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_ecmascript): support partial tsconfig for the transform #3995

Merged
merged 2 commits into from
Mar 7, 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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions crates/turbopack-ecmascript/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ swc_core = { workspace = true, features = [
"ecma_transforms_module",
"ecma_transforms_react",
"ecma_transforms_typescript",
"ecma_transforms_proposal",
"ecma_quote",
"ecma_visit",
"ecma_visit_path",
Expand Down
21 changes: 20 additions & 1 deletion crates/turbopack-ecmascript/src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,12 @@ use turbo_tasks::{
primitives::{StringVc, U64Vc},
Value, ValueToString,
};
use turbo_tasks_fs::{FileContent, FileSystemPath};
use turbo_tasks_fs::{FileContent, FileJsonContentVc, FileSystemPath};
use turbo_tasks_hash::hash_xxh3_hash64;
use turbopack_core::{
asset::{Asset, AssetContent, AssetVc},
resolve::{find_context_file, node::node_cjs_resolve_options, FindContextFileResult},
source_asset::SourceAssetVc,
source_map::{GenerateSourceMap, GenerateSourceMapVc, SourceMapVc},
};
use turbopack_swc_utils::emitter::IssueEmitter;
Expand All @@ -35,6 +37,7 @@ use super::EcmascriptModuleAssetType;
use crate::{
analyzer::graph::EvalContext,
transform::{EcmascriptInputTransformsVc, TransformContext},
typescript::resolve::{read_tsconfigs, tsconfig},
utils::WrapFuture,
EcmascriptInputTransform,
};
Expand Down Expand Up @@ -138,6 +141,19 @@ pub async fn parse(
let fs_path = &*source.ident().path().await?;
let file_path_hash = *hash_ident(source.ident().to_string()).await? as u128;
let ty = ty.into_value();
let tsconfig = find_context_file(source.ident().path(), tsconfig());
let tsconfig = match *tsconfig.await? {
FindContextFileResult::Found(path, _) => Some(
read_tsconfigs(
path.read(),
SourceAssetVc::new(path).into(),
node_cjs_resolve_options(path.root()),
)
.await?,
),
FindContextFileResult::NotFound(_) => None,
};
Comment on lines +144 to +155
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This causes a lot of errors in front as tsconfig in node_modules is read:

  C:\Repos\front\apps\vercel-site\node_modules\.pnpm\@vercel+analytics@0.1.9-beta.3_react@18.2.0\node_modules\@vercel\analytics\tsconfig.json
    An issue occurred while parsing a tsconfig.json file.
    extends doesn't resolve correctly

A tsconfig shouldn't be read in parse


Ok(match &*content.await? {
AssetContent::File(file) => match &*file.await? {
FileContent::NotFound => ParseResult::NotFound.cell(),
Expand All @@ -151,6 +167,7 @@ pub async fn parse(
source,
ty,
transforms,
tsconfig,
)
.await
{
Expand Down Expand Up @@ -178,6 +195,7 @@ async fn parse_content(
source: AssetVc,
ty: EcmascriptModuleAssetType,
transforms: &[EcmascriptInputTransform],
tsconfig: Option<Vec<(FileJsonContentVc, AssetVc)>>,
) -> Result<ParseResultVc> {
let source_map: Arc<SourceMap> = Default::default();
let handler = Handler::with_emitter(
Expand Down Expand Up @@ -284,6 +302,7 @@ async fn parse_content(
file_path_str: &fs_path.path,
file_name_str: fs_path.file_name(),
file_name_hash: file_path_hash,
tsconfig: &tsconfig,
};
for transform in transforms.iter() {
transform.apply(&mut parsed_program, &context).await?;
Expand Down
70 changes: 66 additions & 4 deletions crates/turbopack-ecmascript/src/transform/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use swc_core::{
preset_env::{self, Targets},
transforms::{
base::{feature::FeatureFlag, helpers::inject_helpers, resolver, Assumptions},
proposal::decorators,
react::react,
},
visit::{FoldWith, VisitMutWith},
Expand All @@ -24,8 +25,10 @@ use turbo_tasks::{
primitives::{StringVc, StringsVc},
trace::TraceRawVcs,
};
use turbo_tasks_fs::{json::parse_json_with_source_context, FileSystemPathVc};
use turbopack_core::environment::EnvironmentVc;
use turbo_tasks_fs::{
json::parse_json_with_source_context, FileJsonContent, FileJsonContentVc, FileSystemPathVc,
};
use turbopack_core::{asset::AssetVc, environment::EnvironmentVc};

use self::server_to_client_proxy::{create_proxy_module, is_client_module};

Expand Down Expand Up @@ -78,6 +81,9 @@ pub enum EcmascriptInputTransform {
StyledComponents,
StyledJsx,
TypeScript,
// Apply ecma decorators transform. This is not part of Typescript transform, even though
// decorators can be ts-specific (legacy decorartors) since there's ecma decorators for js.
Decorators,
}

#[turbo_tasks::value(transparent, serialization = "auto_for_input")]
Expand All @@ -102,6 +108,7 @@ pub struct TransformContext<'a> {
pub file_path_str: &'a str,
pub file_name_str: &'a str,
pub file_name_hash: u128,
pub tsconfig: &'a Option<Vec<(FileJsonContentVc, AssetVc)>>,
}

impl EcmascriptInputTransform {
Expand All @@ -116,6 +123,7 @@ impl EcmascriptInputTransform {
file_path_str,
file_name_str,
file_name_hash,
tsconfig,
}: &TransformContext<'_>,
) -> Result<()> {
match *self {
Expand Down Expand Up @@ -198,9 +206,63 @@ impl EcmascriptInputTransform {
FileName::Anon,
));
}
EcmascriptInputTransform::Decorators => {
// TODO: Currently this only supports legacy decorators from tsconfig / jsconfig
// options.
if let Some(tsconfig) = tsconfig {
// Selectively picks up tsconfig.json values to construct
// swc transform's stripconfig. It doesn't account .swcrc config currently.
Comment on lines +213 to +214
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy paste comment?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh you're right 🤦

for (value, _) in tsconfig {
let value = &*value.await?;
if let FileJsonContent::Content(value) = value {
let legacy_decorators = value["compilerOptions"]
["experimentalDecorators"]
.as_bool()
.unwrap_or(false);

if legacy_decorators {
// TODO: `fn decorators` does not support visitMut yet
let p =
std::mem::replace(program, Program::Module(Module::dummy()));
*program = p.fold_with(&mut chain!(
decorators(decorators::Config {
legacy: true,
emit_metadata: true,
use_define_for_class_fields: value["compilerOptions"]
["useDefineForClassFields"]
.as_bool()
.unwrap_or(false),
}),
inject_helpers(unresolved_mark),
));
}
}
}
};
}
EcmascriptInputTransform::TypeScript => {
use swc_core::ecma::transforms::typescript::strip;
program.visit_mut_with(&mut strip(top_level_mark));
use swc_core::ecma::transforms::typescript::{strip_with_config, Config};

let config = if let Some(tsconfig) = tsconfig {
let mut config = Config {
..Default::default()
};

for (value, _) in tsconfig {
let value = &*value.await?;
if let FileJsonContent::Content(value) = value {
let use_define_for_class_fields =
&value["compilerOptions"]["useDefineForClassFields"];
config.use_define_for_class_fields =
use_define_for_class_fields.as_bool().unwrap_or(false);
}
}
config
} else {
Default::default()
};

program.visit_mut_with(&mut strip_with_config(config, top_level_mark));
}
EcmascriptInputTransform::ClientDirective(transition_name) => {
let transition_name = &*transition_name.await?;
Expand Down
5 changes: 4 additions & 1 deletion crates/turbopack/src/module_options/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,10 @@ impl ModuleOptionsVc {
}
}
}
let mut transforms = custom_ecmascript_app_transforms.clone();
// We apply decorators _before_ any ts transforms, as some of decorator requires
// type information.
let mut transforms = vec![EcmascriptInputTransform::Decorators];
transforms.extend(custom_ecmascript_app_transforms.iter().cloned());
transforms.extend(custom_ecmascript_transforms.iter().cloned());

// Order of transforms is important. e.g. if the React transform occurs before
Expand Down