Skip to content

Commit

Permalink
feat(es/transforms/react): Improve development more (#2542)
Browse files Browse the repository at this point in the history
swc_ecma_transforms_react:
 - `jsx_src`: Add column to `__source`.
 - `jsx`: Support `jsxDEV`.
 - `jsx`: Handle `__source` and `__self` specially.
  • Loading branch information
kdy1 authored Oct 26, 2021
1 parent b8933e3 commit 70f5583
Show file tree
Hide file tree
Showing 7 changed files with 209 additions and 71 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

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

2 changes: 1 addition & 1 deletion ecmascript/transforms/react/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ include = ["Cargo.toml", "src/**/*.rs"]
license = "Apache-2.0/MIT"
name = "swc_ecma_transforms_react"
repository = "https://github.com/swc-project/swc.git"
version = "0.55.0"
version = "0.55.1"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
Expand Down
236 changes: 173 additions & 63 deletions ecmascript/transforms/react/src/jsx/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use swc_ecma_ast::*;
use swc_ecma_parser::{Parser, StringInput, Syntax};
use swc_ecma_transforms_base::helper;
use swc_ecma_utils::{
drop_span, member_expr, prepend, private_ident, quote_ident, ExprFactory, HANDLER,
drop_span, member_expr, prepend, private_ident, quote_ident, undefined, ExprFactory, HANDLER,
};
use swc_ecma_visit::{as_folder, noop_visit_mut_type, Fold, VisitMut, VisitMutWith};

Expand Down Expand Up @@ -198,16 +198,19 @@ where
import_source: options.import_source.into(),
import_jsx: None,
import_jsxs: None,
import_fragment: None,
import_create_element: None,

dev: None,
development: options.development,

import_fragment: None,
top_level_node: true,
pragma: parse_expr_for_jsx(&cm, "pragma", options.pragma, top_level_mark),
comments,
pragma_frag: parse_expr_for_jsx(&cm, "pragmaFrag", options.pragma_frag, top_level_mark),
use_builtins: options.use_builtins,
use_spread: options.use_spread,
throw_if_namespace: options.throw_if_namespace,
top_level_node: true,
})
}

Expand All @@ -217,6 +220,8 @@ where
{
cm: Lrc<SourceMap>,

development: bool,

top_level_mark: Mark,

next: bool,
Expand All @@ -233,6 +238,9 @@ where
import_fragment: Option<Ident>,
top_level_node: bool,

/// For automatic runtime.
dev: Option<JsxDevMode>,

pragma: Arc<Box<Expr>>,
comments: Option<C>,
pragma_frag: Arc<Box<Expr>>,
Expand All @@ -241,6 +249,10 @@ where
throw_if_namespace: bool,
}

struct JsxDevMode {
import: Ident,
}

