From bd51be44931982620d92e9dd0c90f1dda8272376 Mon Sep 17 00:00:00 2001 From: Deepak Prajapati Date: Fri, 3 Oct 2025 02:51:08 +0530 Subject: [PATCH 1/2] fix: resolve SystemJS default import undefined issue - Add conditional check for module.default property in SystemLibraryPlugin - Handle both ES6 modules (with default property) and SystemJS modules (without default property) - Fixes issue where default imports returned undefined instead of module object - Maintains backward compatibility with existing functionality - Resolves #19950 --- lib/library/SystemLibraryPlugin.js | 36 ++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/lib/library/SystemLibraryPlugin.js b/lib/library/SystemLibraryPlugin.js index 380962091..36526fa53 100644 --- a/lib/library/SystemLibraryPlugin.js +++ b/lib/library/SystemLibraryPlugin.js @@ -133,7 +133,20 @@ class SystemLibraryPlugin extends AbstractLibraryPlugin { chunk.runtime ); if (used) { - if (otherUnused || used !== exportInfo.name) { + if (used === "default" && exportInfo.name === "default") { + instructions.push( + Template.asString([ + "if (typeof module.default !== 'undefined') {", + Template.indent([ + `${external}.default = module.default;` + ]), + "} else {", + Template.indent([`${external} = module;`]), + "}" + ]) + ); + handledNames.push(exportInfo.name); + } else if (otherUnused || used !== exportInfo.name) { instructions.push( `${external}${propertyAccess([ used @@ -172,9 +185,24 @@ class SystemLibraryPlugin extends AbstractLibraryPlugin { } else { instructions.push( Template.asString([ - "Object.keys(module).forEach(function(key) {", - Template.indent([`${external}[key] = module[key];`]), - "});" + "if (typeof module.default !== 'undefined') {", + Template.indent([ + "Object.keys(module).forEach(function(key) {", + Template.indent([ + `${external}[key] = module[key];` + ]), + "});" + ]), + "} else {", + Template.indent([ + `${external} = module;`, + "Object.keys(module).forEach(function(key) {", + Template.indent([ + `${external}[key] = module[key];` + ]), + "});" + ]), + "}" ]) ); } From dd4769b5ff37821e082f86a8dca0bade99272ca0 Mon Sep 17 00:00:00 2001 From: Deepak Prajapati Date: Sat, 4 Oct 2025 23:39:13 +0530 Subject: [PATCH 2/2] test: add test case for SystemJS default import fix - Add comprehensive test case for system-default-import-fix - Test both scenarios: modules with and without default property - Verify default imports work correctly for SystemJS externals - Ensure backward compatibility with existing functionality --- .../target/system-default-import-fix/index.js | 19 ++++++++++ .../react-with-default.js | 26 ++++++++++++++ .../target/system-default-import-fix/react.js | 25 +++++++++++++ .../system-default-import-fix/test.config.js | 27 ++++++++++++++ .../target/system-default-import-fix/test.js | 36 +++++++++++++++++++ .../webpack.config.js | 15 ++++++++ 6 files changed, 148 insertions(+) create mode 100644 test/configCases/target/system-default-import-fix/index.js create mode 100644 test/configCases/target/system-default-import-fix/react-with-default.js create mode 100644 test/configCases/target/system-default-import-fix/react.js create mode 100644 test/configCases/target/system-default-import-fix/test.config.js create mode 100644 test/configCases/target/system-default-import-fix/test.js create mode 100644 test/configCases/target/system-default-import-fix/webpack.config.js diff --git a/test/configCases/target/system-default-import-fix/index.js b/test/configCases/target/system-default-import-fix/index.js new file mode 100644 index 000000000..83e9d9f92 --- /dev/null +++ b/test/configCases/target/system-default-import-fix/index.js @@ -0,0 +1,19 @@ +import React, { useEffect } from "react"; + +/* This test verifies that default imports work correctly with SystemJS externals + * when the external module doesn't have a default property (e.g., React) + */ + +it("should correctly handle default import from SystemJS external", function() { + // React should be the entire module object, not undefined + expect(React).toBeDefined(); + expect(typeof React).toBe("object"); + expect(React.Component).toBeDefined(); + expect(React.Fragment).toBeDefined(); + + // Named imports should still work + expect(typeof useEffect).toBe("function"); + + // The default import should not be undefined + expect(React).not.toBeUndefined(); +}); diff --git a/test/configCases/target/system-default-import-fix/react-with-default.js b/test/configCases/target/system-default-import-fix/react-with-default.js new file mode 100644 index 000000000..f8e36b12e --- /dev/null +++ b/test/configCases/target/system-default-import-fix/react-with-default.js @@ -0,0 +1,26 @@ +// Mock React module that HAS a default property +// This simulates ES6 modules with default exports +const React = { + Component: function Component() {}, + Fragment: Symbol("react.fragment"), + Profiler: Symbol("react.profiler"), + useEffect: function useEffect(callback, deps) { + return callback(); + }, + useState: function useState(initial) { + return [initial, function() {}]; + }, + createElement: function createElement(type, props, ...children) { + return { type, props, children }; + } +}; + +// Export with default property (ES6 module format) +module.exports = React; +module.exports.default = React; +module.exports.useEffect = React.useEffect; +module.exports.Component = React.Component; +module.exports.Fragment = React.Fragment; +module.exports.Profiler = React.Profiler; +module.exports.useState = React.useState; +module.exports.createElement = React.createElement; diff --git a/test/configCases/target/system-default-import-fix/react.js b/test/configCases/target/system-default-import-fix/react.js new file mode 100644 index 000000000..2b59fb098 --- /dev/null +++ b/test/configCases/target/system-default-import-fix/react.js @@ -0,0 +1,25 @@ +// Mock React module that doesn't have a default property +// This simulates how React is typically exported in SystemJS environments +const React = { + Component: function Component() {}, + Fragment: Symbol("react.fragment"), + Profiler: Symbol("react.profiler"), + useEffect: function useEffect(callback, deps) { + return callback(); + }, + useState: function useState(initial) { + return [initial, function() {}]; + }, + createElement: function createElement(type, props, ...children) { + return { type, props, children }; + } +}; + +// Export named exports (SystemJS style - no default property) +module.exports = React; +module.exports.useEffect = React.useEffect; +module.exports.Component = React.Component; +module.exports.Fragment = React.Fragment; +module.exports.Profiler = React.Profiler; +module.exports.useState = React.useState; +module.exports.createElement = React.createElement; diff --git a/test/configCases/target/system-default-import-fix/test.config.js b/test/configCases/target/system-default-import-fix/test.config.js new file mode 100644 index 000000000..7d86e2c73 --- /dev/null +++ b/test/configCases/target/system-default-import-fix/test.config.js @@ -0,0 +1,27 @@ +"use strict"; + +const path = require("path"); + +/** @type {import("../../../../").Configuration} */ +module.exports = { + entry: "./test.js", + output: { + path: path.resolve(__dirname, "dist"), + filename: "bundle.js", + libraryTarget: "system" + }, + externals: { + react: "react", + "react-with-default": "react-with-default" + }, + resolve: { + alias: { + react: path.resolve(__dirname, "react.js"), + "react-with-default": path.resolve(__dirname, "react-with-default.js") + } + }, + node: { + __dirname: false, + __filename: false + } +}; diff --git a/test/configCases/target/system-default-import-fix/test.js b/test/configCases/target/system-default-import-fix/test.js new file mode 100644 index 000000000..d01378be1 --- /dev/null +++ b/test/configCases/target/system-default-import-fix/test.js @@ -0,0 +1,36 @@ +import React, { useEffect } from "react"; +import ReactWithDefault, { useEffect as useEffectWithDefault } from "react-with-default"; + +/* This test verifies that default imports work correctly with SystemJS externals + * in both scenarios: + * 1. External module without default property (traditional SystemJS) + * 2. External module with default property (ES6 module format) + */ + +it("should correctly handle default import from SystemJS external without default property", function() { + // React should be the entire module object, not undefined + expect(React).toBeDefined(); + expect(typeof React).toBe("object"); + expect(React.Component).toBeDefined(); + expect(React.Fragment).toBeDefined(); + + // Named imports should still work + expect(typeof useEffect).toBe("function"); + + // The default import should not be undefined + expect(React).not.toBeUndefined(); +}); + +it("should correctly handle default import from SystemJS external with default property", function() { + // ReactWithDefault should be the default property value + expect(ReactWithDefault).toBeDefined(); + expect(typeof ReactWithDefault).toBe("object"); + expect(ReactWithDefault.Component).toBeDefined(); + expect(ReactWithDefault.Fragment).toBeDefined(); + + // Named imports should still work + expect(typeof useEffectWithDefault).toBe("function"); + + // The default import should not be undefined + expect(ReactWithDefault).not.toBeUndefined(); +}); diff --git a/test/configCases/target/system-default-import-fix/webpack.config.js b/test/configCases/target/system-default-import-fix/webpack.config.js new file mode 100644 index 000000000..2e66a663c --- /dev/null +++ b/test/configCases/target/system-default-import-fix/webpack.config.js @@ -0,0 +1,15 @@ +"use strict"; + +/** @type {import("../../../../").Configuration} */ +module.exports = { + output: { + libraryTarget: "system" + }, + externals: { + react: "react" + }, + node: { + __dirname: false, + __filename: false + } +};