diff --git a/crates/node_binding/napi-binding.d.ts b/crates/node_binding/napi-binding.d.ts index fb7a14c97629..d984f5570227 100644 --- a/crates/node_binding/napi-binding.d.ts +++ b/crates/node_binding/napi-binding.d.ts @@ -2333,6 +2333,11 @@ export interface RawJavascriptParserOptions { * @experimental */ typeReexportsPresence?: string + /** + * This option is experimental in Rspack only and subject to change or be removed anytime. + * @experimental + */ + jsx?: boolean } export interface RawJsonGeneratorOptions { diff --git a/crates/rspack/src/builder/mod.rs b/crates/rspack/src/builder/mod.rs index 75a6b8843148..3f0313304ab6 100644 --- a/crates/rspack/src/builder/mod.rs +++ b/crates/rspack/src/builder/mod.rs @@ -1716,6 +1716,7 @@ impl ModuleOptionsBuilder { import_dynamic: Some(true), commonjs_magic_comments: Some(false), inline_const: Some(false), + jsx: Some(false), ..Default::default() }), ); diff --git a/crates/rspack/tests/snapshots/defaults__default_options.snap b/crates/rspack/tests/snapshots/defaults__default_options.snap index 1b4ede75bc27..772f74095ac9 100644 --- a/crates/rspack/tests/snapshots/defaults__default_options.snap +++ b/crates/rspack/tests/snapshots/defaults__default_options.snap @@ -1444,6 +1444,9 @@ CompilerOptions { inline_const: Some( false, ), + jsx: Some( + false, + ), }, ), }, diff --git a/crates/rspack_binding_api/src/raw_options/raw_module/mod.rs b/crates/rspack_binding_api/src/raw_options/raw_module/mod.rs index dbe5d19d118e..a8c7147f6b19 100644 --- a/crates/rspack_binding_api/src/raw_options/raw_module/mod.rs +++ b/crates/rspack_binding_api/src/raw_options/raw_module/mod.rs @@ -298,6 +298,9 @@ pub struct RawJavascriptParserOptions { /// This option is experimental in Rspack only and subject to change or be removed anytime. /// @experimental pub type_reexports_presence: Option, + /// This option is experimental in Rspack only and subject to change or be removed anytime. + /// @experimental + pub jsx: Option, } impl From for JavascriptParserOptions { @@ -344,6 +347,7 @@ impl From for JavascriptParserOptions { import_dynamic: value.import_dynamic, commonjs_magic_comments: value.commonjs_magic_comments, inline_const: value.inline_const, + jsx: value.jsx, } } } diff --git a/crates/rspack_core/src/concatenated_module.rs b/crates/rspack_core/src/concatenated_module.rs index 5028c204a39d..c709d19a1f57 100644 --- a/crates/rspack_core/src/concatenated_module.rs +++ b/crates/rspack_core/src/concatenated_module.rs @@ -30,7 +30,7 @@ use swc_core::{ ecma::{ ast::{EsVersion, Program}, atoms::Atom, - parser::{Syntax, parse_file_as_module}, + parser::{EsSyntax, Syntax, parse_file_as_module}, transforms::base::resolver, }, }; @@ -47,13 +47,13 @@ use crate::{ IdentCollector, InitFragment, InitFragmentStage, LibIdentOptions, MaybeDynamicTargetExportInfoHashKey, Module, ModuleArgument, ModuleGraph, ModuleGraphCacheArtifact, ModuleGraphConnection, ModuleIdentifier, ModuleLayer, - ModuleStaticCacheArtifact, ModuleType, NAMESPACE_OBJECT_EXPORT, PrefetchExportsInfoMode, Resolve, - RuntimeCondition, RuntimeGlobals, RuntimeSpec, SourceType, UsageState, UsedName, UsedNameItem, - define_es_module_flag_statement, escape_identifier, filter_runtime, get_runtime_key, - impl_source_map_config, merge_runtime_condition, merge_runtime_condition_non_false, - module_update_hash, property_access, property_name, reserved_names::RESERVED_NAMES, - returning_function, runtime_condition_expression, subtract_runtime_condition, - to_identifier_with_escaped, to_normal_comment, + ModuleStaticCacheArtifact, ModuleType, NAMESPACE_OBJECT_EXPORT, ParserOptions, + PrefetchExportsInfoMode, Resolve, RuntimeCondition, RuntimeGlobals, RuntimeSpec, SourceType, + UsageState, UsedName, UsedNameItem, define_es_module_flag_statement, escape_identifier, + filter_runtime, get_runtime_key, impl_source_map_config, merge_runtime_condition, + merge_runtime_condition_non_false, module_update_hash, property_access, property_name, + reserved_names::RESERVED_NAMES, returning_function, runtime_condition_expression, + subtract_runtime_condition, to_identifier_with_escaped, to_normal_comment, }; type ExportsDefinitionArgs = Vec<(String, String)>; @@ -1993,10 +1993,24 @@ impl ConcatenatedModule { let comments = SwcComments::default(); let mut module_info = concatenation_scope.current_module; + let jsx = module + .as_ref() + .as_normal_module() + .and_then(|normal_module| normal_module.get_parser_options()) + .and_then(|options: &ParserOptions| { + options + .get_javascript() + .and_then(|js_options| js_options.jsx) + }) + .unwrap_or(false); + let mut errors = vec![]; let program = match parse_file_as_module( &fm, - Syntax::default(), + Syntax::Es(EsSyntax { + jsx, + ..Default::default() + }), EsVersion::EsNext, Some(&comments), &mut errors, diff --git a/crates/rspack_core/src/options/module.rs b/crates/rspack_core/src/options/module.rs index f13969113207..d11b3f3011be 100644 --- a/crates/rspack_core/src/options/module.rs +++ b/crates/rspack_core/src/options/module.rs @@ -284,6 +284,7 @@ pub struct JavascriptParserOptions { pub import_dynamic: Option, pub commonjs_magic_comments: Option, pub inline_const: Option, + pub jsx: Option, } #[cacheable] diff --git a/crates/rspack_plugin_javascript/src/parser_and_generator/mod.rs b/crates/rspack_plugin_javascript/src/parser_and_generator/mod.rs index e7d7d207dcf0..e4b39d834103 100644 --- a/crates/rspack_plugin_javascript/src/parser_and_generator/mod.rs +++ b/crates/rspack_plugin_javascript/src/parser_and_generator/mod.rs @@ -179,8 +179,15 @@ impl ParserAndGenerator for JavaScriptParserAndGenerator { ); let comments = SwcComments::default(); let target = ast::EsVersion::EsNext; + + let jsx = module_parser_options + .and_then(|options| options.get_javascript()) + .and_then(|options| options.jsx) + .unwrap_or(false); + let parser_lexer = Lexer::new( Syntax::Es(EsSyntax { + jsx, allow_return_outside_function: matches!( module_type, ModuleType::JsDynamic | ModuleType::JsAuto diff --git a/crates/rspack_plugin_javascript/src/visitors/dependency/parser/walk.rs b/crates/rspack_plugin_javascript/src/visitors/dependency/parser/walk.rs index 031e4c918615..214fa46d9faf 100644 --- a/crates/rspack_plugin_javascript/src/visitors/dependency/parser/walk.rs +++ b/crates/rspack_plugin_javascript/src/visitors/dependency/parser/walk.rs @@ -7,11 +7,13 @@ use swc_core::{ ArrayLit, ArrayPat, ArrowExpr, AssignExpr, AssignPat, AssignTarget, AssignTargetPat, AwaitExpr, BinExpr, BlockStmt, BlockStmtOrExpr, CallExpr, Callee, CatchClause, Class, ClassExpr, ClassMember, CondExpr, DefaultDecl, DoWhileStmt, ExportDefaultDecl, Expr, ExprOrSpread, - ExprStmt, FnExpr, ForHead, ForInStmt, ForOfStmt, ForStmt, Function, GetterProp, Ident, IfStmt, - KeyValueProp, LabeledStmt, MemberExpr, MemberProp, MetaPropExpr, ModuleDecl, ModuleItem, - NewExpr, ObjectLit, ObjectPat, ObjectPatProp, OptCall, OptChainExpr, Param, Pat, Prop, - PropName, PropOrSpread, RestPat, ReturnStmt, SeqExpr, SetterProp, SimpleAssignTarget, Stmt, - SwitchCase, SwitchStmt, TaggedTpl, ThisExpr, ThrowStmt, Tpl, TryStmt, UnaryExpr, UnaryOp, + ExprStmt, FnExpr, ForHead, ForInStmt, ForOfStmt, ForStmt, Function, GetterProp, Ident, + IdentName, IfStmt, JSXAttr, JSXAttrOrSpread, JSXAttrValue, JSXElement, JSXElementChild, + JSXElementName, JSXExpr, JSXExprContainer, JSXFragment, JSXMemberExpr, JSXNamespacedName, + JSXObject, KeyValueProp, LabeledStmt, MemberExpr, MemberProp, MetaPropExpr, ModuleDecl, + ModuleItem, NewExpr, ObjectLit, ObjectPat, ObjectPatProp, OptCall, OptChainExpr, Param, Pat, + Prop, PropName, PropOrSpread, RestPat, ReturnStmt, SeqExpr, SetterProp, SimpleAssignTarget, + Stmt, SwitchCase, SwitchStmt, TaggedTpl, ThisExpr, ThrowStmt, Tpl, TryStmt, UnaryExpr, UnaryOp, UpdateExpr, VarDeclOrExpr, WhileStmt, WithStmt, YieldExpr, }, }; @@ -431,12 +433,18 @@ impl JavascriptParser<'_> { Expr::Update(expr) => self.walk_update_expression(expr), Expr::Yield(expr) => self.walk_yield_expression(expr), Expr::SuperProp(_) | Expr::Lit(_) | Expr::PrivateName(_) | Expr::Invalid(_) => (), + Expr::JSXMember(_) | Expr::JSXNamespacedName(_) | Expr::JSXEmpty(_) => { + self.ensure_jsx_enabled(); + } + Expr::JSXElement(element) => { + self.ensure_jsx_enabled(); + self.walk_jsx_element(element); + } + Expr::JSXFragment(fragment) => { + self.ensure_jsx_enabled(); + self.walk_jsx_fragment(fragment); + } Expr::Paren(_) - | Expr::JSXMember(_) - | Expr::JSXNamespacedName(_) - | Expr::JSXEmpty(_) - | Expr::JSXElement(_) - | Expr::JSXFragment(_) | Expr::TsTypeAssertion(_) | Expr::TsConstAssertion(_) | Expr::TsNonNull(_) @@ -516,6 +524,114 @@ impl JavascriptParser<'_> { } } + fn ensure_jsx_enabled(&self) { + if !self.javascript_options.jsx.unwrap_or_default() { + unreachable!(); + } + } + + fn walk_jsx_element(&mut self, element: &JSXElement) { + self.walk_jsx_element_name(&element.opening.name); + if element.opening.type_args.is_some() { + // JSX type arguments only exist in TSX; this walker assumes pure JSX input. + unreachable!(); + } + for attr in &element.opening.attrs { + self.walk_jsx_attr_or_spread(attr); + } + for child in &element.children { + self.walk_jsx_child(child); + } + if let Some(closing) = &element.closing { + self.walk_jsx_element_name(&closing.name); + } + } + + fn walk_jsx_fragment(&mut self, fragment: &JSXFragment) { + for child in &fragment.children { + self.walk_jsx_child(child); + } + } + + fn walk_jsx_child(&mut self, child: &JSXElementChild) { + match child { + JSXElementChild::JSXElement(element) => self.walk_jsx_element(element), + JSXElementChild::JSXFragment(fragment) => self.walk_jsx_fragment(fragment), + JSXElementChild::JSXExprContainer(container) => self.walk_jsx_expr_container(container), + JSXElementChild::JSXSpreadChild(spread) => self.walk_expression(&spread.expr), + JSXElementChild::JSXText(_) => (), + } + } + + fn walk_jsx_expr_container(&mut self, container: &JSXExprContainer) { + match &container.expr { + JSXExpr::Expr(expr) => self.walk_expression(expr), + JSXExpr::JSXEmptyExpr(_) => (), + } + } + + fn walk_jsx_attr_or_spread(&mut self, attr: &JSXAttrOrSpread) { + match attr { + JSXAttrOrSpread::JSXAttr(attr) => self.walk_jsx_attr(attr), + JSXAttrOrSpread::SpreadElement(spread) => self.walk_expression(&spread.expr), + } + } + + fn walk_jsx_attr(&mut self, attr: &JSXAttr) { + if let Some(value) = &attr.value { + self.walk_jsx_attr_value(value); + } + } + + fn walk_jsx_attr_value(&mut self, value: &JSXAttrValue) { + match value { + JSXAttrValue::Lit(_) => (), + JSXAttrValue::JSXExprContainer(container) => self.walk_jsx_expr_container(container), + JSXAttrValue::JSXElement(element) => self.walk_jsx_element(element), + JSXAttrValue::JSXFragment(fragment) => self.walk_jsx_fragment(fragment), + } + } + + fn walk_jsx_element_name(&mut self, name: &JSXElementName) { + match name { + JSXElementName::Ident(ident) => self.walk_identifier(ident), + JSXElementName::JSXMemberExpr(member) => self.walk_jsx_member_expr(member), + JSXElementName::JSXNamespacedName(namespaced) => self.walk_jsx_namespaced_name(namespaced), + } + } + + fn walk_jsx_member_expr(&mut self, member: &JSXMemberExpr) { + let member_expr = Self::jsx_member_expr_to_member_expr(member); + self.walk_member_expression(&member_expr); + } + + fn jsx_member_expr_to_member_expr(member: &JSXMemberExpr) -> MemberExpr { + MemberExpr { + span: member.span, + obj: Box::new(Self::jsx_object_to_expr(&member.obj)), + prop: MemberProp::Ident(member.prop.clone()), + } + } + + fn jsx_object_to_expr(obj: &JSXObject) -> Expr { + match obj { + JSXObject::Ident(ident) => Expr::Ident(ident.clone()), + JSXObject::JSXMemberExpr(member) => { + Expr::Member(Self::jsx_member_expr_to_member_expr(member)) + } + } + } + + fn walk_jsx_namespaced_name(&mut self, name: &JSXNamespacedName) { + self.walk_ident_name(&name.ns); + self.walk_ident_name(&name.name); + } + + fn walk_ident_name(&mut self, name: &IdentName) { + let ident: Ident = name.clone().into(); + self.walk_identifier(&ident); + } + fn walk_object_expression(&mut self, expr: &ObjectLit) { for prop in &expr.props { self.walk_property_or_spread(prop); diff --git a/packages/rspack/etc/core.api.md b/packages/rspack/etc/core.api.md index 5edb0ddd89ab..d0394406582f 100644 --- a/packages/rspack/etc/core.api.md +++ b/packages/rspack/etc/core.api.md @@ -3380,6 +3380,7 @@ export type JavascriptParserOptions = { commonjsMagicComments?: boolean; inlineConst?: boolean; typeReexportsPresence?: "no-tolerant" | "tolerant" | "tolerant-no-check"; + jsx?: boolean; }; // @public (undocumented) diff --git a/packages/rspack/src/config/adapter.ts b/packages/rspack/src/config/adapter.ts index e8e12e368897..9f660975b008 100644 --- a/packages/rspack/src/config/adapter.ts +++ b/packages/rspack/src/config/adapter.ts @@ -586,7 +586,8 @@ function getRawJavascriptParserOptions( importDynamic: parser.importDynamic, commonjsMagicComments: parser.commonjsMagicComments, inlineConst: parser.inlineConst, - typeReexportsPresence: parser.typeReexportsPresence + typeReexportsPresence: parser.typeReexportsPresence, + jsx: parser.jsx }; } diff --git a/packages/rspack/src/config/defaults.ts b/packages/rspack/src/config/defaults.ts index 2b844b857d80..2d592acbd849 100644 --- a/packages/rspack/src/config/defaults.ts +++ b/packages/rspack/src/config/defaults.ts @@ -322,6 +322,7 @@ const applyJavascriptParserOptionsDefaults = ( D(parserOptions, "importMeta", true); D(parserOptions, "inlineConst", usedExports && inlineConst); D(parserOptions, "typeReexportsPresence", "no-tolerant"); + D(parserOptions, "jsx", false); }; const applyJsonGeneratorOptionsDefaults = ( diff --git a/packages/rspack/src/config/types.ts b/packages/rspack/src/config/types.ts index a4ae42095839..555d87dac15d 100644 --- a/packages/rspack/src/config/types.ts +++ b/packages/rspack/src/config/types.ts @@ -1118,6 +1118,9 @@ export type JavascriptParserOptions = { /** Whether to tolerant exportsPresence for type reexport */ typeReexportsPresence?: "no-tolerant" | "tolerant" | "tolerant-no-check"; + + /** Whether to enable JSX parsing */ + jsx?: boolean; }; export type JsonParserOptions = { diff --git a/packages/rspack/src/schema/config.ts b/packages/rspack/src/schema/config.ts index c10f7e8e1dc6..5b27ef88f3d4 100644 --- a/packages/rspack/src/schema/config.ts +++ b/packages/rspack/src/schema/config.ts @@ -658,6 +658,7 @@ export const getRspackOptionsSchema = memoize(() => { "tolerant", "tolerant-no-check" ]); + const jsx = z.boolean(); const javascriptParserOptions = z .strictObject({ @@ -684,7 +685,8 @@ export const getRspackOptionsSchema = memoize(() => { requireResolve: requireResolve, importDynamic: importDynamic, inlineConst: inlineConst, - typeReexportsPresence: typeReexportsPresence + typeReexportsPresence: typeReexportsPresence, + jsx: jsx // #endregion }) .partial() satisfies z.ZodType; diff --git a/packages/rspack/src/schema/loaders.ts b/packages/rspack/src/schema/loaders.ts index 3405c340d236..c75d433fd1fb 100644 --- a/packages/rspack/src/schema/loaders.ts +++ b/packages/rspack/src/schema/loaders.ts @@ -253,7 +253,7 @@ export const getZodSwcLoaderOptionsSchema = memoize(() => { }) .partial() ), - runtime: z.enum(["automatic", "classic"]), + runtime: z.enum(["automatic", "classic", "preserve"]), importSource: z.string() }) .partial() satisfies z.ZodType; diff --git a/tests/rspack-test/configCases/parsing/jsx-enabled/__snapshot__/bundle0.jsx.txt b/tests/rspack-test/configCases/parsing/jsx-enabled/__snapshot__/bundle0.jsx.txt new file mode 100644 index 000000000000..abf24a3b89c7 --- /dev/null +++ b/tests/rspack-test/configCases/parsing/jsx-enabled/__snapshot__/bundle0.jsx.txt @@ -0,0 +1,96 @@ +import { App, App1A, App1B, App1C, app1cProps } from "./App1"; +import { App2, app2Props } from "./App2"; + +;// CONCATENATED MODULE: external "./App1" + +;// CONCATENATED MODULE: external "./App2" + +;// CONCATENATED MODULE: ./index.jsx + + + +const DynamicComponent = ()=>{ + const Component = Math.random() > 0.5 ? App1A : App1C; + return import("./App1").then((mod)=>{ + const Dynamic = mod[Component === App1A ? "App1A" : "App1C"]; + return ; + }); +}; +const NamespaceComponents = { + Button: ({ label, ...rest })=> +}; +const SectionWithSpread = (props)=>
; +const spreadChildren = [ + First, + Second +]; +function Root() { + return <> + + <> + + Loading...}> + + + + + + {x ? + + + + + + : } + + + + + } fragmentContent={<> + Nested + Fragment + }/> +
+ {[ +
+ + + + {"item-one".toUpperCase()} + { /* JSXEmptyExpr in action */ } +
, +
+ + app2 + + + + + { /* JSXEmptyExpr in action */ } +
, +
+ + + + {(()=>)()} + { /* JSXEmptyExpr in action */ } +
+ ]} + {...spreadChildren} + bold" + }}/> + +
+ ; +} + +export { Root as default }; \ No newline at end of file diff --git a/tests/rspack-test/configCases/parsing/jsx-enabled/index.jsx b/tests/rspack-test/configCases/parsing/jsx-enabled/index.jsx new file mode 100644 index 000000000000..1e2bc16aab2d --- /dev/null +++ b/tests/rspack-test/configCases/parsing/jsx-enabled/index.jsx @@ -0,0 +1,105 @@ +import { App1A, App1C as C, App1C } from "./App1"; +import * as NamespaceImportApp1 from "./App1"; +import { App2, app2Props } from "./App2"; + +const DynamicComponent = () => { + const Component = Math.random() > 0.5 ? App1A : App1C; + return import("./App1").then((mod) => { + const Dynamic = mod[Component === App1A ? "App1A" : "App1C"]; + return ; + }); +}; + +const NamespaceComponents = { + Button: ({ label, ...rest }) => ( + + ), +}; + +const SectionWithSpread = (props) =>
; + +const spreadChildren = [ + First, + Second, +]; + +export default function Root() { + return ( + <> + + <> + + Loading...}> + + + + + + {x ? ( + + + + + + + + ) : ( + + )} + + + + + } + fragmentContent={ + <> + Nested + Fragment + + } + /> +
+ {[ +
+ + + + {"item-one".toUpperCase()} + {/* JSXEmptyExpr in action */} +
, +
+ + app2 + + + + + {/* JSXEmptyExpr in action */} +
, +
+ + + + {(() => ( + + ))()} + {/* JSXEmptyExpr in action */} +
, + ]} + {...spreadChildren} + bold" }} + /> + +
+ + ); +} diff --git a/tests/rspack-test/configCases/parsing/jsx-enabled/rspack.config.js b/tests/rspack-test/configCases/parsing/jsx-enabled/rspack.config.js new file mode 100644 index 000000000000..b5aaaba6ed94 --- /dev/null +++ b/tests/rspack-test/configCases/parsing/jsx-enabled/rspack.config.js @@ -0,0 +1,108 @@ +const rspack = require("@rspack/core"); + +/** @type {import("@rspack/core").Configuration} */ +const baseConfig = { + mode: "production", + context: __dirname, + entry: "./index.jsx", + experiments: { + "outputModule": true + }, + externalsType: "module-import", + externals: { + 'react': 'react', + './App1': './App1', + './App2': './App2', + }, + output: { + module: true, + library: { + type: 'modern-module', + }, + }, + optimization: { + avoidEntryIife: true, + minimize: false, + }, + module: { + parser: { + javascript: { + jsx: true, + }, + 'javascript/auto': { + jsx: true, + }, + 'javascript/dynamic': { + jsx: true, + }, + 'javascript/esm': { + jsx: true, + }, + }, + rules: [ + { + test: /\.(jsx|tsx)$/, + loader: "builtin:swc-loader", + options: { + jsc: { + parser: { + syntax: "typescript", + tsx: true + }, + transform: { + react: { + runtime: "preserve" + } + }, + target: "esnext", + }, + } + } + ] + } +} + +/** @type {import("@rspack/core").Configuration[]} */ +module.exports = [ + { + ...baseConfig, + output: { + ...baseConfig.output, + filename: "bundle0.jsx" + } + }, + { + ...baseConfig, + output: { + ...baseConfig.output, + filename: "bundle1.jsx" + }, + optimization: { + ...baseConfig.optimization, + minimize: true, + minimizer: [ + new rspack.SwcJsMinimizerRspackPlugin({ + test: /\.jsx?$/, + minimizerOptions: { + mangle: false, + compress: { + defaults: false, + unused: true, + dead_code: true, + }, + format: { + comments: 'some', + preserve_annotations: true, + }, + } + })] + }, + }, + { + name: "test-output", + entry: "./test.js", + output: { + filename: "test.js" + } + } +] diff --git a/tests/rspack-test/configCases/parsing/jsx-enabled/test.config.js b/tests/rspack-test/configCases/parsing/jsx-enabled/test.config.js new file mode 100644 index 000000000000..f6c7ebc1a350 --- /dev/null +++ b/tests/rspack-test/configCases/parsing/jsx-enabled/test.config.js @@ -0,0 +1,6 @@ +module.exports = { + findBundle: function (i, options) { + return ["test.js"]; + } +}; + diff --git a/tests/rspack-test/configCases/parsing/jsx-enabled/test.js b/tests/rspack-test/configCases/parsing/jsx-enabled/test.js new file mode 100644 index 000000000000..331967b0767b --- /dev/null +++ b/tests/rspack-test/configCases/parsing/jsx-enabled/test.js @@ -0,0 +1,21 @@ +const fs = require("fs"); +const path = require("path"); + +it("should keep jsx in output when parser jsx is enabled", () => { + const bundle = fs.readFileSync(path.join(__dirname, "bundle0.jsx"), "utf-8"); + expect(bundle).toMatchFileSnapshot( + path.join(__SNAPSHOT__, "bundle0.jsx.txt") + ); +}); + +// TODO: There are some clear mangle errors, including but not limited to illegal component names like `t.App1`. +it ("should keep jsx in output when parser jsx is enabled (with minify)", () => { + const bundle = fs.readFileSync(path.join(__dirname, "bundle1.jsx"), "utf-8"); + expect(bundle).toContain(""); + expect(bundle).toContain(""); + expect(bundle).toContain("bold\"}}/>"); + expect(bundle).toContain(""); +}) diff --git a/tests/rspack-test/defaultsCases/default/base.js b/tests/rspack-test/defaultsCases/default/base.js index 96f62daa62b9..203121415fa2 100644 --- a/tests/rspack-test/defaultsCases/default/base.js +++ b/tests/rspack-test/defaultsCases/default/base.js @@ -200,6 +200,7 @@ module.exports = { importDynamic: true, importMeta: true, inlineConst: false, + jsx: false, requireAsExpression: true, requireDynamic: true, requireResolve: true,