Skip to content

Commit

Permalink
feat(turbopack): support modularizeImports next.js config
Browse files Browse the repository at this point in the history
  • Loading branch information
kwonoj committed Apr 18, 2023
1 parent a92c546 commit 448dc1b
Show file tree
Hide file tree
Showing 8 changed files with 98 additions and 14 deletions.
13 changes: 7 additions & 6 deletions packages/next-swc/crates/next-core/Cargo.toml
Expand Up @@ -22,6 +22,7 @@ indoc = { workspace = true }
allsorts = { workspace = true }
futures = { workspace = true }
turbo-binding = { workspace = true, features = [
"__swc_transform_modularize_imports",
"__feature_auto_hash_map",
"__turbo_tasks",
"__turbo_tasks_bytes",
Expand All @@ -36,19 +37,20 @@ turbo-binding = { workspace = true, features = [
"__turbopack_ecmascript",
"__turbopack_env",
"__turbopack_node",
] }
] }
turbo-tasks = { workspace = true }
turbo-tasks-fs = { workspace = true }
next-transform-strip-page-exports = { workspace = true }
next-transform-font = { workspace = true }
next-transform-dynamic = { workspace = true }

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

[build-dependencies]
turbo-binding = { workspace = true, features = [
"__turbo_tasks_build"
]}
turbo-binding = { workspace = true, features = ["__turbo_tasks_build"] }

[features]
next-font-local = []
Expand All @@ -61,4 +63,3 @@ dynamic_embed_contents = [
"turbo-binding/__turbo_tasks_fs_dynamic_embed_contents",
"turbo-binding/__turbopack_dev_dynamic_embed_contents",
]

