Skip to content

Commit

Permalink
feat(transformer/react): support development mode
Browse files Browse the repository at this point in the history
  • Loading branch information
Dunqing committed May 9, 2024
1 parent 0ba7778 commit 4876089
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 33 deletions.
123 changes: 97 additions & 26 deletions crates/oxc_transformer/src/react/jsx/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,15 @@ impl<'a> ReactJsx<'a> {
let default_runtime = options.runtime;
let jsx_runtime_importer =
if options.import_source == "react" || default_runtime.is_classic() {
CompactStr::from("react/jsx-runtime")
let source =
if options.development { "react/jsx-dev-runtime" } else { "react/jsx-runtime" };
CompactStr::from(source)
} else {
CompactStr::from(format!("{}/jsx-runtime", options.import_source))
CompactStr::from(format!(
"{}/jsx-{}runtime",
options.import_source,
if options.development { "dev-" } else { "" }
))
};

Self {
Expand Down Expand Up @@ -153,17 +159,17 @@ impl<'a> ReactJsx<'a> {
fn add_require_jsx_runtime(&mut self) {
if !self.require_jsx_runtime {
self.require_jsx_runtime = true;
self.add_require_statement(
"_reactJsxRuntime",
self.jsx_runtime_importer.clone(),
false,
);
let variable_name =
if self.options.development { "_reactJsxDevRuntime" } else { "_reactJsxRuntime" };
self.add_require_statement(variable_name, self.jsx_runtime_importer.clone(), false);
}
}

fn add_import_jsx(&mut self) {
if self.is_script() {
self.add_require_jsx_runtime();
} else if self.options.development {
self.add_import_jsx_dev();
} else if !self.import_jsx {
self.import_jsx = true;
self.add_import_statement("jsx", "_jsx", self.jsx_runtime_importer.clone());
Expand All @@ -173,12 +179,23 @@ impl<'a> ReactJsx<'a> {
fn add_import_jsxs(&mut self) {
if self.is_script() {
self.add_require_jsx_runtime();
} else if self.options.development {
self.add_import_jsx_dev();
} else if !self.import_jsxs {
self.import_jsxs = true;
self.add_import_statement("jsxs", "_jsxs", self.jsx_runtime_importer.clone());
}
}

fn add_import_jsx_dev(&mut self) {
if self.is_script() {
self.add_require_jsx_runtime();
} else if !self.import_jsx {
self.import_jsx = true;
self.add_import_statement("jsxDEV", "_jsxDEV", self.jsx_runtime_importer.clone());
}
}

fn add_import_fragment(&mut self) {
if self.is_script() {
self.add_require_jsx_runtime();
Expand Down Expand Up @@ -262,6 +279,7 @@ impl<'a> ReactJsx<'a> {
fn transform_jsx<'b>(&mut self, e: &JSXElementOrFragment<'a, 'b>) -> Expression<'a> {
let is_classic = self.default_runtime.is_classic();
let is_automatic = self.default_runtime.is_automatic();
let is_fragment = matches!(e, JSXElementOrFragment::Fragment(_));
let has_key_after_props_spread = e.has_key_after_props_spread();

let mut arguments = self.ast().new_vec();
Expand Down Expand Up @@ -363,21 +381,24 @@ impl<'a> ReactJsx<'a> {
properties.push(ObjectPropertyKind::ObjectProperty(object_property));
}
}

if self.options.is_jsx_self_plugin_enabled() {
if let Some(span) = self_attr_span {
self.jsx_self.report_error(span);
} else {
properties.push(self.jsx_self.get_object_property_kind_for_jsx_plugin());
if has_key_after_props_spread || self.options.runtime.is_classic() {
if self.options.is_jsx_self_plugin_enabled() {
if let Some(span) = self_attr_span {
self.jsx_self.report_error(span);
} else {
properties.push(self.jsx_self.get_object_property_kind_for_jsx_plugin());
}
}
}
if self.options.is_jsx_source_plugin_enabled() {
if let Some(span) = source_attr_span {
self.jsx_source.report_error(span);
} else {
let (line, column) = get_line_column(e.span().start, self.ctx.source_text);
properties
.push(self.jsx_source.get_object_property_kind_for_jsx_plugin(line, column));

if self.options.is_jsx_source_plugin_enabled() {
if let Some(span) = source_attr_span {
self.jsx_source.report_error(span);
} else {
let (line, column) = get_line_column(e.span().start, self.ctx.source_text);
properties.push(
self.jsx_source.get_object_property_kind_for_jsx_plugin(line, column),
);
}
}
}

Expand All @@ -388,8 +409,44 @@ impl<'a> ReactJsx<'a> {
arguments.push(Argument::from(object_expression));
}

if is_automatic && key_prop.is_some() {
arguments.push(Argument::from(self.transform_jsx_attribute_value(key_prop)));
if is_automatic {
if key_prop.is_some() {
arguments.push(Argument::from(self.transform_jsx_attribute_value(key_prop)));
} else if self.options.development && !has_key_after_props_spread {
arguments.push(Argument::from(self.ctx.ast.void_0()));
}

if !has_key_after_props_spread {
if self.options.development {
let literal = self.ctx.ast.boolean_literal(
SPAN,
if is_fragment { false } else { children.len() > 1 },
);
arguments
.push(Argument::from(self.ctx.ast.literal_boolean_expression(literal)));
}

if !is_fragment {
if self.options.is_jsx_source_plugin_enabled() {
if let Some(span) = source_attr_span {
self.jsx_source.report_error(span);
} else {
let (line, column) =
get_line_column(e.span().start, self.ctx.source_text);
let expr = self.jsx_source.get_source_object(line, column);
arguments.push(Argument::from(expr));
}
}

if self.options.is_jsx_self_plugin_enabled() {
if let Some(span) = self_attr_span {
self.jsx_self.report_error(span);
} else {
arguments.push(Argument::from(self.ctx.ast.this_expression(SPAN)));
}
}
}
}
}

if is_classic && !children.is_empty() {
Expand Down Expand Up @@ -445,7 +502,12 @@ impl<'a> ReactJsx<'a> {
}
ReactJsxRuntime::Automatic => {
if self.is_script() {
self.get_static_member_expression("_reactJsxRuntime", "Fragment")
let object_name = if self.options.development {
"_reactJsxDevRuntime"
} else {
"_reactJsxRuntime"
};
self.get_static_member_expression(object_name, "Fragment")
} else {
let ident = IdentifierReference::new(SPAN, "_Fragment".into());
self.ast().identifier_reference_expression(ident)
Expand All @@ -469,21 +531,30 @@ impl<'a> ReactJsx<'a> {
let name = if self.is_script() {
if has_key_after_props_spread {
"createElement"
} else if self.options.development {
"jsxDEV"
} else if jsxs {
"jsxs"
} else {
"jsx"
}
} else if has_key_after_props_spread {
"_createElement"
} else if self.options.development {
"_jsxDEV"
} else if jsxs {
"_jsxs"
} else {
"_jsx"
};
if self.is_script() {
let object_ident_name =
if has_key_after_props_spread { "_react" } else { "_reactJsxRuntime" };
let object_ident_name = if has_key_after_props_spread {
"_react"
} else if self.options.development {
"_reactJsxDevRuntime"
} else {
"_reactJsxRuntime"
};
self.get_static_member_expression(object_ident_name, name)
} else {
let ident = IdentifierReference::new(SPAN, name.into());
Expand Down
7 changes: 3 additions & 4 deletions crates/oxc_transformer/src/react/jsx_source/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ impl<'a> ReactJsxSource<'a> {
line: usize,
column: usize,
) -> ObjectPropertyKind<'a> {
self.should_add_jsx_file_name_variable = true;
let kind = PropertyKind::Init;
let ident = IdentifierName::new(SPAN, SOURCE.into());
let key = self.ctx.ast.property_key_identifier(ident);
Expand Down Expand Up @@ -84,8 +83,6 @@ impl<'a> ReactJsxSource<'a> {
}
}

self.should_add_jsx_file_name_variable = true;

let key = JSXAttributeName::Identifier(
self.ctx.ast.alloc(self.ctx.ast.jsx_identifier(SPAN, SOURCE.into())),
);
Expand All @@ -98,7 +95,9 @@ impl<'a> ReactJsxSource<'a> {
}

#[allow(clippy::cast_precision_loss)]
fn get_source_object(&self, line: usize, column: usize) -> Expression<'a> {
pub fn get_source_object(&mut self, line: usize, column: usize) -> Expression<'a> {
self.should_add_jsx_file_name_variable = true;

let kind = PropertyKind::Init;

let filename = {
Expand Down
5 changes: 2 additions & 3 deletions tasks/transform_conformance/babel.snap.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Passed: 296/362
Passed: 297/362

# All Passed:
* babel-plugin-transform-react-display-name
Expand Down Expand Up @@ -73,8 +73,7 @@ Passed: 296/362
* react-source/arrow-function/input.js
* react-source/disable-with-super/input.js

# babel-plugin-transform-react-jsx-development (2/12)
* cross-platform/auto-import-dev/input.js
# babel-plugin-transform-react-jsx-development (3/12)
* cross-platform/classic-runtime/input.js
* cross-platform/fragments/input.js
* cross-platform/handle-fragments-with-key/input.js
Expand Down

0 comments on commit 4876089

Please sign in to comment.