diff --git a/crates/pack-core/src/client/context.rs b/crates/pack-core/src/client/context.rs index dc610099a3..4e7dc09341 100644 --- a/crates/pack-core/src/client/context.rs +++ b/crates/pack-core/src/client/context.rs @@ -278,15 +278,9 @@ pub async fn get_client_module_options_context( } else { false }; - let jsx_transform_options = get_jsx_transform_options( - project_path.clone(), - mode, - false, - config, - enable_react_refresh, - ) - .to_resolved() - .await?; + let jsx_transform_options = get_jsx_transform_options(mode, config, enable_react_refresh) + .to_resolved() + .await?; let mut loader_conditions = BTreeSet::new(); loader_conditions.insert(WebpackLoaderBuiltinCondition::Browser); diff --git a/crates/pack-core/src/config.rs b/crates/pack-core/src/config.rs index 382c533059..773b81e372 100644 --- a/crates/pack-core/src/config.rs +++ b/crates/pack-core/src/config.rs @@ -249,11 +249,21 @@ pub enum ReactRuntime { Classic, } +impl ReactRuntime { + pub fn as_str(&self) -> &'static str { + match self { + ReactRuntime::Automatic => "automatic", + ReactRuntime::Classic => "classic", + } + } +} + #[turbo_tasks::value(eq = "manual")] #[derive(Clone, Debug, PartialEq, Default, Deserialize, OperationValue)] #[serde(rename_all = "camelCase")] pub struct ReactConfig { pub runtime: Option, + pub import_source: Option, } #[turbo_tasks::value(eq = "manual")] diff --git a/crates/pack-core/src/transform_options.rs b/crates/pack-core/src/transform_options.rs index 7d674bba4f..8bb7fc20e0 100644 --- a/crates/pack-core/src/transform_options.rs +++ b/crates/pack-core/src/transform_options.rs @@ -11,10 +11,7 @@ use turbopack_core::{ }; use turbopack_ecmascript::typescript::resolve::{read_from_tsconfigs, read_tsconfigs, tsconfig}; -use crate::{ - config::{Config, ReactRuntime}, - mode::Mode, -}; +use crate::{config::Config, mode::Mode}; async fn get_typescript_options( project_path: FileSystemPath, @@ -117,52 +114,22 @@ pub async fn get_decorators_transform_options( #[turbo_tasks::function] pub async fn get_jsx_transform_options( - project_path: FileSystemPath, mode: Vc, - is_rsc_context: bool, config: Vc, enable_react_refresh: bool, ) -> Result> { - let tsconfig = get_typescript_options(project_path.clone()).await?; - let is_emotion_enabled = config.styles().await?.emotion.is_some(); let react_config = config.react().await?; let react_transform_options = JsxTransformOptions { development: mode.await?.is_react_development(), - // https://github.com/vercel/next.js/blob/3dc2c1c7f8441cdee31da9f7e0986d654c7fd2e7/packages/next/src/build/swc/options.ts#L112 - // This'll be ignored if ts|jsconfig explicitly specifies importSource - import_source: if is_emotion_enabled && !is_rsc_context { - Some("@emotion/react".into()) - } else { - None - }, - runtime: react_config.runtime.as_ref().map(|runtime| match runtime { - ReactRuntime::Automatic => "automatic".into(), - ReactRuntime::Classic => "classic".into(), - }), + import_source: react_config.import_source.clone().or(Some("react".into())), + runtime: react_config + .runtime + .as_ref() + .map(|r| r.as_str().into()) + .or(Some("automatic".into())), react_refresh: enable_react_refresh, }; - let react_transform_options = if let Some(tsconfig) = tsconfig { - read_from_tsconfigs(&tsconfig, |json, _| { - let jsx_import_source = json["compilerOptions"]["jsxImportSource"] - .as_str() - .map(|s| s.into()); - - Some(JsxTransformOptions { - import_source: if jsx_import_source.is_some() { - jsx_import_source - } else { - react_transform_options.import_source.clone() - }, - ..react_transform_options.clone() - }) - }) - .await? - .unwrap_or_default() - } else { - react_transform_options - }; - Ok(react_transform_options.cell()) } diff --git a/crates/pack-tests/tests/snapshot/basic/foreign_jsx_transform/config.json b/crates/pack-tests/tests/snapshot/basic/foreign_jsx_transform/config.json index 7face3a7db..1d069d2d2f 100644 --- a/crates/pack-tests/tests/snapshot/basic/foreign_jsx_transform/config.json +++ b/crates/pack-tests/tests/snapshot/basic/foreign_jsx_transform/config.json @@ -2,7 +2,7 @@ "config": { "entry": [ { - "import": "input/index.js", + "import": "input/index.jsx", "name": "main" } ], diff --git a/crates/pack-tests/tests/snapshot/basic/foreign_jsx_transform/input/index.js b/crates/pack-tests/tests/snapshot/basic/foreign_jsx_transform/input/index.js deleted file mode 100644 index 8219bf8161..0000000000 --- a/crates/pack-tests/tests/snapshot/basic/foreign_jsx_transform/input/index.js +++ /dev/null @@ -1 +0,0 @@ -import 'foreign-jsx-transform'; \ No newline at end of file diff --git a/crates/pack-tests/tests/snapshot/basic/foreign_jsx_transform/input/index.jsx b/crates/pack-tests/tests/snapshot/basic/foreign_jsx_transform/input/index.jsx new file mode 100644 index 0000000000..7b64ebc9fa --- /dev/null +++ b/crates/pack-tests/tests/snapshot/basic/foreign_jsx_transform/input/index.jsx @@ -0,0 +1,8 @@ +import React from 'react'; +import 'foreign-jsx-transform'; + +const App = () => { + return
+} + +export default App; \ No newline at end of file diff --git a/crates/pack-tests/tests/snapshot/basic/foreign_jsx_transform/issues/Export-default-doesn-t-exist-in-target-module-421f54.txt b/crates/pack-tests/tests/snapshot/basic/foreign_jsx_transform/issues/Export-default-doesn-t-exist-in-target-module-421f54.txt new file mode 100644 index 0000000000..defd9e3ef3 --- /dev/null +++ b/crates/pack-tests/tests/snapshot/basic/foreign_jsx_transform/issues/Export-default-doesn-t-exist-in-target-module-421f54.txt @@ -0,0 +1,20 @@ +warning - [bindings] /basic/foreign_jsx_transform/input/index.jsx:1:0 Export default doesn't exist in target module + + + v------------------------v + 1 + import React from 'react'; + + ^------------------------^ + 2 | import 'foreign-jsx-transform'; + 3 | + 4 | const App = () => { + 5 | return
+ + The export default was not found in module [project]/node_modules/react/index.js [client] (ecmascript). + + Did you mean to import jsx? + + All exports of the module are statically known (It doesn't have dynamic exports). So it's known statically that the requested export doesn't exist. + + + | These are the exports of the module: + | jsx + | \ No newline at end of file diff --git a/crates/pack-tests/tests/snapshot/basic/foreign_jsx_transform/output/_project___e660a1cd.js b/crates/pack-tests/tests/snapshot/basic/foreign_jsx_transform/output/_project___e660a1cd.js new file mode 100644 index 0000000000..d12e3a5f43 --- /dev/null +++ b/crates/pack-tests/tests/snapshot/basic/foreign_jsx_transform/output/_project___e660a1cd.js @@ -0,0 +1,36 @@ +(globalThis["TURBOPACK"] || (globalThis["TURBOPACK"] = [])).push([typeof document === "object" ? document.currentScript : undefined, +88, ((__turbopack_context__) => { +"use strict"; + +function jsx() { + return 'purposefully empty stub for react/index.js'; +} +__turbopack_context__.s([]); +}), +86, ((__turbopack_context__) => { +"use strict"; + +/** @jsx jsx */ var a = 1; +var __TURBOPACK__default__export__ = a; +__turbopack_context__.s([]); +}), +97, ((__turbopack_context__) => { +"use strict"; + +var __TURBOPACK__imported__module__88__ = __turbopack_context__.i(88); +var __TURBOPACK__imported__module__86__ = __turbopack_context__.i(86); +; +; +const App = ()=>{ + return /*#__PURE__*/ __TURBOPACK__imported__module__88__["default"].createElement("div", null); +}; +var __TURBOPACK__default__export__ = App; +__turbopack_context__.s([ + "default", + 0, + __TURBOPACK__default__export__ +]); +}), +]); + +//# sourceMappingURL=_project___e660a1cd.js.map \ No newline at end of file diff --git a/crates/pack-tests/tests/snapshot/basic/foreign_jsx_transform/output/_project___e660a1cd.js.map b/crates/pack-tests/tests/snapshot/basic/foreign_jsx_transform/output/_project___e660a1cd.js.map new file mode 100644 index 0000000000..3f6579e224 --- /dev/null +++ b/crates/pack-tests/tests/snapshot/basic/foreign_jsx_transform/output/_project___e660a1cd.js.map @@ -0,0 +1,8 @@ +{ + "version": 3, + "sources": [], + "sections": [ + {"offset": {"line": 4, "column": 0}, "map": {"version":3,"sources":["turbopack:///[project]/node_modules/react/index.js"],"sourcesContent":["export function jsx() {\n return 'purposefully empty stub for react/index.js'\n}\n"],"names":["jsx"],"mappings":"AAAO,SAASA;IACd,OAAO;AACT","ignoreList":[0]}}, + {"offset": {"line": 12, "column": 0}, "map": {"version":3,"sources":["turbopack:///[project]/basic/foreign_jsx_transform/node_modules/foreign-jsx-transform/index.js"],"sourcesContent":["/** @jsx jsx */\nvar a = 1;\nexport default a;"],"names":["a"],"mappings":"AAAA,aAAa,GACb,IAAIA,IAAI;qCACOA","ignoreList":[0]}}, + {"offset": {"line": 19, "column": 0}, "map": {"version":3,"sources":["turbopack:///[project]/basic/foreign_jsx_transform/input/index.jsx"],"sourcesContent":["import React from 'react';\nimport 'foreign-jsx-transform';\n\nconst App = () => {\n return
\n}\n\nexport default App;"],"names":["App"],"mappings":"AAAA;AACA;;;AAEA,MAAMA,MAAM;IACR,qBAAO,6DAAC;AACZ;qCAEeA"}}] +} \ No newline at end of file diff --git a/crates/pack-tests/tests/snapshot/basic/foreign_jsx_transform/output/_project__basic_foreign_jsx_transform_9ec7bd5f.js b/crates/pack-tests/tests/snapshot/basic/foreign_jsx_transform/output/_project__basic_foreign_jsx_transform_9ec7bd5f.js deleted file mode 100644 index 996df96dea..0000000000 --- a/crates/pack-tests/tests/snapshot/basic/foreign_jsx_transform/output/_project__basic_foreign_jsx_transform_9ec7bd5f.js +++ /dev/null @@ -1,18 +0,0 @@ -(globalThis["TURBOPACK"] || (globalThis["TURBOPACK"] = [])).push([typeof document === "object" ? document.currentScript : undefined, -86, ((__turbopack_context__) => { -"use strict"; - -/** @jsx jsx */ var a = 1; -var __TURBOPACK__default__export__ = a; -__turbopack_context__.s([]); -}), -46, ((__turbopack_context__) => { -"use strict"; - -var __TURBOPACK__imported__module__86__ = __turbopack_context__.i(86); -; -__turbopack_context__.s([]); -}), -]); - -//# sourceMappingURL=_project__basic_foreign_jsx_transform_9ec7bd5f.js.map \ No newline at end of file diff --git a/crates/pack-tests/tests/snapshot/basic/foreign_jsx_transform/output/_project__basic_foreign_jsx_transform_9ec7bd5f.js.map b/crates/pack-tests/tests/snapshot/basic/foreign_jsx_transform/output/_project__basic_foreign_jsx_transform_9ec7bd5f.js.map deleted file mode 100644 index 8b905c0467..0000000000 --- a/crates/pack-tests/tests/snapshot/basic/foreign_jsx_transform/output/_project__basic_foreign_jsx_transform_9ec7bd5f.js.map +++ /dev/null @@ -1,7 +0,0 @@ -{ - "version": 3, - "sources": [], - "sections": [ - {"offset": {"line": 4, "column": 0}, "map": {"version":3,"sources":["turbopack:///[project]/basic/foreign_jsx_transform/node_modules/foreign-jsx-transform/index.js"],"sourcesContent":["/** @jsx jsx */\nvar a = 1;\nexport default a;"],"names":["a"],"mappings":"AAAA,aAAa,GACb,IAAIA,IAAI;qCACOA","ignoreList":[0]}}, - {"offset": {"line": 11, "column": 0}, "map": {"version":3,"sources":["turbopack:///[project]/basic/foreign_jsx_transform/input/index.js"],"sourcesContent":["import 'foreign-jsx-transform';"],"names":[],"mappings":"AAAA"}}] -} \ No newline at end of file diff --git a/crates/pack-tests/tests/snapshot/basic/foreign_jsx_transform/output/main.js b/crates/pack-tests/tests/snapshot/basic/foreign_jsx_transform/output/main.js index 1c75db9027..d2d7797f80 100644 --- a/crates/pack-tests/tests/snapshot/basic/foreign_jsx_transform/output/main.js +++ b/crates/pack-tests/tests/snapshot/basic/foreign_jsx_transform/output/main.js @@ -1,5 +1,5 @@ (globalThis["TURBOPACK"] || (globalThis["TURBOPACK"] = [])).push([ typeof document === "object" ? document.currentScript : undefined, - {"otherChunks":["_project__basic_foreign_jsx_transform_9ec7bd5f.js"],"runtimeModuleIds":[46]} + {"otherChunks":["_project___e660a1cd.js"],"runtimeModuleIds":[97]} ]); // Dummy runtime diff --git a/packages/pack-shared/src/config.ts b/packages/pack-shared/src/config.ts index dec3637eca..711e820dcc 100644 --- a/packages/pack-shared/src/config.ts +++ b/packages/pack-shared/src/config.ts @@ -191,6 +191,7 @@ export interface ConfigComplete { }; react?: { runtime?: "automatic" | "classic"; + importSource?: string; }; stats?: boolean; persistentCaching?: boolean;