Skip to content

Commit 5c9d855

Browse files
fix(turbopack): external module shouldn't wrap by esm when type as global (#82374)
When use externalType: `global` or `script` under utoopack(turbopack only use esm or cjs external): like externalType is global , and the external package is react. The generate external module code like: ```ts 263: ((__turbopack_context__) => { "use strict"; const mod = globalThis["react"]; __turbopack_context__.n(mod); }), ``` The real function of runtime code `__turbopack_context__.n` is `exportNamespace`, its code as follows: ```ts module.exports = module.namespaceObject = namespace ``` And when we import the module as following: ```ts import react from "react"; console.log(react.version); ``` it will be bundled as: ```ts var __TURBOPACK__imported__module__263__ = __turbopack_context__.i(263); console.log(__TURBOPACK__imported__module__263__["default"]); ``` The `__turbopack_context__i` is esmImport, it will return the module when the module contains `namespaceObject` without `interopEsm`: ```ts function esmImport() { const module = getOrInstantiateModuleFromParent(id, this.m) // any ES module has to have `module.namespaceObject` defined. if (module.namespaceObject) return module.namespaceObject return interopEsm(); } ``` So the following case if we use a react umd module(which doesn't have a `default export`) as our external package, code `console.log(__TURBOPACK__imported__module__263__["default"]);` will output `undefined`(which webpack can output the right version). I just change export wrapper the externalType: global and script here(which now only consumed by utoopack), so the esmImport will execute `interopEsm` function here to make our code work fine. We test the case under utoopack and here is our pr: https://github.com/umijs/mako/pull/2097/files. --------- Co-authored-by: Niklas Mischkulnig <[email protected]>
1 parent 0a890da commit 5c9d855

File tree

4 files changed

+22
-3
lines changed

4 files changed

+22
-3
lines changed

turbopack/crates/turbopack-ecmascript/src/references/external_module.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ use crate::{
2828
},
2929
references::async_module::{AsyncModule, OptionAsyncModule},
3030
runtime_functions::{
31-
TURBOPACK_EXPORT_NAMESPACE, TURBOPACK_EXTERNAL_IMPORT, TURBOPACK_EXTERNAL_REQUIRE,
32-
TURBOPACK_LOAD_BY_URL,
31+
TURBOPACK_EXPORT_NAMESPACE, TURBOPACK_EXPORT_VALUE, TURBOPACK_EXTERNAL_IMPORT,
32+
TURBOPACK_EXTERNAL_REQUIRE, TURBOPACK_LOAD_BY_URL,
3333
},
3434
utils::StringifyJs,
3535
};
@@ -193,8 +193,12 @@ impl CachedExternalModule {
193193

194194
if self.external_type == CachedExternalType::CommonJs {
195195
writeln!(code, "module.exports = mod;")?;
196-
} else {
196+
} else if self.external_type == CachedExternalType::EcmaScriptViaImport
197+
|| self.external_type == CachedExternalType::EcmaScriptViaRequire
198+
{
197199
writeln!(code, "{TURBOPACK_EXPORT_NAMESPACE}(mod);")?;
200+
} else {
201+
writeln!(code, "{TURBOPACK_EXPORT_VALUE}(mod);")?;
198202
}
199203

200204
Ok(EcmascriptModuleContent {

turbopack/crates/turbopack-tests/js/jest-entry.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ function setupGlobals() {
1010
// @ts-ignore Property 'expect' does not exist on type 'typeof globalThis'
1111
globalThis.expect = expectMod.expect
1212

13+
// Set up global external values for testing
14+
// @ts-ignore Property 'testGlobalExternalValue' does not exist on type 'typeof globalThis'
15+
globalThis.testGlobalExternalValue = { bar: '11' }
16+
1317
// From https://github.com/webpack/webpack/blob/9fcaa243573005d6fdece9a3f8d89a0e8b399613/test/TestCases.template.js#L422
1418
globalThis.nsObj = function nsObj(obj) {
1519
Object.defineProperty(obj, Symbol.toStringTag, {

turbopack/crates/turbopack-tests/tests/execution.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,11 @@ async fn run_test_operation(prepared_test: ResolvedVc<PreparedTest>) -> Result<V
377377
ImportMapping::External(None, ExternalType::CommonJs, ExternalTraced::Untraced)
378378
.resolved_cell(),
379379
);
380+
import_map.insert_exact_alias(
381+
rcstr!("testGlobalExternalValue"),
382+
ImportMapping::External(None, ExternalType::Global, ExternalTraced::Untraced)
383+
.resolved_cell(),
384+
);
380385

381386
let remove_unused_exports = options.remove_unused_exports.unwrap_or(true);
382387

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import foo from 'testGlobalExternalValue'
2+
3+
it('should access global external values', () => {
4+
expect(foo).toEqual({ bar: '11' })
5+
expect(foo.bar).toBe('11')
6+
})

0 commit comments

Comments
 (0)