Skip to content

Commit 0d2faa0

Browse files
authored
Merge pull request webpack#8460 from webpack/refactor/node_polyfills
Do not polyfill node bindings by default
2 parents 9023d21 + 3c50dba commit 0d2faa0

File tree

32 files changed

+188
-896
lines changed

32 files changed

+188
-896
lines changed

buildin/global.js

Lines changed: 0 additions & 20 deletions
This file was deleted.

declarations/WebpackOptions.d.ts

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -764,10 +764,6 @@ export interface WebpackPluginInstance {
764764
* via the `definition` "NodeOptions".
765765
*/
766766
export interface NodeOptions {
767-
/**
768-
* Include a polyfill for the 'Buffer' variable
769-
*/
770-
Buffer?: false | true | "mock";
771767
/**
772768
* Include a polyfill for the '__dirname' variable
773769
*/
@@ -776,22 +772,10 @@ export interface NodeOptions {
776772
* Include a polyfill for the '__filename' variable
777773
*/
778774
__filename?: false | true | "mock";
779-
/**
780-
* Include a polyfill for the 'console' variable
781-
*/
782-
console?: false | true | "mock";
783775
/**
784776
* Include a polyfill for the 'global' variable
785777
*/
786778
global?: boolean;
787-
/**
788-
* Include a polyfill for the 'process' variable
789-
*/
790-
process?: false | true | "mock";
791-
/**
792-
* Include a polyfill for the node.js module
793-
*/
794-
[k: string]: false | true | "mock" | "empty";
795779
}
796780
/**
797781
* Enables/Disables integrated optimizations

lib/ModuleNotFoundError.js

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,74 @@ const WebpackError = require("./WebpackError");
99

1010
/** @typedef {import("./Module")} Module */
1111

12+
const previouslyPolyfilledBuiltinModules = {
13+
assert: "assert",
14+
buffer: "buffer",
15+
console: "console-browserify",
16+
constants: "constants-browserify",
17+
crypto: "crypto-browserify",
18+
___domain: "___domain-browser",
19+
events: "events",
20+
http: "stream-http",
21+
https: "https-browserify",
22+
os: "os-browserify/browser",
23+
path: "path-browserify",
24+
punycode: "punycode",
25+
process: "process/browser",
26+
querystring: "querystring-es3",
27+
stream: "stream-browserify",
28+
_stream_duplex: "readable-stream/duplex",
29+
_stream_passthrough: "readable-stream/passthrough",
30+
_stream_readable: "readable-stream/readable",
31+
_stream_transform: "readable-stream/transform",
32+
_stream_writable: "readable-stream/writable",
33+
string_decoder: "string_decoder",
34+
sys: "util",
35+
timers: "timers-browserify",
36+
tty: "tty-browserify",
37+
url: "url",
38+
util: "util",
39+
vm: "vm-browserify",
40+
zlib: "browserify-zlib"
41+
};
42+
1243
class ModuleNotFoundError extends WebpackError {
1344
/**
1445
* @param {Module} module module tied to dependency
1546
* @param {Error&any} err error thrown
1647
* @param {TODO} loc ___location of dependency
1748
*/
1849
constructor(module, err, loc) {
19-
super("Module not found: " + err);
50+
let message = `Module not found: ${err.toString()}`;
51+
52+
// TODO remove in webpack 6
53+
const match = err.message.match(/Can't resolve '([^']+)'/);
54+
if (match) {
55+
const request = match[1];
56+
const alias = previouslyPolyfilledBuiltinModules[request];
57+
if (alias) {
58+
const pathIndex = alias.indexOf("/");
59+
const dependency = pathIndex > 0 ? alias.slice(0, pathIndex) : alias;
60+
message +=
61+
"\n\n" +
62+
"BREAKING CHANGE: " +
63+
"webpack < 5 used to include polyfills for node.js core modules by default.\n" +
64+
"This is no longer the case. Verify if you need these module and configure a polyfill for it.\n\n";
65+
if (request !== alias) {
66+
message +=
67+
"If you want to include a polyfill, you need to:\n" +
68+
`\t- add an alias 'resolve.alias: { "${request}": "${alias}" }'\n` +
69+
`\t- install '${dependency}'\n`;
70+
} else {
71+
message += `If you want to include a polyfill, you need to install '${dependency}'.\n`;
72+
}
73+
message +=
74+
"If you don't want to include a polyfill, you can use an empty module like this:\n" +
75+
`\tresolve.alias: { "${request}": false }`;
76+
}
77+
}
78+
79+
super(message);
2080

2181
this.name = "ModuleNotFoundError";
2282
this.details = err.details;

lib/RuntimeGlobals.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,11 @@ exports.startup = "__webpack_require__.x";
125125
*/
126126
exports.interceptModuleExecution = "__webpack_require__.i";
127127

128+
/**
129+
* the global object
130+
*/
131+
exports.global = "__webpack_require__.g";
132+
128133
/**
129134
* the filename of the HMR manifest
130135
*/

lib/RuntimePlugin.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ const DefinePropertyGetterRuntimeModule = require("./runtime/DefinePropertyGette
1212
const EnsureChunkRuntimeModule = require("./runtime/EnsureChunkRuntimeModule");
1313
const GetChunkFilenameRuntimeModule = require("./runtime/GetChunkFilenameRuntimeModule");
1414
const GetMainFilenameRuntimeModule = require("./runtime/GetMainFilenameRuntimeModule");
15+
const GlobalRuntimeModule = require("./runtime/GlobalRuntimeModule");
1516
const MakeNamespaceObjectRuntimeModule = require("./runtime/MakeNamespaceObjectRuntimeModule");
1617
const PublicPathRuntimeModule = require("./runtime/PublicPathRuntimeModule");
1718

@@ -34,6 +35,7 @@ const DEPENDENCIES = {
3435
[RuntimeGlobals.ensureChunk]: [RuntimeGlobals.require],
3536
[RuntimeGlobals.entryModuleId]: [RuntimeGlobals.require],
3637
[RuntimeGlobals.getFullHash]: [RuntimeGlobals.require],
38+
[RuntimeGlobals.global]: [RuntimeGlobals.require],
3739
[RuntimeGlobals.makeNamespaceObject]: [RuntimeGlobals.require],
3840
[RuntimeGlobals.moduleCache]: [RuntimeGlobals.require],
3941
[RuntimeGlobals.moduleFactories]: [RuntimeGlobals.require],
@@ -103,6 +105,12 @@ class RuntimePlugin {
103105
);
104106
return true;
105107
});
108+
compilation.hooks.runtimeRequirementInTree
109+
.for(RuntimeGlobals.global)
110+
.tap("RuntimePlugin", chunk => {
111+
compilation.addRuntimeModule(chunk, new GlobalRuntimeModule());
112+
return true;
113+
});
106114
compilation.hooks.runtimeRequirementInTree
107115
.for(RuntimeGlobals.getChunkScriptFilename)
108116
.tap("RuntimePlugin", (chunk, set) => {

lib/WebpackOptionsDefaulter.js

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -203,11 +203,7 @@ class WebpackOptionsDefaulter extends OptionsDefaulter {
203203
return Object.assign({}, value);
204204
}
205205
});
206-
this.set("node.console", false);
207-
this.set("node.process", true);
208-
this.set("node.global", true);
209-
this.set("node.Buffer", true);
210-
this.set("node.setImmediate", true);
206+
this.set("node.global", false);
211207
this.set("node.__filename", "mock");
212208
this.set("node.__dirname", "mock");
213209

lib/node/NodeSourcePlugin.js

Lines changed: 12 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,16 @@
55

66
"use strict";
77

8-
const AliasPlugin = require("enhanced-resolve/lib/AliasPlugin");
9-
const nodeLibsBrowser = require("node-libs-browser");
10-
const { getModulePath } = require("../JavascriptParserHelpers");
11-
const ProvidedDependency = require("../dependencies/ProvidedDependency");
8+
const RuntimeGlobals = require("../RuntimeGlobals");
9+
const ConstDependency = require("../dependencies/ConstDependency");
1210

11+
/** @typedef {import("../../declarations/WebpackOptions").NodeOptions} NodeOptions */
1312
/** @typedef {import("../Compiler")} Compiler */
1413

1514
module.exports = class NodeSourcePlugin {
15+
/**
16+
* @param {NodeOptions | false} options plugin options
17+
*/
1618
constructor(options) {
1719
this.options = options;
1820
}
@@ -28,112 +30,32 @@ module.exports = class NodeSourcePlugin {
2830
return;
2931
}
3032

31-
const getPathToModule = (module, type) => {
32-
if (type === true || (type === undefined && nodeLibsBrowser[module])) {
33-
if (!nodeLibsBrowser[module]) {
34-
throw new Error(
35-
`No browser version for node.js core module ${module} available`
36-
);
37-
}
38-
return nodeLibsBrowser[module];
39-
} else if (type === "mock") {
40-
return require.resolve(`node-libs-browser/mock/${module}`);
41-
} else if (type === "empty") {
42-
return require.resolve("node-libs-browser/mock/empty");
43-
} else {
44-
return module;
45-
}
46-
};
47-
48-
const addExpression = (parser, module, identifier, path, type) => {
49-
parser.hooks.expression.for(identifier).tap("NodeSourcePlugin", expr => {
50-
if (
51-
parser.state.module &&
52-
parser.state.module.resource === getPathToModule(module, type)
53-
) {
54-
return;
55-
}
56-
const dep = new ProvidedDependency(
57-
getModulePath(
58-
parser.state.module.context,
59-
getPathToModule(module, type)
60-
),
61-
identifier,
62-
path,
63-
expr.range
64-
);
65-
dep.loc = expr.loc;
66-
parser.state.module.addDependency(dep);
67-
return true;
68-
});
69-
};
70-
7133
compiler.hooks.compilation.tap(
7234
"NodeSourcePlugin",
7335
(compilation, { normalModuleFactory }) => {
74-
compilation.dependencyFactories.set(
75-
ProvidedDependency,
76-
normalModuleFactory
77-
);
78-
compilation.dependencyTemplates.set(
79-
ProvidedDependency,
80-
new ProvidedDependency.Template()
81-
);
82-
8336
const handler = (parser, parserOptions) => {
8437
if (parserOptions.node === false) return;
8538

8639
let localOptions = options;
8740
if (parserOptions.node) {
8841
localOptions = Object.assign({}, localOptions, parserOptions.node);
8942
}
43+
9044
if (localOptions.global) {
9145
parser.hooks.expression
9246
.for("global")
9347
.tap("NodeSourcePlugin", expr => {
94-
const dep = new ProvidedDependency(
95-
getModulePath(
96-
parser.state.module.context,
97-
require.resolve("../../buildin/global")
98-
),
99-
"global",
100-
null,
101-
expr.range
48+
const dep = new ConstDependency(
49+
RuntimeGlobals.global,
50+
expr.range,
51+
[RuntimeGlobals.global]
10252
);
10353
dep.loc = expr.loc;
10454
parser.state.module.addDependency(dep);
10555
});
10656
}
107-
if (localOptions.process) {
108-
const processType = localOptions.process;
109-
addExpression(parser, "process", "process", null, processType);
110-
}
111-
if (localOptions.console) {
112-
const consoleType = localOptions.console;
113-
addExpression(parser, "console", "console", null, consoleType);
114-
}
115-
const bufferType = localOptions.Buffer;
116-
if (bufferType) {
117-
addExpression(parser, "buffer", "Buffer", ["Buffer"], bufferType);
118-
}
119-
if (localOptions.setImmediate) {
120-
const setImmediateType = localOptions.setImmediate;
121-
addExpression(
122-
parser,
123-
"timers",
124-
"setImmediate",
125-
["setImmediate"],
126-
setImmediateType
127-
);
128-
addExpression(
129-
parser,
130-
"timers",
131-
"clearImmediate",
132-
["clearImmediate"],
133-
setImmediateType
134-
);
135-
}
13657
};
58+
13759
normalModuleFactory.hooks.parser
13860
.for("javascript/auto")
13961
.tap("NodeSourcePlugin", handler);
@@ -145,24 +67,5 @@ module.exports = class NodeSourcePlugin {
14567
.tap("NodeSourcePlugin", handler);
14668
}
14769
);
148-
compiler.hooks.afterResolvers.tap("NodeSourcePlugin", compiler => {
149-
for (const lib of Object.keys(nodeLibsBrowser)) {
150-
if (options[lib] !== false) {
151-
compiler.resolverFactory.hooks.resolver
152-
.for("normal")
153-
.tap("NodeSourcePlugin", resolver => {
154-
new AliasPlugin(
155-
"described-resolve",
156-
{
157-
name: lib,
158-
onlyModule: true,
159-
alias: getPathToModule(lib, options[lib])
160-
},
161-
"resolve"
162-
).apply(resolver);
163-
});
164-
}
165-
}
166-
});
16770
}
16871
};

lib/runtime/GlobalRuntimeModule.js

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
MIT License http://www.opensource.org/licenses/mit-license.php
3+
*/
4+
5+
"use strict";
6+
7+
const RuntimeGlobals = require("../RuntimeGlobals");
8+
const RuntimeModule = require("../RuntimeModule");
9+
const Template = require("../Template");
10+
11+
class GlobalRuntimeModule extends RuntimeModule {
12+
constructor() {
13+
super("global");
14+
}
15+
16+
/**
17+
* @returns {string} runtime code
18+
*/
19+
generate() {
20+
return Template.asString([
21+
`${RuntimeGlobals.global} = (function() {`,
22+
Template.indent([
23+
// This works in non-strict mode
24+
"var g = (function() { return this; })();",
25+
"try {",
26+
Template.indent(
27+
// This works if eval is allowed (see CSP)
28+
"g = g || new Function('return this')();"
29+
),
30+
"} catch (e) {",
31+
Template.indent(
32+
// This works if the window reference is available
33+
"if (typeof window === 'object') g = window;"
34+
),
35+
"}",
36+
// g can still be `undefined`, but nothing to do about it...
37+
// We return `undefined`, instead of nothing here, so it's
38+
// easier to handle this case:
39+
// if (!global) { … }
40+
"return g;"
41+
]),
42+
"})();"
43+
]);
44+
}
45+
}
46+
47+
module.exports = GlobalRuntimeModule;

0 commit comments

Comments
 (0)