mirror of https://github.com/webpack/webpack.git
add node-module option for node.__file/dirname
evaluate __filename and __dirname for common js modules when output.module to fileURLToPath(import.meta.url) and fileURLToPath(import.meta.url + "/..") respectively
This commit is contained in:
parent
562f17a8c0
commit
6c3a04d5ce
|
|
@ -1633,11 +1633,17 @@ export interface NodeOptions {
|
|||
/**
|
||||
* Include a polyfill for the '__dirname' variable.
|
||||
*/
|
||||
__dirname?: false | true | "warn-mock" | "mock" | "eval-only";
|
||||
__dirname?: false | true | "warn-mock" | "mock" | "node-module" | "eval-only";
|
||||
/**
|
||||
* Include a polyfill for the '__filename' variable.
|
||||
*/
|
||||
__filename?: false | true | "warn-mock" | "mock" | "eval-only";
|
||||
__filename?:
|
||||
| false
|
||||
| true
|
||||
| "warn-mock"
|
||||
| "mock"
|
||||
| "node-module"
|
||||
| "eval-only";
|
||||
/**
|
||||
* Include a polyfill for the 'global' variable.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -15,14 +15,19 @@ const {
|
|||
} = require("./javascript/JavascriptParserHelpers");
|
||||
const { relative } = require("./util/fs");
|
||||
const { parseResource } = require("./util/identifier");
|
||||
const InitFragment = require("./InitFragment");
|
||||
|
||||
/** @typedef {import("webpack-sources").ReplaceSource} ReplaceSource */
|
||||
/** @typedef {import("./Compiler")} Compiler */
|
||||
/** @typedef {import("./Dependency")} Dependency */
|
||||
/** @typedef {import("./DependencyTemplates")} DependencyTemplates */
|
||||
/** @typedef {import("./RuntimeTemplate")} RuntimeTemplate */
|
||||
/** @typedef {import("../declarations/WebpackOptions").NodeOptions} NodeOptions */
|
||||
|
||||
class NodeStuffPlugin {
|
||||
/**
|
||||
* @param {NodeOptions} options options
|
||||
*/
|
||||
constructor(options) {
|
||||
this.options = options;
|
||||
}
|
||||
|
|
@ -71,7 +76,7 @@ class NodeStuffPlugin {
|
|||
});
|
||||
}
|
||||
|
||||
const setModuleConstant = (expressionName, fn, warning) => {
|
||||
const setCjsModuleConstant = (expressionName, fn, warning) => {
|
||||
parser.hooks.expression
|
||||
.for(expressionName)
|
||||
.tap("NodeStuffPlugin", expr => {
|
||||
|
|
@ -94,24 +99,54 @@ class NodeStuffPlugin {
|
|||
});
|
||||
};
|
||||
|
||||
const setConstant = (expressionName, value, warning) =>
|
||||
setModuleConstant(expressionName, () => value, warning);
|
||||
const setEsmModuleConstant = (expressionName, fn) => {
|
||||
parser.hooks.expression
|
||||
.for(expressionName)
|
||||
.tap("NodeStuffPlugin", expr => {
|
||||
const dep = new CachedConstDependency(
|
||||
JSON.stringify(fn(parser.state.module)),
|
||||
expr.range,
|
||||
expressionName,
|
||||
[
|
||||
new InitFragment(
|
||||
'import url from "url"',
|
||||
InitFragment.STAGE_CONSTANTS,
|
||||
0,
|
||||
"import url"
|
||||
)
|
||||
]
|
||||
);
|
||||
dep.loc = expr.loc;
|
||||
parser.state.module.addPresentationalDependency(dep);
|
||||
|
||||
return true;
|
||||
});
|
||||
};
|
||||
|
||||
const setCjsConstant = (expressionName, value, warning) =>
|
||||
setCjsModuleConstant(expressionName, () => value, warning);
|
||||
|
||||
const setEsmConstant = (expressionName, value) =>
|
||||
setEsmModuleConstant(expressionName, () => value);
|
||||
|
||||
const context = compiler.context;
|
||||
if (localOptions.__filename) {
|
||||
switch (localOptions.__filename) {
|
||||
case "mock":
|
||||
setConstant("__filename", "/index.js");
|
||||
setCjsConstant("__filename", "/index.js");
|
||||
break;
|
||||
case "warn-mock":
|
||||
setConstant(
|
||||
setCjsConstant(
|
||||
"__filename",
|
||||
"/index.js",
|
||||
"The __filename is Node.js feature and doesn't present in browser."
|
||||
);
|
||||
break;
|
||||
case "node-module":
|
||||
setEsmConstant("__filename", "fileURLToPath(import.meta.url)");
|
||||
break;
|
||||
case true:
|
||||
setModuleConstant("__filename", module =>
|
||||
setCjsModuleConstant("__filename", module =>
|
||||
relative(compiler.inputFileSystem, context, module.resource)
|
||||
);
|
||||
break;
|
||||
|
|
@ -128,17 +163,23 @@ class NodeStuffPlugin {
|
|||
if (localOptions.__dirname) {
|
||||
switch (localOptions.__dirname) {
|
||||
case "mock":
|
||||
setConstant("__dirname", "/");
|
||||
setCjsConstant("__dirname", "/");
|
||||
break;
|
||||
case "warn-mock":
|
||||
setConstant(
|
||||
setCjsConstant(
|
||||
"__dirname",
|
||||
"/",
|
||||
"The __dirname is Node.js feature and doesn't present in browser."
|
||||
);
|
||||
break;
|
||||
case "node-module":
|
||||
setEsmConstant(
|
||||
"__filename",
|
||||
'fileURLToPath(import.meta.url + "/..")'
|
||||
);
|
||||
break;
|
||||
case true:
|
||||
setModuleConstant("__dirname", module =>
|
||||
setCjsModuleConstant("__dirname", module =>
|
||||
relative(compiler.inputFileSystem, context, module.context)
|
||||
);
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -213,6 +213,7 @@ const applyWebpackOptionsDefaults = options => {
|
|||
|
||||
applyNodeDefaults(options.node, {
|
||||
futureDefaults: options.experiments.futureDefaults,
|
||||
outputModule: options.output.module,
|
||||
targetProperties
|
||||
});
|
||||
|
||||
|
|
@ -948,9 +949,13 @@ const applyLoaderDefaults = (loader, { targetProperties }) => {
|
|||
* @param {Object} options options
|
||||
* @param {TargetProperties | false} options.targetProperties target properties
|
||||
* @param {boolean} options.futureDefaults is future defaults enabled
|
||||
* @param {boolean} options.outputModule is output type is module
|
||||
* @returns {void}
|
||||
*/
|
||||
const applyNodeDefaults = (node, { futureDefaults, targetProperties }) => {
|
||||
const applyNodeDefaults = (
|
||||
node,
|
||||
{ futureDefaults, outputModule, targetProperties }
|
||||
) => {
|
||||
if (node === false) return;
|
||||
|
||||
F(node, "global", () => {
|
||||
|
|
@ -958,16 +963,16 @@ const applyNodeDefaults = (node, { futureDefaults, targetProperties }) => {
|
|||
// TODO webpack 6 should always default to false
|
||||
return futureDefaults ? "warn" : true;
|
||||
});
|
||||
F(node, "__filename", () => {
|
||||
if (targetProperties && targetProperties.node) return "eval-only";
|
||||
|
||||
const handlerForNames = () => {
|
||||
if (targetProperties && targetProperties.node)
|
||||
return outputModule ? "node-module" : "eval-only";
|
||||
// TODO webpack 6 should always default to false
|
||||
return futureDefaults ? "warn-mock" : "mock";
|
||||
});
|
||||
F(node, "__dirname", () => {
|
||||
if (targetProperties && targetProperties.node) return "eval-only";
|
||||
// TODO webpack 6 should always default to false
|
||||
return futureDefaults ? "warn-mock" : "mock";
|
||||
});
|
||||
};
|
||||
|
||||
F(node, "__filename", handlerForNames);
|
||||
F(node, "__dirname", handlerForNames);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ const NullDependency = require("./NullDependency");
|
|||
/** @typedef {import("webpack-sources").ReplaceSource} ReplaceSource */
|
||||
/** @typedef {import("../ChunkGraph")} ChunkGraph */
|
||||
/** @typedef {import("../Dependency")} Dependency */
|
||||
/** @typedef {import("../Generator").GenerateContext} GenerateContext */
|
||||
/** @typedef {import("../Dependency").UpdateHashContext} UpdateHashContext */
|
||||
/** @typedef {import("../DependencyTemplate").DependencyTemplateContext} DependencyTemplateContext */
|
||||
/** @typedef {import("../DependencyTemplates")} DependencyTemplates */
|
||||
|
|
@ -21,12 +22,19 @@ const NullDependency = require("./NullDependency");
|
|||
/** @typedef {import("../util/Hash")} Hash */
|
||||
|
||||
class CachedConstDependency extends NullDependency {
|
||||
constructor(expression, range, identifier) {
|
||||
/**
|
||||
* @param {string} expression expression
|
||||
* @param {number|[number, number]} range range
|
||||
* @param {string} identifier identifier
|
||||
* @param {InitFragment<GenerateContext>[]=} initFragments init fragments
|
||||
*/
|
||||
constructor(expression, range, identifier, initFragments) {
|
||||
super();
|
||||
|
||||
this.expression = expression;
|
||||
this.range = range;
|
||||
this.identifier = identifier;
|
||||
this.initFragments = initFragments;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -36,9 +44,14 @@ class CachedConstDependency extends NullDependency {
|
|||
* @returns {void}
|
||||
*/
|
||||
updateHash(hash, context) {
|
||||
hash.update(this.identifier + "");
|
||||
hash.update(this.range + "");
|
||||
hash.update(this.expression + "");
|
||||
hash.update(`${this.identifier}`);
|
||||
hash.update(`${this.range}`);
|
||||
hash.update(`${this.expression}`);
|
||||
|
||||
if (this.initFragments) {
|
||||
for (const fragment of this.initFragments)
|
||||
hash.update(`${fragment.key}_${fragment.position}`);
|
||||
}
|
||||
}
|
||||
|
||||
serialize(context) {
|
||||
|
|
@ -47,6 +60,7 @@ class CachedConstDependency extends NullDependency {
|
|||
write(this.expression);
|
||||
write(this.range);
|
||||
write(this.identifier);
|
||||
write(this.initFragments);
|
||||
|
||||
super.serialize(context);
|
||||
}
|
||||
|
|
@ -57,6 +71,7 @@ class CachedConstDependency extends NullDependency {
|
|||
this.expression = read();
|
||||
this.range = read();
|
||||
this.identifier = read();
|
||||
this.initFragments = read();
|
||||
|
||||
super.deserialize(context);
|
||||
}
|
||||
|
|
@ -83,11 +98,22 @@ CachedConstDependency.Template = class CachedConstDependencyTemplate extends (
|
|||
) {
|
||||
const dep = /** @type {CachedConstDependency} */ (dependency);
|
||||
|
||||
let position = 0;
|
||||
|
||||
if (dep.initFragments && dep.initFragments.length > 0) {
|
||||
for (const fragment of dep.initFragments) {
|
||||
initFragments.push(fragment);
|
||||
}
|
||||
position = dep.initFragments[dep.initFragments.length - 1].position + 1;
|
||||
}
|
||||
|
||||
initFragments.push(
|
||||
new InitFragment(
|
||||
`var ${dep.identifier} = ${dep.expression};\n`,
|
||||
`${runtimeTemplate.supportsConst() ? "const" : "var"} ${
|
||||
dep.identifier
|
||||
} = ${dep.expression};\n`,
|
||||
InitFragment.STAGE_CONSTANTS,
|
||||
0,
|
||||
position,
|
||||
`const ${dep.identifier}`
|
||||
)
|
||||
);
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -1944,11 +1944,11 @@
|
|||
"properties": {
|
||||
"__dirname": {
|
||||
"description": "Include a polyfill for the '__dirname' variable.",
|
||||
"enum": [false, true, "warn-mock", "mock", "eval-only"]
|
||||
"enum": [false, true, "warn-mock", "mock", "node-module", "eval-only"]
|
||||
},
|
||||
"__filename": {
|
||||
"description": "Include a polyfill for the '__filename' variable.",
|
||||
"enum": [false, true, "warn-mock", "mock", "eval-only"]
|
||||
"enum": [false, true, "warn-mock", "mock", "node-module", "eval-only"]
|
||||
},
|
||||
"global": {
|
||||
"description": "Include a polyfill for the 'global' variable.",
|
||||
|
|
|
|||
|
|
@ -7161,12 +7161,12 @@ declare interface NodeOptions {
|
|||
/**
|
||||
* Include a polyfill for the '__dirname' variable.
|
||||
*/
|
||||
__dirname?: boolean | "warn-mock" | "mock" | "eval-only";
|
||||
__dirname?: boolean | "warn-mock" | "mock" | "node-module" | "eval-only";
|
||||
|
||||
/**
|
||||
* Include a polyfill for the '__filename' variable.
|
||||
*/
|
||||
__filename?: boolean | "warn-mock" | "mock" | "eval-only";
|
||||
__filename?: boolean | "warn-mock" | "mock" | "node-module" | "eval-only";
|
||||
|
||||
/**
|
||||
* Include a polyfill for the 'global' variable.
|
||||
|
|
|
|||
Loading…
Reference in New Issue