Skip to content

Commit

Permalink
feat(ecma-plugins): extract custom emotion transform (#4662)
Browse files Browse the repository at this point in the history
### Description

First step for WEB-940.

Context: https://vercel.slack.com/archives/C03EWR7LGEN/p1681789689115509

Currently all of the ecma transforms are explicitly listed under
EcmaInputTransform in turbopack-ecmascript. This makes enum verbose, we
have to manually expand it each time adding new transform, as well as
turbopack-ecmascript gets larger to contain all of the 3rd party
transforms by default.

PR extracts non-core transforms into a new crate, named as
ecmascript-plugins then utilize EcmaInputTransform::Custom to invoke
transforms instead. `EcmaInputTransform::Custom` is renamed to
`EcmaInputTransform::Plugin` as well. Goal is extracting all of 3rd
party / non-core transforms. This also reduces multiple steps to
construct option value between caller (next-*) to actual transform
(swcOptions).

vercel/next.js#48671 have corresponding next.js
changes.
  • Loading branch information
kwonoj committed Apr 26, 2023
1 parent 1dfda18 commit bef88f9
Show file tree
Hide file tree
Showing 19 changed files with 226 additions and 107 deletions.
17 changes: 17 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ members = [
"crates/turbopack-dev",
"crates/turbopack-dev-server",
"crates/turbopack-ecmascript",
"crates/turbopack-ecmascript-plugins",
"crates/turbopack-env",
"crates/turbopack-image",
"crates/turbopack-json",
Expand Down Expand Up @@ -134,6 +135,7 @@ turbopack-css = { path = "crates/turbopack-css" }
turbopack-dev = { path = "crates/turbopack-dev" }
turbopack-dev-server = { path = "crates/turbopack-dev-server" }
turbopack-ecmascript = { path = "crates/turbopack-ecmascript" }
turbopack-ecmascript-plugins = { path = "crates/turbopack-ecmascript-plugins" }
turbopack-env = { path = "crates/turbopack-env" }
turbopack-image = { path = "crates/turbopack-image" }
turbopack-json = { path = "crates/turbopack-json" }
Expand Down
7 changes: 7 additions & 0 deletions crates/turbo-binding/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,12 @@ __turbopack_dev_dynamic_embed_contents = [
]
__turbopack_dev_server = ["__turbopack", "turbopack-dev-server"]
__turbopack_ecmascript = ["__turbopack", "turbopack-ecmascript"]
# [Note]: currently all of the transform features are enabled by default
__turbopack_ecmascript_plugin = [
"__turbopack",
"turbopack-ecmascript-plugins",
"turbopack-ecmascript-plugins/transform_emotion",
]
__turbopack_env = ["__turbopack", "turbopack-env"]
__turbopack_image = ["__turbopack", "turbopack-image"]
__turbopack_image_avif = ["turbopack-image/avif"]
Expand Down Expand Up @@ -185,6 +191,7 @@ turbopack-css = { optional = true, workspace = true }
turbopack-dev = { optional = true, workspace = true }
turbopack-dev-server = { optional = true, workspace = true }
turbopack-ecmascript = { optional = true, workspace = true }
turbopack-ecmascript-plugins = { optional = true, workspace = true }
turbopack-env = { optional = true, workspace = true }
turbopack-image = { optional = true, workspace = true }
turbopack-json = { optional = true, workspace = true }
Expand Down
2 changes: 2 additions & 0 deletions crates/turbo-binding/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,8 @@ pub mod turbopack {
pub use turbopack_dev_server as dev_server;
#[cfg(feature = "__turbopack_ecmascript")]
pub use turbopack_ecmascript as ecmascript;
#[cfg(feature = "__turbopack_ecmascript_plugin")]
pub use turbopack_ecmascript_plugins as ecmascript_plugin;
#[cfg(feature = "__turbopack_env")]
pub use turbopack_env as env;
#[cfg(feature = "__turbopack_image")]
Expand Down
3 changes: 3 additions & 0 deletions crates/turbopack-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ turbopack-cli-utils = { workspace = true }
turbopack-core = { workspace = true }
turbopack-dev = { workspace = true }
turbopack-dev-server = { workspace = true }
turbopack-ecmascript-plugins = { workspace = true, features = [
"transform_emotion",
] }
turbopack-env = { workspace = true }
turbopack-node = { workspace = true }
webbrowser = { workspace = true }
Expand Down
5 changes: 3 additions & 2 deletions crates/turbopack-cli/src/dev/web_entry_source.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ use turbopack::{
condition::ContextCondition,
ecmascript::EcmascriptModuleAssetVc,
module_options::{
EmotionTransformConfigVc, JsxTransformOptions, ModuleOptionsContext,
ModuleOptionsContextVc, StyledComponentsTransformConfigVc,
JsxTransformOptions, ModuleOptionsContext, ModuleOptionsContextVc,
StyledComponentsTransformConfigVc,
},
resolve_options_context::{ResolveOptionsContext, ResolveOptionsContextVc},
transition::TransitionsByNameVc,
Expand All @@ -35,6 +35,7 @@ use turbopack_dev_server::{
html::DevHtmlAssetVc,
source::{asset_graph::AssetGraphContentSourceVc, ContentSourceVc},
};
use turbopack_ecmascript_plugins::transform::emotion::EmotionTransformConfigVc;
use turbopack_node::execution_context::ExecutionContextVc;

use crate::embed_js::embed_file_path;
Expand Down
1 change: 1 addition & 0 deletions crates/turbopack-cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ pub(crate) mod embed_js;
pub fn register() {
turbopack::register();
turbopack_dev::register();
turbopack_ecmascript_plugins::register();
include!(concat!(env!("OUT_DIR"), "/register.rs"));
}
26 changes: 26 additions & 0 deletions crates/turbopack-ecmascript-plugins/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
[package]
name = "turbopack-ecmascript-plugins"
version = "0.1.0"
description = "TBD"
license = "MPL-2.0"
edition = "2021"
autobenches = false

[lib]
bench = false

[features]
transform_emotion = []

[dependencies]
anyhow = { workspace = true }
serde = { workspace = true }

turbo-tasks = { workspace = true }
turbopack-ecmascript = { workspace = true }

swc_core = { workspace = true, features = ["ecma_ast", "ecma_visit", "common"] }
swc_emotion = { workspace = true }

[build-dependencies]
turbo-tasks-build = { workspace = true }
5 changes: 5 additions & 0 deletions crates/turbopack-ecmascript-plugins/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
use turbo_tasks_build::generate_register;

fn main() {
generate_register();
}
7 changes: 7 additions & 0 deletions crates/turbopack-ecmascript-plugins/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
pub mod transform;

pub fn register() {
turbo_tasks::register();
turbopack_ecmascript::register();
include!(concat!(env!("OUT_DIR"), "/register.rs"));
}
126 changes: 126 additions & 0 deletions crates/turbopack-ecmascript-plugins/src/transform/emotion.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
#![allow(unused)]
use std::{
hash::{Hash, Hasher},
path::Path,
};

use anyhow::Result;
use serde::{Deserialize, Serialize};
use swc_core::{
common::util::take::Take,
ecma::{
ast::{Module, Program},
visit::FoldWith,
},
};
use turbo_tasks::trace::TraceRawVcs;
use turbopack_ecmascript::{CustomTransformer, TransformContext};

#[derive(Clone, PartialEq, Eq, Debug, TraceRawVcs, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum EmotionLabelKind {
DevOnly,
Always,
Never,
}

#[turbo_tasks::value(transparent)]
pub struct OptionEmotionTransformConfig(Option<EmotionTransformConfigVc>);

//[TODO]: need to support importmap, there are type mismatch between
//next.config.js to swc's emotion options
#[turbo_tasks::value(shared)]
#[derive(Default, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub struct EmotionTransformConfig {
pub sourcemap: Option<bool>,
pub label_format: Option<String>,
pub auto_label: Option<EmotionLabelKind>,
}

#[turbo_tasks::value_impl]
impl EmotionTransformConfigVc {
#[turbo_tasks::function]
pub fn default() -> Self {
Self::cell(Default::default())
}
}

impl Default for EmotionTransformConfigVc {
fn default() -> Self {
Self::default()
}
}

#[derive(Debug)]
pub struct EmotionTransformer {
#[cfg(feature = "transform_emotion")]
config: swc_emotion::EmotionOptions,
}

#[cfg(feature = "transform_emotion")]
impl EmotionTransformer {
pub fn new(config: &EmotionTransformConfig) -> Option<Self> {
let config = swc_emotion::EmotionOptions {
// When you create a transformer structure, it is assumed that you are performing an
// emotion transform.
enabled: Some(true),
sourcemap: config.sourcemap,
label_format: config.label_format.clone(),
auto_label: if let Some(auto_label) = config.auto_label.as_ref() {
match auto_label {
EmotionLabelKind::Always => Some(true),
EmotionLabelKind::Never => Some(false),
// [TODO]: this is not correct coerece, need to be fixed
EmotionLabelKind::DevOnly => None,
}
} else {
None
},
..Default::default()
};

Some(EmotionTransformer { config })
}
}

#[cfg(not(feature = "transform_emotion"))]
impl EmotionTransformer {
pub fn new(_config: &EmotionTransformConfig) -> Option<Self> {
None
}
}

impl CustomTransformer for EmotionTransformer {
fn transform(&self, program: &mut Program, ctx: &TransformContext<'_>) -> Option<Program> {
#[cfg(feature = "transform_emotion")]
{
let p = std::mem::replace(program, Program::Module(Module::dummy()));
let hash = {
#[allow(clippy::disallowed_types)]
let mut hasher = std::collections::hash_map::DefaultHasher::new();
p.hash(&mut hasher);
hasher.finish()
};
*program = p.fold_with(&mut swc_emotion::emotion(
self.config.clone(),
Path::new(ctx.file_name_str),
hash as u32,
ctx.source_map.clone(),
ctx.comments.clone(),
));
}

None
}
}

pub async fn build_emotion_transformer(
config: &Option<EmotionTransformConfigVc>,
) -> Result<Option<Box<EmotionTransformer>>> {
Ok(if let Some(config) = config {
EmotionTransformer::new(&*config.await?).map(Box::new)
} else {
None
})
}
1 change: 1 addition & 0 deletions crates/turbopack-ecmascript-plugins/src/transform/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod emotion;
4 changes: 2 additions & 2 deletions crates/turbopack-ecmascript/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ use swc_core::{
},
};
pub use transform::{
CustomTransform, CustomTransformVc, CustomTransformer, EcmascriptInputTransform,
EcmascriptInputTransformsVc, TransformContext,
CustomTransformer, EcmascriptInputTransform, EcmascriptInputTransformsVc, TransformContext,
TransformPlugin, TransformPluginVc,
};
use turbo_tasks::{
primitives::StringVc, trace::TraceRawVcs, RawVc, ReadRef, TryJoinIterExt, Value, ValueToString,
Expand Down

0 comments on commit bef88f9

Please sign in to comment.