Expand Up @@ -147,7 +147,7 @@ pub async fn get_client_module_options_context(
ty: Value<ClientContextType>,
next_config: NextConfigVc,
) -> Result<ModuleOptionsContextVc> {
let custom_rules = get_next_client_transforms_rules(ty.into_value()).await?;
let custom_rules = get_next_client_transforms_rules(next_config, ty.into_value()).await?;
let resolve_options_context =
get_client_resolve_options_context(project_path, ty, next_config, execution_context);
let enable_react_refresh =
Expand Down
Expand Up @@ -4,19 +4,26 @@ use turbo_binding::turbopack::turbopack::module_options::ModuleRule;

use crate::{
next_client::context::ClientContextType,
next_config::NextConfigVc,
next_shared::transforms::{
get_next_dynamic_transform_rule, get_next_font_transform_rule,
get_next_pages_transforms_rule,
get_next_modularize_imports_rule, get_next_pages_transforms_rule,
},
};

/// Returns a list of module rules which apply client-side, Next.js-specific
/// transforms.
pub async fn get_next_client_transforms_rules(
next_config: NextConfigVc,
context_ty: ClientContextType,
) -> Result<Vec<ModuleRule>> {
let mut rules = vec![];

let modularize_imports_config = &next_config.await?.modularize_imports;
if let Some(modularize_imports_config) = modularize_imports_config {
rules.push(get_next_modularize_imports_rule(modularize_imports_config));
}

rules.push(get_next_font_transform_rule());

let pages_dir = match context_ty {
Expand Down
4 changes: 2 additions & 2 deletions packages/next-swc/crates/next-core/src/next_config.rs
Expand Up @@ -41,7 +41,7 @@ use turbo_tasks::{
};
use turbo_tasks_fs::json::parse_json_with_source_context;

use crate::embed_js::next_asset;
use crate::{embed_js::next_asset, next_shared::transforms::ModularizeImportPackageConfig};

#[turbo_tasks::value(serialization = "custom", eq = "manual")]
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
Expand All @@ -57,6 +57,7 @@ pub struct NextConfig {
pub react_strict_mode: Option<bool>,
pub rewrites: Rewrites,
pub transpile_packages: Option<Vec<String>>,
pub modularize_imports: Option<IndexMap<String, ModularizeImportPackageConfig>>,

// Partially supported
pub compiler: Option<CompilerConfig>,
Expand Down Expand Up @@ -385,7 +386,6 @@ pub struct ExperimentalConfig {
legacy_browsers: Option<bool>,
manual_client_base_path: Option<bool>,
middleware_prefetch: Option<MiddlewarePrefetchType>,
modularize_imports: Option<serde_json::Value>,
new_next_link_behavior: Option<bool>,
next_script_workers: Option<bool>,
optimistic_client_cache: Option<bool>,
Expand Down
Expand Up @@ -209,7 +209,7 @@ pub async fn get_server_module_options_context(
ty: Value<ServerContextType>,
next_config: NextConfigVc,
) -> Result<ModuleOptionsContextVc> {
let custom_rules = get_next_server_transforms_rules(ty.into_value()).await?;
let custom_rules = get_next_server_transforms_rules(next_config, ty.into_value()).await?;
let foreign_code_context_condition = foreign_code_context_condition(next_config).await?;
let enable_postcss_transform = Some(PostCssTransformOptions {
postcss_package: Some(get_postcss_package_mapping(project_path)),
Expand Down
12 changes: 10 additions & 2 deletions packages/next-swc/crates/next-core/src/next_server/transforms.rs
Expand Up @@ -3,19 +3,27 @@ use next_transform_strip_page_exports::ExportFilter;
use turbo_binding::turbopack::turbopack::module_options::ModuleRule;

use crate::{
next_config::NextConfigVc,
next_server::context::ServerContextType,
next_shared::transforms::{
get_next_dynamic_transform_rule, get_next_font_transform_rule,
get_next_pages_transforms_rule,
get_next_modularize_imports_rule, get_next_pages_transforms_rule,
},
};

/// Returns a list of module rules which apply server-side, Next.js-specific
/// transforms.
pub async fn get_next_server_transforms_rules(
next_config: NextConfigVc,
context_ty: ServerContextType,
) -> Result<Vec<ModuleRule>> {
let mut rules = vec![get_next_font_transform_rule()];
let mut rules = vec![];

let modularize_imports_config = &next_config.await?.modularize_imports;
if let Some(modularize_imports_config) = modularize_imports_config {
rules.push(get_next_modularize_imports_rule(modularize_imports_config));
}
rules.push(get_next_font_transform_rule());

let (is_server_components, pages_dir) = match context_ty {
ServerContextType::Pages { pages_dir } => (false, Some(pages_dir)),
Expand Down
69 changes: 68 additions & 1 deletion packages/next-swc/crates/next-core/src/next_shared/transforms.rs
@@ -1,8 +1,10 @@
use std::path::PathBuf;
use std::{collections::HashMap, path::PathBuf};

use anyhow::Result;
use indexmap::IndexMap;
use next_transform_dynamic::{next_dynamic, NextDynamicMode};
use next_transform_strip_page_exports::{next_transform_strip_page_exports, ExportFilter};
use serde::{Deserialize, Serialize};
use swc_core::{
common::{util::take::Take, FileName},
ecma::{
Expand All @@ -12,6 +14,7 @@ use swc_core::{
},
};
use turbo_binding::{
swc::custom_transform::modularize_imports::{modularize_imports, PackageConfig},
turbo::tasks_fs::FileSystemPathVc,
turbopack::{
core::reference_type::{ReferenceType, UrlReferenceSubType},
Expand All @@ -22,6 +25,7 @@ use turbo_binding::{
turbopack::module_options::{ModuleRule, ModuleRuleCondition, ModuleRuleEffect},
},
};
use turbo_tasks::trace::TraceRawVcs;

/// Returns a rule which applies the Next.js page export stripping transform.
pub async fn get_next_pages_transforms_rule(
Expand Down Expand Up @@ -188,3 +192,66 @@ fn unwrap_module_program(program: &mut Program) -> Program {
}),
}
}

#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize, TraceRawVcs)]
#[serde(rename_all = "camelCase")]
pub struct ModularizeImportPackageConfig {
pub transform: String,
#[serde(default)]
pub prevent_full_import: bool,
#[serde(default)]
pub skip_default_conversion: bool,
}

/// Returns a rule which applies the Next.js modularize imports transform.
pub fn get_next_modularize_imports_rule(
modularize_imports_config: &IndexMap<String, ModularizeImportPackageConfig>,
) -> ModuleRule {
let transformer = EcmascriptInputTransform::Custom(CustomTransformVc::cell(Box::new(
ModularizeImportsTransformer::new(modularize_imports_config),
)));
ModuleRule::new(
module_rule_match_js_no_url(),
vec![ModuleRuleEffect::AddEcmascriptTransforms(
EcmascriptInputTransformsVc::cell(vec![transformer]),
)],
)
}

#[derive(Debug)]
struct ModularizeImportsTransformer {
packages: HashMap<String, PackageConfig>,
}

impl ModularizeImportsTransformer {
fn new(packages: &IndexMap<String, ModularizeImportPackageConfig>) -> Self {
Self {
packages: packages
.iter()
.map(|(k, v)| {
(
k.clone(),
PackageConfig {
transform: v.transform.clone(),
prevent_full_import: v.prevent_full_import,
skip_default_conversion: v.skip_default_conversion,
},
)
})
.collect(),
}
}
}

impl CustomTransformer for ModularizeImportsTransformer {
fn transform(&self, program: &mut Program, _ctx: &TransformContext<'_>) -> Option<Program> {
let p = std::mem::replace(program, Program::Module(Module::dummy()));
*program = p.fold_with(&mut modularize_imports(
turbo_binding::swc::custom_transform::modularize_imports::Config {
packages: self.packages.clone(),
},
));

None
}
}
1 change: 1 addition & 0 deletions packages/next/src/lib/turbopack-warning.ts
Expand Up @@ -7,6 +7,7 @@ const supportedTurbopackNextConfigOptions = [
'configFileName',
'env',
'experimental.appDir',
'modularizeImports',
'compiler.emotion',
'compiler.styledComponents',
'experimental.serverComponentsExternalPackages',
Expand Down

0 comments on commit 448dc1b

Please sign in to comment.