#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct JsxDirectives {
pub runtime: Option<Runtime>,
Expand Down Expand Up @@ -326,6 +338,12 @@ impl<C> Jsx<C>
where
C: Comments,
{
fn dev_mode(&mut self) -> &mut JsxDevMode {
self.dev.get_or_insert_with(|| JsxDevMode {
import: private_ident!("_jsxDEV"),
})
}

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

Expand All @@ -337,14 +355,18 @@ where

match self.runtime {
Runtime::Automatic => {
let jsx = if use_jsxs {
self.import_jsxs
.get_or_insert_with(|| private_ident!("_jsxs"))
.clone()
let jsx = if self.development {
self.dev_mode().import.clone()
} else {
self.import_jsx
.get_or_insert_with(|| private_ident!("_jsx"))
.clone()
if use_jsxs {
self.import_jsxs
.get_or_insert_with(|| private_ident!("_jsxs"))
.clone()
} else {
self.import_jsx
.get_or_insert_with(|| private_ident!("_jsx"))
.clone()
}
};

let fragment = self
Expand Down Expand Up @@ -443,14 +465,20 @@ where
self.import_create_element
.get_or_insert_with(|| private_ident!("_createElement"))
.clone()
} else if use_jsxs {
self.import_jsxs
.get_or_insert_with(|| private_ident!("_jsxs"))
.clone()
} else {
self.import_jsx
.get_or_insert_with(|| private_ident!("_jsx"))
.clone()
if self.development {
self.dev_mode().import.clone()
} else {
if use_jsxs {
self.import_jsxs
.get_or_insert_with(|| private_ident!("_jsxs"))
.clone()
} else {
self.import_jsx
.get_or_insert_with(|| private_ident!("_jsx"))
.clone()
}
}
};

let mut props_obj = ObjectLit {
Expand All @@ -460,12 +488,36 @@ where

let mut key = None;

let mut source_attr = None;
let mut self_attr = None;

for attr in el.opening.attrs {
match attr {
JSXAttrOrSpread::JSXAttr(attr) => {
//
match attr.name {
JSXAttrName::Ident(i) => {
match &*i.sym {
"__source" => {
source_attr = attr
.value
.map(jsx_attr_value_to_expr)
.flatten()
.map(|expr| ExprOrSpread { expr, spread: None });
continue;
}
"__self" => {
self_attr = attr
.value
.map(jsx_attr_value_to_expr)
.flatten()
.map(|expr| ExprOrSpread { expr, spread: None });
continue;
}

_ => {}
}

//
if !use_create_element && i.sym == js_word!("key") {
key = attr
Expand Down Expand Up @@ -555,6 +607,8 @@ where
}
}

let children_cnt = el.children.len();

let children = el
.children
.into_iter()
Expand Down Expand Up @@ -587,13 +641,38 @@ where

self.top_level_node = top_level_node;

let mut args = once(name.as_arg())
.chain(once(props_obj.as_arg()))
.collect::<Vec<_>>();

if !self.development {
args.extend(key);
} else {
args.push(key.unwrap_or_else(|| ExprOrSpread {
spread: None,
expr: undefined(DUMMY_SP),
}));
args.push(ExprOrSpread {
spread: None,
expr: Box::new(Expr::Lit(Lit::Bool(Bool {
span: DUMMY_SP,
value: children_cnt > 1,
}))),
});
args.push(source_attr.unwrap_or_else(|| ExprOrSpread {
spread: None,
expr: undefined(DUMMY_SP),
}));
args.push(self_attr.unwrap_or_else(|| ExprOrSpread {
spread: None,
expr: Box::new(Expr::This(ThisExpr { span: DUMMY_SP })),
}));
}

Expr::Call(CallExpr {
span,
callee: jsx.as_callee(),
args: once(name.as_arg())
.chain(once(props_obj.as_arg()))
.chain(key)
.collect(),
args,
type_args: Default::default(),
})
}
Expand Down Expand Up @@ -961,51 +1040,82 @@ where
);
}

let imports = self
.import_jsx
.take()
.map(|local| ImportNamedSpecifier {
span: DUMMY_SP,
local,
imported: Some(quote_ident!("jsx")),
is_type_only: false,
})
.into_iter()
.chain(self.import_jsxs.take().map(|local| ImportNamedSpecifier {
span: DUMMY_SP,
local,
imported: Some(quote_ident!("jsxs")),
is_type_only: false,
}))
.chain(
self.import_fragment
.take()
.map(|local| ImportNamedSpecifier {
{
// Import for development mode

if let Some(dev) = self.dev.take() {
let specifier = ImportSpecifier::Named(ImportNamedSpecifier {
span: DUMMY_SP,
local: dev.import,
imported: Some(quote_ident!("jsxDEV")),
is_type_only: false,
});

prepend(
&mut module.body,
ModuleItem::ModuleDecl(ModuleDecl::Import(ImportDecl {
span: DUMMY_SP,
local,
imported: Some(quote_ident!("Fragment")),
is_type_only: false,
}),
)
.map(ImportSpecifier::Named)
.collect::<Vec<_>>();

if !imports.is_empty() {
prepend(
&mut module.body,
ModuleItem::ModuleDecl(ModuleDecl::Import(ImportDecl {
specifiers: vec![specifier],
src: Str {
span: DUMMY_SP,
value: format!("{}/jsx-dev-runtime", self.import_source).into(),
has_escape: false,
kind: Default::default(),
},
type_only: Default::default(),
asserts: Default::default(),
})),
);
}
}

{
let imports = self
.import_jsx
.take()
.map(|local| ImportNamedSpecifier {
span: DUMMY_SP,
specifiers: imports,
src: Str {
local,
imported: Some(quote_ident!("jsx")),
is_type_only: false,
})
.into_iter()
.chain(self.import_jsxs.take().map(|local| ImportNamedSpecifier {
span: DUMMY_SP,
local,
imported: Some(quote_ident!("jsxs")),
is_type_only: false,
}))
.chain(
self.import_fragment
.take()
.map(|local| ImportNamedSpecifier {
span: DUMMY_SP,
local,
imported: Some(quote_ident!("Fragment")),
is_type_only: false,
}),
)
.map(ImportSpecifier::Named)
.collect::<Vec<_>>();

if !imports.is_empty() {
prepend(
&mut module.body,
ModuleItem::ModuleDecl(ModuleDecl::Import(ImportDecl {
span: DUMMY_SP,
value: format!("{}/jsx-runtime", self.import_source).into(),
has_escape: false,
kind: Default::default(),
},
type_only: Default::default(),
asserts: Default::default(),
})),
);
specifiers: imports,
src: Str {
span: DUMMY_SP,
value: format!("{}/jsx-runtime", self.import_source).into(),
has_escape: false,
kind: Default::default(),
},
type_only: Default::default(),
asserts: Default::default(),
})),
);
}
}
}
}
Expand Down
16 changes: 10 additions & 6 deletions ecmascript/transforms/react/src/jsx_src/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,7 @@ impl VisitMut for JsxSrc {
return;
}

let file_lines = match self.cm.span_to_lines(e.span) {
Ok(v) => v,
_ => return,
};
let loc = self.cm.lookup_char_pos(e.span.lo);

e.attrs.push(JSXAttrOrSpread::JSXAttr(JSXAttr {
span: DUMMY_SP,
Expand All @@ -54,7 +51,7 @@ impl VisitMut for JsxSrc {
key: PropName::Ident(quote_ident!("fileName")),
value: Box::new(Expr::Lit(Lit::Str(Str {
span: DUMMY_SP,
value: file_lines.file.name.to_string().into(),
value: loc.file.name.to_string().into(),
has_escape: false,
kind: Default::default(),
}))),
Expand All @@ -63,7 +60,14 @@ impl VisitMut for JsxSrc {
key: PropName::Ident(quote_ident!("lineNumber")),
value: Box::new(Expr::Lit(Lit::Num(Number {
span: DUMMY_SP,
value: (file_lines.lines[0].line_index + 1) as _,
value: loc.line as _,
}))),
}))),
PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
key: PropName::Ident(quote_ident!("columnNumber")),
value: Box::new(Expr::Lit(Lit::Num(Number {
span: DUMMY_SP,
value: (loc.col.0 + 1) as _,
}))),
}))),
],
Expand Down
Loading

