Skip to content

Commit 562f17a

Browse files
authored
Merge pull request #14212 from webpack/fix-14210
add options to warn on using Node.js features
2 parents 3e3b528 + 5592f66 commit 562f17a

File tree

14 files changed

+268
-41
lines changed

14 files changed

+268
-41
lines changed

declarations/WebpackOptions.d.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1106,6 +1106,10 @@ export interface Experiments {
11061106
* Build http(s): urls using a lockfile and resource content cache.
11071107
*/
11081108
buildHttp?: boolean | HttpUriOptions;
1109+
/**
1110+
* Apply defaults of next major version.
1111+
*/
1112+
futureDefaults?: boolean;
11091113
/**
11101114
* Enable module and chunk layers.
11111115
*/
@@ -1629,15 +1633,15 @@ export interface NodeOptions {
16291633
/**
16301634
* Include a polyfill for the '__dirname' variable.
16311635
*/
1632-
__dirname?: false | true | "mock" | "eval-only";
1636+
__dirname?: false | true | "warn-mock" | "mock" | "eval-only";
16331637
/**
16341638
* Include a polyfill for the '__filename' variable.
16351639
*/
1636-
__filename?: false | true | "mock" | "eval-only";
1640+
__filename?: false | true | "warn-mock" | "mock" | "eval-only";
16371641
/**
16381642
* Include a polyfill for the 'global' variable.
16391643
*/
1640-
global?: boolean;
1644+
global?: false | true | "warn";
16411645
}
16421646
/**
16431647
* Enables/Disables integrated optimizations.

lib/NodeStuffInWebError.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
MIT License http://www.opensource.org/licenses/mit-license.php
3+
Author Ivan Kopeykin @vankop
4+
*/
5+
6+
"use strict";
7+
8+
const WebpackError = require("./WebpackError");
9+
const makeSerializable = require("./util/makeSerializable");
10+
11+
/** @typedef {import("./Dependency").DependencyLocation} DependencyLocation */
12+
13+
class NodeStuffInWebError extends WebpackError {
14+
/**
15+
* @param {DependencyLocation} loc loc
16+
* @param {string} expression expression
17+
* @param {string} description description
18+
*/
19+
constructor(loc, expression, description) {
20+
super(
21+
`${JSON.stringify(
22+
expression
23+
)} has been used, it will be undefined in next major version.
24+
${description}`
25+
);
26+
27+
this.name = "NodeStuffInWebError";
28+
this.loc = loc;
29+
}
30+
}
31+
32+
makeSerializable(NodeStuffInWebError, "webpack/lib/NodeStuffInWebError");
33+
34+
module.exports = NodeStuffInWebError;

lib/NodeStuffPlugin.js

Lines changed: 59 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
"use strict";
77

8+
const NodeStuffInWebError = require("./NodeStuffInWebError");
89
const RuntimeGlobals = require("./RuntimeGlobals");
910
const CachedConstDependency = require("./dependencies/CachedConstDependency");
1011
const ConstDependency = require("./dependencies/ConstDependency");
@@ -44,7 +45,8 @@ class NodeStuffPlugin {
4445
localOptions = { ...localOptions, ...parserOptions.node };
4546
}
4647

47-
if (localOptions.global) {
48+
if (localOptions.global !== false) {
49+
const withWarning = localOptions.global === "warn";
4850
parser.hooks.expression
4951
.for("global")
5052
.tap("NodeStuffPlugin", expr => {
@@ -55,10 +57,21 @@ class NodeStuffPlugin {
5557
);
5658
dep.loc = expr.loc;
5759
parser.state.module.addPresentationalDependency(dep);
60+
61+
// TODO webpack 6 remove
62+
if (withWarning) {
63+
parser.state.module.addWarning(
64+
new NodeStuffInWebError(
65+
dep.loc,
66+
"global",
67+
"The global namespace object is Node.js feature and doesn't present in browser."
68+
)
69+
);
70+
}
5871
});
5972
}
6073

61-
const setModuleConstant = (expressionName, fn) => {
74+
const setModuleConstant = (expressionName, fn, warning) => {
6275
parser.hooks.expression
6376
.for(expressionName)
6477
.tap("NodeStuffPlugin", expr => {
@@ -69,22 +82,41 @@ class NodeStuffPlugin {
6982
);
7083
dep.loc = expr.loc;
7184
parser.state.module.addPresentationalDependency(dep);
85+
86+
// TODO webpack 6 remove
87+
if (warning) {
88+
parser.state.module.addWarning(
89+
new NodeStuffInWebError(dep.loc, expressionName, warning)
90+
);
91+
}
92+
7293
return true;
7394
});
7495
};
7596

76-
const setConstant = (expressionName, value) =>
77-
setModuleConstant(expressionName, () => value);
97+
const setConstant = (expressionName, value, warning) =>
98+
setModuleConstant(expressionName, () => value, warning);
7899

79100
const context = compiler.context;
80101
if (localOptions.__filename) {
81-
if (localOptions.__filename === "mock") {
82-
setConstant("__filename", "/index.js");
83-
} else if (localOptions.__filename === true) {
84-
setModuleConstant("__filename", module =>
85-
relative(compiler.inputFileSystem, context, module.resource)
86-
);
102+
switch (localOptions.__filename) {
103+
case "mock":
104+
setConstant("__filename", "/index.js");
105+
break;
106+
case "warn-mock":
107+
setConstant(
108+
"__filename",
109+
"/index.js",
110+
"The __filename is Node.js feature and doesn't present in browser."
111+
);
112+
break;
113+
case true:
114+
setModuleConstant("__filename", module =>
115+
relative(compiler.inputFileSystem, context, module.resource)
116+
);
117+
break;
87118
}
119+
88120
parser.hooks.evaluateIdentifier
89121
.for("__filename")
90122
.tap("NodeStuffPlugin", expr => {
@@ -94,13 +126,24 @@ class NodeStuffPlugin {
94126
});
95127
}
96128
if (localOptions.__dirname) {
97-
if (localOptions.__dirname === "mock") {
98-
setConstant("__dirname", "/");
99-
} else if (localOptions.__dirname === true) {
100-
setModuleConstant("__dirname", module =>
101-
relative(compiler.inputFileSystem, context, module.context)
102-
);
129+
switch (localOptions.__dirname) {
130+
case "mock":
131+
setConstant("__dirname", "/");
132+
break;
133+
case "warn-mock":
134+
setConstant(
135+
"__dirname",
136+
"/",
137+
"The __dirname is Node.js feature and doesn't present in browser."
138+
);
139+
break;
140+
case true:
141+
setModuleConstant("__dirname", module =>
142+
relative(compiler.inputFileSystem, context, module.context)
143+
);
144+
break;
103145
}
146+
104147
parser.hooks.evaluateIdentifier
105148
.for("__dirname")
106149
.tap("NodeStuffPlugin", expr => {

lib/config/defaults.js

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,10 @@ const applyWebpackOptionsDefaults = options => {
211211
: "var";
212212
});
213213

214-
applyNodeDefaults(options.node, { targetProperties });
214+
applyNodeDefaults(options.node, {
215+
futureDefaults: options.experiments.futureDefaults,
216+
targetProperties
217+
});
215218

216219
F(options, "performance", () =>
217220
production &&
@@ -262,6 +265,7 @@ const applyExperimentsDefaults = (experiments, { production, development }) => {
262265
D(experiments, "layers", false);
263266
D(experiments, "lazyCompilation", false);
264267
D(experiments, "buildHttp", false);
268+
D(experiments, "futureDefaults", false);
265269

266270
if (typeof experiments.buildHttp === "object") {
267271
D(experiments.buildHttp, "frozen", production);
@@ -943,21 +947,26 @@ const applyLoaderDefaults = (loader, { targetProperties }) => {
943947
* @param {WebpackNode} node options
944948
* @param {Object} options options
945949
* @param {TargetProperties | false} options.targetProperties target properties
950+
* @param {boolean} options.futureDefaults is future defaults enabled
946951
* @returns {void}
947952
*/
948-
const applyNodeDefaults = (node, { targetProperties }) => {
953+
const applyNodeDefaults = (node, { futureDefaults, targetProperties }) => {
949954
if (node === false) return;
955+
950956
F(node, "global", () => {
951957
if (targetProperties && targetProperties.global) return false;
952-
return true;
958+
// TODO webpack 6 should always default to false
959+
return futureDefaults ? "warn" : true;
953960
});
954961
F(node, "__filename", () => {
955962
if (targetProperties && targetProperties.node) return "eval-only";
956-
return "mock";
963+
// TODO webpack 6 should always default to false
964+
return futureDefaults ? "warn-mock" : "mock";
957965
});
958966
F(node, "__dirname", () => {
959967
if (targetProperties && targetProperties.node) return "eval-only";
960-
return "mock";
968+
// TODO webpack 6 should always default to false
969+
return futureDefaults ? "warn-mock" : "mock";
961970
});
962971
};
963972

lib/util/internalSerializables.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@ module.exports = {
189189
UnsupportedFeatureWarning: () => require("../UnsupportedFeatureWarning"),
190190
"util/LazySet": () => require("../util/LazySet"),
191191
UnhandledSchemeError: () => require("../UnhandledSchemeError"),
192+
NodeStuffInWebError: () => require("../NodeStuffInWebError"),
192193
WebpackError: () => require("../WebpackError"),
193194

194195
"util/registerExternalSerializer": () => {

schemas/WebpackOptions.check.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

schemas/WebpackOptions.json

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -699,6 +699,10 @@
699699
}
700700
]
701701
},
702+
"futureDefaults": {
703+
"description": "Apply defaults of next major version.",
704+
"type": "boolean"
705+
},
702706
"layers": {
703707
"description": "Enable module and chunk layers.",
704708
"type": "boolean"
@@ -1940,15 +1944,15 @@
19401944
"properties": {
19411945
"__dirname": {
19421946
"description": "Include a polyfill for the '__dirname' variable.",
1943-
"enum": [false, true, "mock", "eval-only"]
1947+
"enum": [false, true, "warn-mock", "mock", "eval-only"]
19441948
},
19451949
"__filename": {
19461950
"description": "Include a polyfill for the '__filename' variable.",
1947-
"enum": [false, true, "mock", "eval-only"]
1951+
"enum": [false, true, "warn-mock", "mock", "eval-only"]
19481952
},
19491953
"global": {
19501954
"description": "Include a polyfill for the 'global' variable.",
1951-
"type": "boolean"
1955+
"enum": [false, true, "warn"]
19521956
}
19531957
}
19541958
},

test/Defaults.unittest.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ Object {
9494
"asset": false,
9595
"asyncWebAssembly": false,
9696
"buildHttp": false,
97+
"futureDefaults": false,
9798
"layers": false,
9899
"lazyCompilation": false,
99100
"outputModule": false,
@@ -1875,4 +1876,29 @@ Object {
18751876
+ "async-node",
18761877
`)
18771878
);
1879+
1880+
test(
1881+
"experiments.futureDefaults",
1882+
{
1883+
experiments: {
1884+
futureDefaults: true
1885+
}
1886+
},
1887+
e =>
1888+
e.toMatchInlineSnapshot(`
1889+
- Expected
1890+
+ Received
1891+
1892+
@@ ... @@
1893+
- "futureDefaults": false,
1894+
+ "futureDefaults": true,
1895+
@@ ... @@
1896+
- "__dirname": "mock",
1897+
- "__filename": "mock",
1898+
- "global": true,
1899+
+ "__dirname": "warn-mock",
1900+
+ "__filename": "warn-mock",
1901+
+ "global": "warn",
1902+
`)
1903+
);
18781904
});

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy