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