1 comment on commit 70f5583

@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: 70f5583 Previous: b8933e3 Ratio
base_tr_fixer 24007 ns/iter (± 373) 23882 ns/iter (± 456) 1.01
base_tr_resolver_and_hygiene 132209 ns/iter (± 25832) 131945 ns/iter (± 14615) 1.00
codegen_es2015 51814 ns/iter (± 370) 51075 ns/iter (± 318) 1.01
codegen_es2016 51812 ns/iter (± 384) 51433 ns/iter (± 339) 1.01
codegen_es2017 51711 ns/iter (± 436) 51369 ns/iter (± 412) 1.01
codegen_es2018 51532 ns/iter (± 358) 51415 ns/iter (± 361) 1.00
codegen_es2019 51713 ns/iter (± 465) 51334 ns/iter (± 371) 1.01
codegen_es2020 51852 ns/iter (± 393) 51067 ns/iter (± 389) 1.02
codegen_es3 51688 ns/iter (± 383) 51294 ns/iter (± 439) 1.01
codegen_es5 52232 ns/iter (± 388) 51489 ns/iter (± 374) 1.01
config_for_file 14093 ns/iter (± 1641) 12890 ns/iter (± 4234) 1.09
full_es2015 191367142 ns/iter (± 14453907) 180580162 ns/iter (± 4768157) 1.06
full_es2016 147458176 ns/iter (± 10398241) 143015153 ns/iter (± 6259457) 1.03
full_es2017 159979802 ns/iter (± 8902336) 151079240 ns/iter (± 9468129) 1.06
full_es2018 158889199 ns/iter (± 14290962) 148789283 ns/iter (± 6888370) 1.07
full_es2019 157043498 ns/iter (± 10988502) 149521074 ns/iter (± 6169306) 1.05
full_es2020 158191641 ns/iter (± 17805437) 149029362 ns/iter (± 7792294) 1.06
full_es3 245769471 ns/iter (± 27496104) 217580139 ns/iter (± 19460829) 1.13
full_es5 222661476 ns/iter (± 18236583) 203851472 ns/iter (± 13214868) 1.09
parser 667874 ns/iter (± 15884) 658442 ns/iter (± 18789) 1.01
transforms_es2015 1153235 ns/iter (± 137900) 1000631 ns/iter (± 73957) 1.15
transforms_es2016 671208 ns/iter (± 50829) 591812 ns/iter (± 68531) 1.13
transforms_es2017 650588 ns/iter (± 46710) 568536 ns/iter (± 19364) 1.14
transforms_es2018 617308 ns/iter (± 50595) 562701 ns/iter (± 50204) 1.10
transforms_es2019 596335 ns/iter (± 51040) 548841 ns/iter (± 23558) 1.09
transforms_es2020 633514 ns/iter (± 37130) 538311 ns/iter (± 32579) 1.18
transforms_es3 1500632 ns/iter (± 111765) 1127953 ns/iter (± 56706) 1.33
transforms_es5 1230975 ns/iter (± 172687) 985705 ns/iter (± 28368) 1.25
ser_ast_node 150 ns/iter (± 2) 149 ns/iter (± 4) 1.01
ser_serde 158 ns/iter (± 2) 158 ns/iter (± 0) 1
emit_colors 12297831 ns/iter (± 10270197) 15695609 ns/iter (± 21418291) 0.78
emit_large 102128183 ns/iter (± 157261503) 80212289 ns/iter (± 132039808) 1.27
base_clone 2583539 ns/iter (± 911225) 2383554 ns/iter (± 65281) 1.08
fold_span 4697669 ns/iter (± 754076) 3914825 ns/iter (± 189458) 1.20
fold_span_panic 4853933 ns/iter (± 874839) 4160214 ns/iter (± 141117) 1.17
visit_mut_span 3359419 ns/iter (± 929524) 2815834 ns/iter (± 161120) 1.19
visit_mut_span_panic 3041017 ns/iter (± 430633) 2883020 ns/iter (± 90721) 1.05
boxing_boxed 144 ns/iter (± 0) 156 ns/iter (± 1) 0.92
boxing_boxed_clone 76 ns/iter (± 11) 68 ns/iter (± 0) 1.12
boxing_unboxed 136 ns/iter (± 0) 147 ns/iter (± 1) 0.93
boxing_unboxed_clone 64 ns/iter (± 0) 63 ns/iter (± 0) 1.02

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

Please sign in to comment.