Skip to content

Commit fe2ce39

Browse files
authored
fix: library module without export statement (#19411)
1 parent 4d6d380 commit fe2ce39

File tree

9 files changed

+172
-5
lines changed

9 files changed

+172
-5
lines changed

lib/WebpackOptionsApply.js

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ const WorkerPlugin = require("./dependencies/WorkerPlugin");
4848

4949
const InferAsyncModulesPlugin = require("./async-modules/InferAsyncModulesPlugin");
5050

51+
const FlagDependencyExportsPlugin = require("./FlagDependencyExportsPlugin");
5152
const JavascriptMetaInfoPlugin = require("./JavascriptMetaInfoPlugin");
5253
const DefaultStatsFactoryPlugin = require("./stats/DefaultStatsFactoryPlugin");
5354
const DefaultStatsPresetPlugin = require("./stats/DefaultStatsPresetPlugin");
@@ -236,9 +237,24 @@ class WebpackOptionsApply extends OptionsApply {
236237
(options.output.enabledLibraryTypes);
237238

238239
if (enabledLibraryTypes.length > 0) {
240+
let once = true;
239241
for (const type of enabledLibraryTypes) {
240242
const EnableLibraryPlugin = require("./library/EnableLibraryPlugin");
241-
new EnableLibraryPlugin(type).apply(compiler);
243+
new EnableLibraryPlugin(type, {
244+
// eslint-disable-next-line no-loop-func
245+
additionalApply: () => {
246+
if (!once) return;
247+
once = false;
248+
// We rely on `exportInfo` to generate the `export statement` in certain library bundles.
249+
// Therefore, we ignore the disabling of `optimization.providedExport` and continue to apply `FlagDependencyExportsPlugin`.
250+
if (
251+
["module", "commonjs-static", "modern-module"].includes(type) &&
252+
!options.optimization.providedExports
253+
) {
254+
new FlagDependencyExportsPlugin().apply(compiler);
255+
}
256+
}
257+
}).apply(compiler);
242258
}
243259
}
244260

@@ -458,7 +474,6 @@ class WebpackOptionsApply extends OptionsApply {
458474
).apply(compiler);
459475
}
460476
if (options.optimization.providedExports) {
461-
const FlagDependencyExportsPlugin = require("./FlagDependencyExportsPlugin");
462477
new FlagDependencyExportsPlugin().apply(compiler);
463478
}
464479
if (options.optimization.usedExports) {

lib/library/EnableLibraryPlugin.js

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@
1212
/** @type {WeakMap<Compiler, Set<LibraryType>>} */
1313
const enabledTypes = new WeakMap();
1414

15+
/**
16+
* @typedef {object} EnableLibraryPluginOptions
17+
* @property {() => void} [additionalApply] function that runs when applying the current plugin.
18+
*/
19+
1520
/**
1621
* @param {Compiler} compiler the compiler instance
1722
* @returns {Set<LibraryType>} enabled types
@@ -28,9 +33,13 @@ const getEnabledTypes = compiler => {
2833
class EnableLibraryPlugin {
2934
/**
3035
* @param {LibraryType} type library type that should be available
36+
* @param {EnableLibraryPluginOptions} options options of EnableLibraryPlugin
3137
*/
32-
constructor(type) {
38+
constructor(type, options = {}) {
39+
/** @type {LibraryType} */
3340
this.type = type;
41+
/** @type {EnableLibraryPluginOptions} */
42+
this.options = options;
3443
}
3544

3645
/**
@@ -67,13 +76,17 @@ class EnableLibraryPlugin {
6776
* @returns {void}
6877
*/
6978
apply(compiler) {
70-
const { type } = this;
79+
const { type, options } = this;
7180

7281
// Only enable once
7382
const enabled = getEnabledTypes(compiler);
7483
if (enabled.has(type)) return;
7584
enabled.add(type);
7685

86+
if (typeof options.additionalApply === "function") {
87+
options.additionalApply();
88+
}
89+
7790
if (typeof type === "string") {
7891
const enableExportProperty = () => {
7992
const ExportPropertyTemplatePlugin = require("./ExportPropertyLibraryPlugin");
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export const lib3 = 'commonjs-static'
2+
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export const lib2 = 'modern-module'
2+
3+
export default "null"
4+
5+
it("should compile and run", () => {
6+
// avoid `No tests exported by test case`
7+
expect(true).toBe(true)
8+
});
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import React from 'react';
2+
3+
const foo = "module"
4+
5+
export default 'module'
6+
export { React, foo }
7+
8+
it("should compile and run", () => {
9+
// avoid `No tests exported by test case`
10+
expect(true).toBe(true)
11+
});
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
it("should compile and run", () => {
2+
expect(libModule.default).toBe("module");
3+
expect(libModule.foo).toBe("module");
4+
expect(Boolean(libModule.React.version)).toBe(true);
5+
6+
expect(libModernModule.default).toBe("modern-module");
7+
8+
expect(libCommonjsStatic.default).toBe("commonjs-static");
9+
});
10+
11+
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
const supportsRequireInModule = require("../../../helpers/supportsRequireInModule");
2+
3+
module.exports = () => supportsRequireInModule();
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
var webpack = require("../../../../");
2+
3+
/** @type {import("../../../../").Configuration[]} */
4+
module.exports = [
5+
{
6+
entry: "./module.js",
7+
optimization: {
8+
providedExports: false
9+
},
10+
output: {
11+
library: {
12+
type: "module"
13+
}
14+
},
15+
experiments: {
16+
outputModule: true
17+
},
18+
externals: ["react"],
19+
externalsType: "module"
20+
},
21+
{
22+
entry: "./modern-module.js",
23+
optimization: {
24+
providedExports: false
25+
},
26+
output: {
27+
library: {
28+
type: "modern-module",
29+
export: ["lib2"]
30+
}
31+
},
32+
experiments: {
33+
outputModule: true
34+
}
35+
},
36+
{
37+
entry: "./commonjs-static.js",
38+
optimization: {
39+
providedExports: false
40+
},
41+
output: {
42+
library: {
43+
type: "commonjs-static"
44+
}
45+
}
46+
},
47+
{
48+
entry: "./run.js",
49+
plugins: [
50+
new webpack.BannerPlugin({
51+
raw: true,
52+
banner: `
53+
import lib1Default, { foo, React } from './bundle0.mjs';
54+
import { lib2 } from './bundle1.mjs';
55+
56+
import { createRequire } from 'module';
57+
const require = createRequire(import.meta.url);
58+
59+
const { lib3 } = require("./bundle2.js");
60+
61+
let libModule = { default: lib1Default, foo, React };
62+
let libModernModule = { default: lib2};
63+
let libCommonjsStatic = { default: lib3 };
64+
`
65+
}),
66+
{
67+
apply(compiler) {
68+
compiler.hooks.done.tap(
69+
{
70+
name: "disable-provided-export",
71+
stage: 100
72+
},
73+
() => {
74+
expect(
75+
compiler.hooks.compilation.taps.filter(
76+
tap => tap.name === "FlagDependencyExportsPlugin"
77+
).length
78+
).toBe(1);
79+
}
80+
);
81+
}
82+
}
83+
],
84+
output: {
85+
enabledLibraryTypes: ["module", "modern-module"],
86+
library: {
87+
type: "module"
88+
}
89+
},
90+
optimization: {
91+
providedExports: false
92+
},
93+
experiments: {
94+
outputModule: true
95+
}
96+
}
97+
];

types.d.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3946,8 +3946,9 @@ declare class EnableChunkLoadingPlugin {
39463946
static checkEnabled(compiler: Compiler, type: string): void;
39473947
}
39483948
declare class EnableLibraryPlugin {
3949-
constructor(type: string);
3949+
constructor(type: string, options?: EnableLibraryPluginOptions);
39503950
type: string;
3951+
options: EnableLibraryPluginOptions;
39513952

39523953
/**
39533954
* Apply the plugin
@@ -3956,6 +3957,12 @@ declare class EnableLibraryPlugin {
39563957
static setEnabled(compiler: Compiler, type: string): void;
39573958
static checkEnabled(compiler: Compiler, type: string): void;
39583959
}
3960+
declare interface EnableLibraryPluginOptions {
3961+
/**
3962+
* function that runs when applying the current plugin.
3963+
*/
3964+
additionalApply?: () => void;
3965+
}
39593966
declare class EnableWasmLoadingPlugin {
39603967
constructor(type: string);
39613968
type: string;

0 commit comments

Comments
 (0)