Skip to content

Commit

Permalink
feat(es/react): Support script within automatic runtime (#7126)
Browse files Browse the repository at this point in the history
**Description:**

Inject `const { jsx: _jsx} = require("react/jsx-runtime")` when sourceType is `script`

**Related issue:**

 - Closes #7119.
  • Loading branch information
JSerFeng committed Mar 27, 2023
1 parent 47f15f9 commit 05a2815
Show file tree
Hide file tree
Showing 31 changed files with 476 additions and 100 deletions.
8 changes: 7 additions & 1 deletion crates/swc/src/config/mod.rs
Expand Up @@ -749,7 +749,13 @@ impl Options {
custom_before_pass(&program),
// handle jsx
Optional::new(
react::react(cm.clone(), comments, transform.react, top_level_mark),
react::react(
cm.clone(),
comments,
transform.react,
top_level_mark,
unresolved_mark
),
syntax.jsx()
),
pass,
Expand Down
1 change: 1 addition & 0 deletions crates/swc_bundler/tests/common/mod.rs
Expand Up @@ -146,6 +146,7 @@ impl Load for Loader {
None,
Default::default(),
top_level_mark,
unresolved_mark,
))
.fold_with(&mut inject_helpers(unresolved_mark))
});
Expand Down
244 changes: 154 additions & 90 deletions crates/swc_ecma_transforms_react/src/jsx/mod.rs
Expand Up @@ -18,7 +18,9 @@ use swc_common::{
use swc_config::merge::Merge;
use swc_ecma_ast::*;
use swc_ecma_parser::{parse_file_as_expr, Syntax};
use swc_ecma_utils::{drop_span, prepend_stmt, private_ident, quote_ident, undefined, ExprFactory};
use swc_ecma_utils::{
drop_span, prepend_stmt, private_ident, quote_ident, undefined, ExprFactory, StmtLike,
};
use swc_ecma_visit::{as_folder, noop_visit_mut_type, Fold, VisitMut, VisitMutWith};

use self::static_check::should_use_create_element;
Expand Down Expand Up @@ -187,13 +189,15 @@ pub fn jsx<C>(
comments: Option<C>,
options: Options,
top_level_mark: Mark,
unresolved_mark: Mark,
) -> impl Fold + VisitMut
where
C: Comments,
{
as_folder(Jsx {
cm: cm.clone(),
top_level_mark,
unresolved_mark,
runtime: options.runtime.unwrap_or_default(),
import_source: options
.import_source
Expand Down Expand Up @@ -232,6 +236,7 @@ where
cm: Lrc<SourceMap>,

top_level_mark: Mark,
unresolved_mark: Mark,

runtime: Runtime,
/// For automatic runtime.
Expand Down Expand Up @@ -376,6 +381,62 @@ impl<C> Jsx<C>
where
C: Comments,
{
fn inject_runtime<T, F>(&mut self, body: &mut Vec<T>, inject: F)
where
T: StmtLike,
// Fn(Vec<(local, imported)>, src, body)
F: Fn(Vec<(Ident, Ident)>, &str, &mut Vec<T>),
{
if self.runtime == Runtime::Automatic {
if let Some(local) = self.import_create_element.take() {
inject(
vec![(local, quote_ident!("createElement"))],
&self.import_source,
body,
);
}

let imports = self.import_jsx.take();
let imports = if self.development {
imports
.map(|local| (local, quote_ident!("jsxDEV")))
.into_iter()
.chain(
self.import_fragment
.take()
.map(|local| (local, quote_ident!("Fragment"))),
)
.collect::<Vec<_>>()
} else {
imports
.map(|local| (local, quote_ident!("jsx")))
.into_iter()
.chain(
self.import_jsxs
.take()
.map(|local| (local, quote_ident!("jsxs"))),
)
.chain(
self.import_fragment
.take()
.map(|local| (local, quote_ident!("Fragment"))),
)
.collect::<Vec<_>>()
};

if !imports.is_empty() {
let jsx_runtime = if self.development {
"jsx-dev-runtime"
} else {
"jsx-runtime"
};

let value = format!("{}/{}", self.import_source, jsx_runtime);
inject(imports, &value, body)
}
}
}

fn jsx_frag_to_expr(&mut self, el: JSXFragment) -> Expr {
let span = el.span();

Expand Down Expand Up @@ -477,7 +538,7 @@ where

/// # Automatic
///
///
/// <div></div> => jsx('div', null);
///
/// # Classic
///
Expand Down Expand Up @@ -975,113 +1036,116 @@ where
module.visit_mut_children_with(self);

if self.runtime == Runtime::Automatic {
if let Some(local) = self.import_create_element.take() {
let specifier = ImportSpecifier::Named(ImportNamedSpecifier {
span: DUMMY_SP,
local,
imported: Some(ModuleExportName::Ident(Ident::new(
"createElement".into(),
DUMMY_SP,
))),
is_type_only: false,
});
prepend_stmt(
&mut module.body,
ModuleItem::ModuleDecl(ModuleDecl::Import(ImportDecl {
span: DUMMY_SP,
specifiers: vec![specifier],
src: Str {
span: DUMMY_SP,
raw: None,
value: self.import_source.clone(),
}
.into(),
type_only: Default::default(),
asserts: Default::default(),
})),
);
}

let imports = self.import_jsx.take();
let imports = if self.development {
imports
.map(|local| ImportNamedSpecifier {
span: DUMMY_SP,
local,
imported: Some(ModuleExportName::Ident(quote_ident!("jsxDEV"))),
is_type_only: false,
})
self.inject_runtime(&mut module.body, |imports, src, stmts| {
let specifiers = imports
.into_iter()
.chain(
self.import_fragment
.take()
.map(|local| ImportNamedSpecifier {
span: DUMMY_SP,
local,
imported: Some(ModuleExportName::Ident(quote_ident!("Fragment"))),
is_type_only: false,
}),
)
.map(ImportSpecifier::Named)
.collect::<Vec<_>>()
} else {
imports
.map(|local| ImportNamedSpecifier {
span: DUMMY_SP,
local,
imported: Some(ModuleExportName::Ident(quote_ident!("jsx"))),
is_type_only: false,
.map(|(local, imported)| {
ImportSpecifier::Named(ImportNamedSpecifier {
span: DUMMY_SP,
local,
imported: Some(ModuleExportName::Ident(imported)),
is_type_only: false,
})
})
.into_iter()
.chain(self.import_jsxs.take().map(|local| ImportNamedSpecifier {
span: DUMMY_SP,
local,
imported: Some(ModuleExportName::Ident(quote_ident!("jsxs"))),
is_type_only: false,
}))
.chain(
self.import_fragment
.take()
.map(|local| ImportNamedSpecifier {
span: DUMMY_SP,
local,
imported: Some(ModuleExportName::Ident(quote_ident!("Fragment"))),
is_type_only: false,
}),
)
.map(ImportSpecifier::Named)
.collect::<Vec<_>>()
};

if !imports.is_empty() {
let jsx_runtime = if self.development {
"jsx-dev-runtime"
} else {
"jsx-runtime"
};

let value = format!("{}/{}", self.import_source, jsx_runtime);
.collect();

prepend_stmt(
&mut module.body,
stmts,
ModuleItem::ModuleDecl(ModuleDecl::Import(ImportDecl {
span: DUMMY_SP,
specifiers: imports,
specifiers,
src: Str {
span: DUMMY_SP,
raw: None,
value: value.into(),
value: src.into(),
}
.into(),
type_only: Default::default(),
asserts: Default::default(),
})),
);
)
});
}
}

fn visit_mut_script(&mut self, script: &mut Script) {
self.parse_directives(script.span);

for item in &script.body {
let span = item.span();
if self.parse_directives(span) {
break;
}
}

script.visit_mut_children_with(self);

if self.runtime == Runtime::Automatic {
let mark = self.unresolved_mark;
self.inject_runtime(&mut script.body, |imports, src, stmts| {
prepend_stmt(stmts, add_require(imports, src, mark))
});
}
}
}

// const { createElement } = require('react')
// const { jsx: jsx } = require('react/jsx-runtime')
fn add_require(imports: Vec<(Ident, Ident)>, src: &str, unresolved_mark: Mark) -> Stmt {
Stmt::Decl(Decl::Var(Box::new(VarDecl {
span: DUMMY_SP,
kind: VarDeclKind::Const,
declare: false,
decls: vec![VarDeclarator {
span: DUMMY_SP,
name: Pat::Object(ObjectPat {
span: DUMMY_SP,
props: imports
.into_iter()
.map(|(local, imported)| {
if imported.sym != local.sym {
ObjectPatProp::KeyValue(KeyValuePatProp {
key: PropName::Ident(imported),
value: Box::new(Pat::Ident(BindingIdent {
id: local,
type_ann: None,
})),
})
} else {
ObjectPatProp::Assign(AssignPatProp {
span: DUMMY_SP,
key: local,
value: None,
})
}
})
.collect(),
optional: false,
type_ann: None,
}),
// require('react')
init: Some(Box::new(Expr::Call(CallExpr {
span: DUMMY_SP,
callee: Callee::Expr(Box::new(Expr::Ident(Ident {
span: DUMMY_SP.apply_mark(unresolved_mark),
sym: js_word!("require"),
optional: false,
}))),
args: vec![ExprOrSpread {
spread: None,
expr: Box::new(Expr::Lit(Lit::Str(Str {
span: DUMMY_SP,
value: src.into(),
raw: None,
}))),
}],
type_args: None,
}))),
definite: false,
}],
})))
}

impl<C> Jsx<C>
where
C: Comments,
Expand Down

1 comment on commit 05a2815

@github-actions
Copy link

Choose a reason for hiding this comment

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

Benchmark

Benchmark suite Current: 05a2815 Previous: 5e58b3e Ratio
es/full/bugs-1 286166 ns/iter (± 15485) 321166 ns/iter (± 9915) 0.89
es/full/minify/libraries/antd 1543084670 ns/iter (± 18233636) 1696865161 ns/iter (± 21535551) 0.91
es/full/minify/libraries/d3 296337470 ns/iter (± 5455452) 313692167 ns/iter (± 6256167) 0.94
es/full/minify/libraries/echarts 1223230043 ns/iter (± 14589295) 1296385284 ns/iter (± 8905118) 0.94
es/full/minify/libraries/jquery 91280937 ns/iter (± 824052) 93143658 ns/iter (± 965435) 0.98
es/full/minify/libraries/lodash 106991231 ns/iter (± 1803421) 107692497 ns/iter (± 648653) 0.99
es/full/minify/libraries/moment 53406124 ns/iter (± 729148) 53019876 ns/iter (± 389759) 1.01
es/full/minify/libraries/react 19099732 ns/iter (± 202787) 19415099 ns/iter (± 123640) 0.98
es/full/minify/libraries/terser 248350503 ns/iter (± 3862224) 262504666 ns/iter (± 4313641) 0.95
es/full/minify/libraries/three 450547656 ns/iter (± 3810626) 468573847 ns/iter (± 6154713) 0.96
es/full/minify/libraries/typescript 2952506531 ns/iter (± 17589907) 3157176870 ns/iter (± 25110170) 0.94
es/full/minify/libraries/victory 679908761 ns/iter (± 22557648) 710493550 ns/iter (± 12366296) 0.96
es/full/minify/libraries/vue 130657592 ns/iter (± 1956663) 135678896 ns/iter (± 3469723) 0.96
es/full/codegen/es3 28185 ns/iter (± 175) 28842 ns/iter (± 61) 0.98
es/full/codegen/es5 28232 ns/iter (± 99) 28944 ns/iter (± 32) 0.98
es/full/codegen/es2015 28211 ns/iter (± 67) 28943 ns/iter (± 54) 0.97
es/full/codegen/es2016 28232 ns/iter (± 69) 28977 ns/iter (± 40) 0.97
es/full/codegen/es2017 28295 ns/iter (± 50) 28983 ns/iter (± 41) 0.98
es/full/codegen/es2018 28192 ns/iter (± 57) 29007 ns/iter (± 108) 0.97
es/full/codegen/es2019 28229 ns/iter (± 75) 28930 ns/iter (± 62) 0.98
es/full/codegen/es2020 28245 ns/iter (± 58) 28916 ns/iter (± 31) 0.98
es/full/all/es3 181033595 ns/iter (± 2429937) 183049960 ns/iter (± 3149603) 0.99
es/full/all/es5 170024824 ns/iter (± 2683427) 173836522 ns/iter (± 5615868) 0.98
es/full/all/es2015 135054447 ns/iter (± 2890752) 136937388 ns/iter (± 3523173) 0.99
es/full/all/es2016 133665622 ns/iter (± 1884542) 136855340 ns/iter (± 1226229) 0.98
es/full/all/es2017 131329988 ns/iter (± 2846115) 135492180 ns/iter (± 1544865) 0.97
es/full/all/es2018 128086947 ns/iter (± 1014312) 130228192 ns/iter (± 1955189) 0.98
es/full/all/es2019 125727742 ns/iter (± 1614292) 127531131 ns/iter (± 2627234) 0.99
es/full/all/es2020 118660944 ns/iter (± 804444) 119261666 ns/iter (± 2563132) 0.99
es/full/parser 529893 ns/iter (± 9136) 530885 ns/iter (± 8816) 1.00
es/full/base/fixer 22346 ns/iter (± 23) 22268 ns/iter (± 58) 1.00
es/full/base/resolver_and_hygiene 83652 ns/iter (± 124) 83013 ns/iter (± 81) 1.01
serialization of serde 130 ns/iter (± 0) 131 ns/iter (± 0) 0.99
css/minify/libraries/bootstrap 28527350 ns/iter (± 87830) 29157784 ns/iter (± 181940) 0.98
css/visitor/compare/clone 2088044 ns/iter (± 18958) 2116153 ns/iter (± 14182) 0.99
css/visitor/compare/visit_mut_span 2248870 ns/iter (± 5201) 2319363 ns/iter (± 8713) 0.97
css/visitor/compare/visit_mut_span_panic 2324306 ns/iter (± 4042) 2329788 ns/iter (± 8009) 1.00
css/visitor/compare/fold_span 3072586 ns/iter (± 29319) 3070910 ns/iter (± 28022) 1.00
css/visitor/compare/fold_span_panic 3191617 ns/iter (± 20953) 3212730 ns/iter (± 36358) 0.99
css/lexer/bootstrap_5_1_3 5159365 ns/iter (± 18311) 5168666 ns/iter (± 47299) 1.00
css/lexer/foundation_6_7_4 4386063 ns/iter (± 2657) 4354804 ns/iter (± 2481) 1.01
css/lexer/tailwind_3_1_1 833038 ns/iter (± 552) 829740 ns/iter (± 556) 1.00
css/parser/bootstrap_5_1_3 21960986 ns/iter (± 78217) 22336897 ns/iter (± 127454) 0.98
css/parser/foundation_6_7_4 17469137 ns/iter (± 29803) 17668465 ns/iter (± 67392) 0.99
css/parser/tailwind_3_1_1 3334509 ns/iter (± 4936) 3336438 ns/iter (± 21971) 1.00
es/codegen/colors 327689 ns/iter (± 184517) 319184 ns/iter (± 178600) 1.03
es/codegen/large 1216705 ns/iter (± 614071) 1219426 ns/iter (± 622306) 1.00
es/codegen/with-parser/colors 47497 ns/iter (± 337) 46872 ns/iter (± 281) 1.01
es/codegen/with-parser/large 514271 ns/iter (± 918) 521006 ns/iter (± 6828) 0.99
es/minify/libraries/antd 1359479667 ns/iter (± 11280520) 1522420124 ns/iter (± 25776815) 0.89
es/minify/libraries/d3 265851221 ns/iter (± 3370610) 284018759 ns/iter (± 4143792) 0.94
es/minify/libraries/echarts 1066883398 ns/iter (± 7216198) 1138477782 ns/iter (± 9822477) 0.94
es/minify/libraries/jquery 80453409 ns/iter (± 869798) 82673836 ns/iter (± 669631) 0.97
es/minify/libraries/lodash 95718585 ns/iter (± 2094633) 101185029 ns/iter (± 1125005) 0.95
es/minify/libraries/moment 46443692 ns/iter (± 392193) 47915011 ns/iter (± 1374721) 0.97
es/minify/libraries/react 17400288 ns/iter (± 236821) 17631394 ns/iter (± 895074) 0.99
es/minify/libraries/terser 224126661 ns/iter (± 2526292) 227296954 ns/iter (± 2097549) 0.99
es/minify/libraries/three 383293868 ns/iter (± 6556151) 402899473 ns/iter (± 3969379) 0.95
es/minify/libraries/typescript 2502044579 ns/iter (± 11658688) 2665350947 ns/iter (± 18873397) 0.94
es/minify/libraries/victory 574791298 ns/iter (± 12135616) 624843143 ns/iter (± 9730967) 0.92
es/minify/libraries/vue 116773786 ns/iter (± 2775983) 118182178 ns/iter (± 686052) 0.99
es/visitor/compare/clone 2278690 ns/iter (± 12423) 2327502 ns/iter (± 8823) 0.98
es/visitor/compare/visit_mut_span 2663724 ns/iter (± 14370) 2705698 ns/iter (± 11687) 0.98
es/visitor/compare/visit_mut_span_panic 2732186 ns/iter (± 14752) 2724638 ns/iter (± 14923) 1.00
es/visitor/compare/fold_span 3800752 ns/iter (± 13652) 3846202 ns/iter (± 33190) 0.99
es/visitor/compare/fold_span_panic 3976919 ns/iter (± 20207) 4025253 ns/iter (± 28468) 0.99
es/lexer/colors 15474 ns/iter (± 13) 15366 ns/iter (± 9) 1.01
es/lexer/angular 7502821 ns/iter (± 5728) 7481608 ns/iter (± 2054) 1.00
es/lexer/backbone 964795 ns/iter (± 414) 954148 ns/iter (± 428) 1.01
es/lexer/jquery 5404499 ns/iter (± 1864) 5381144 ns/iter (± 3188) 1.00
es/lexer/jquery mobile 8342515 ns/iter (± 5922) 8292624 ns/iter (± 4725) 1.01
es/lexer/mootools 4264017 ns/iter (± 2618) 4254264 ns/iter (± 3245) 1.00
es/lexer/underscore 807891 ns/iter (± 334) 802347 ns/iter (± 616) 1.01
es/lexer/three 25389681 ns/iter (± 39511) 25377846 ns/iter (± 55789) 1.00
es/lexer/yui 4613323 ns/iter (± 1311) 4592482 ns/iter (± 3715) 1.00
es/parser/colors 29566 ns/iter (± 42) 29254 ns/iter (± 81) 1.01
es/parser/angular 15965980 ns/iter (± 265989) 15633597 ns/iter (± 165972) 1.02
es/parser/backbone 2196965 ns/iter (± 10624) 2197989 ns/iter (± 7020) 1.00
es/parser/jquery 12311797 ns/iter (± 106232) 12315066 ns/iter (± 209245) 1.00
es/parser/jquery mobile 19923757 ns/iter (± 350753) 20206127 ns/iter (± 515772) 0.99
es/parser/mootools 9197569 ns/iter (± 38435) 9125385 ns/iter (± 45383) 1.01
es/parser/underscore 1862669 ns/iter (± 9920) 1863137 ns/iter (± 10863) 1.00
es/parser/three 56261470 ns/iter (± 284307) 56737017 ns/iter (± 224822) 0.99
es/parser/yui 9378293 ns/iter (± 102851) 9310638 ns/iter (± 80911) 1.01
es/preset-env/usage/builtin_type 140989 ns/iter (± 33530) 142176 ns/iter (± 32564) 0.99
es/preset-env/usage/property 20827 ns/iter (± 88) 21142 ns/iter (± 92) 0.99
es/resolver/typescript 118238098 ns/iter (± 2807283) 124986356 ns/iter (± 1614793) 0.95
es/fixer/typescript 79606479 ns/iter (± 1240222) 88100644 ns/iter (± 2561498) 0.90
es/hygiene/typescript 167954784 ns/iter (± 1230164) 183790986 ns/iter (± 1352309) 0.91
es/resolver_with_hygiene/typescript 319740106 ns/iter (± 1956497) 327934195 ns/iter (± 2211042) 0.98
es/visitor/base-perf/module_clone 79571 ns/iter (± 1405) 80176 ns/iter (± 1203) 0.99
es/visitor/base-perf/fold_empty 88331 ns/iter (± 1370) 90516 ns/iter (± 1356) 0.98
es/visitor/base-perf/fold_noop_impl_all 90131 ns/iter (± 1871) 90146 ns/iter (± 1309) 1.00
es/visitor/base-perf/fold_noop_impl_vec 91029 ns/iter (± 1285) 90908 ns/iter (± 1204) 1.00
es/visitor/base-perf/boxing_boxed_clone 56 ns/iter (± 0) 59 ns/iter (± 0) 0.95
es/visitor/base-perf/boxing_unboxed_clone 53 ns/iter (± 0) 53 ns/iter (± 0) 1
es/visitor/base-perf/boxing_boxed 101 ns/iter (± 0) 104 ns/iter (± 0) 0.97
es/visitor/base-perf/boxing_unboxed 97 ns/iter (± 0) 100 ns/iter (± 0) 0.97
es/visitor/base-perf/visit_contains_this 3617 ns/iter (± 48) 3473 ns/iter (± 57) 1.04
es/base/parallel/resolver/typescript 6736891945 ns/iter (± 444399279) 6747873954 ns/iter (± 367723472) 1.00
es/base/parallel/hygiene/typescript 1971385546 ns/iter (± 23498942) 2149697465 ns/iter (± 20697184) 0.92
misc/visitors/time-complexity/time 5 91 ns/iter (± 0) 97 ns/iter (± 0) 0.94
misc/visitors/time-complexity/time 10 290 ns/iter (± 4) 295 ns/iter (± 1) 0.98
misc/visitors/time-complexity/time 15 638 ns/iter (± 7) 608 ns/iter (± 25) 1.05
misc/visitors/time-complexity/time 20 1125 ns/iter (± 14) 1138 ns/iter (± 10) 0.99
misc/visitors/time-complexity/time 40 5780 ns/iter (± 44) 6019 ns/iter (± 18) 0.96
misc/visitors/time-complexity/time 60 12859 ns/iter (± 8) 15181 ns/iter (± 47) 0.85
es/full-target/es2016 251233 ns/iter (± 1175) 250498 ns/iter (± 407) 1.00
es/full-target/es2017 243531 ns/iter (± 459) 242543 ns/iter (± 389) 1.00
es/full-target/es2018 232733 ns/iter (± 466) 230954 ns/iter (± 445) 1.01
es2020_nullish_coalescing 91252 ns/iter (± 558) 90560 ns/iter (± 261) 1.01
es2020_optional_chaining 124061 ns/iter (± 268) 124043 ns/iter (± 528) 1.00
es2022_class_properties 148462 ns/iter (± 332) 146017 ns/iter (± 210) 1.02
es2018_object_rest_spread 95164 ns/iter (± 132) 94724 ns/iter (± 257) 1.00
es2019_optional_catch_binding 84714 ns/iter (± 209) 83861 ns/iter (± 181) 1.01
es2017_async_to_generator 85507 ns/iter (± 157) 85012 ns/iter (± 262) 1.01
es2016_exponentiation 89605 ns/iter (± 185) 88882 ns/iter (± 233) 1.01
es2015_arrow 94039 ns/iter (± 289) 93027 ns/iter (± 147) 1.01
es2015_block_scoped_fn 90948 ns/iter (± 288) 90537 ns/iter (± 260) 1.00
es2015_block_scoping 169621 ns/iter (± 400) 168304 ns/iter (± 331) 1.01

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.