Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(turbopack): support modularizeImports next.js config #48511

Merged
merged 1 commit into from Apr 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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
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
@@ -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