add [root] and [internal-path] placeholders

- [root] prevents asset path leading outside of build context
- [internal-path] is like [path] guarded by [root] (`[root][path]`)
This commit is contained in:
Ivan Kopeykin 2022-04-06 13:40:41 +03:00
parent d3a0f8de03
commit 85dd7b71d2
8 changed files with 100 additions and 18 deletions

View File

@ -6,7 +6,7 @@
"use strict";
const mime = require("mime-types");
const { basename, extname } = require("path");
const { basename, extname, posix } = require("path");
const util = require("util");
const Chunk = require("./Chunk");
const Module = require("./Module");
@ -29,6 +29,8 @@ const prepareId = id => {
return id.replace(/(^[.-]|[^a-zA-Z0-9_-])+/g, "_");
};
const internalPath = path =>
path.replace(/^(\.\.\/)+/, m => "_/".repeat(m.length / 3));
const hashLength = (replacer, handler, assetInfo, hashName) => {
const fn = (match, arg, input) => {
@ -79,6 +81,18 @@ const replacer = (value, allowEmpty) => {
return fn;
};
/**
* @param {string} input input
* @param {number} index match index
* @returns {string} replaced path
*/
const rootReplacer = (input, index) => {
const subPath = input.slice(index + 6 /* "[root]".length */);
const normalized = posix.normalize(subPath);
return input.slice(0, index) + internalPath(normalized);
};
const deprecationCache = new Map();
const deprecatedFunction = (() => () => {})();
const deprecated = (fn, message, code) => {
@ -152,6 +166,10 @@ const replacePathVariables = (path, data, assetInfo) => {
replacements.set("query", replacer(query, true));
replacements.set("fragment", replacer(fragment, true));
replacements.set("path", replacer(path, true));
replacements.set(
"internal-path",
replacer(() => internalPath(path), true)
);
replacements.set("base", replacer(base));
replacements.set("name", replacer(name));
replacements.set("ext", replacer(ext, true));
@ -325,6 +343,17 @@ const replacePathVariables = (path, data, assetInfo) => {
return match;
});
const regexp = /\[root\]/gi;
const matches = [];
let match;
while ((match = regexp.exec(path))) matches.push(match.index);
if (matches.length) {
for (let i = matches.length - 1; i >= 0; i--) {
path = rootReplacer(path, matches[i]);
}
}
return path;
};

View File

@ -739,7 +739,7 @@ const applyOutputDefaults = (
});
F(output, "module", () => !!outputModule);
D(output, "filename", output.module ? "[name].mjs" : "[name].js");
D(output, "filename", output.module ? "[root][name].mjs" : "[root][name].js");
F(output, "iife", () => !output.module);
D(output, "importFunctionName", "import");
D(output, "importMetaName", "import.meta");

View File

@ -300,7 +300,7 @@ describe("snapshots", () => {
"assetModuleFilename": "[hash][ext][query]",
"asyncChunks": true,
"charset": true,
"chunkFilename": "[name].js",
"chunkFilename": "[root][name].js",
"chunkFormat": "array-push",
"chunkLoadTimeout": 120000,
"chunkLoading": "jsonp",
@ -308,8 +308,8 @@ describe("snapshots", () => {
"clean": undefined,
"compareBeforeEmit": true,
"crossOriginLoading": false,
"cssChunkFilename": "[name].css",
"cssFilename": "[name].css",
"cssChunkFilename": "[root][name].css",
"cssFilename": "[root][name].css",
"devtoolFallbackModuleFilenameTemplate": undefined,
"devtoolModuleFilenameTemplate": undefined,
"devtoolNamespace": "webpack",
@ -330,7 +330,7 @@ describe("snapshots", () => {
"forOf": true,
"module": undefined,
},
"filename": "[name].js",
"filename": "[root][name].js",
"globalObject": "self",
"hashDigest": "hex",
"hashDigestLength": 20,
@ -879,8 +879,8 @@ describe("snapshots", () => {
- "externalsType": "var",
+ "externalsType": "module",
@@ ... @@
- "chunkFilename": "[name].js",
+ "chunkFilename": "[name].mjs",
- "chunkFilename": "[root][name].js",
+ "chunkFilename": "[root][name].mjs",
@@ ... @@
- "dynamicImport": undefined,
+ "dynamicImport": true,
@ -888,8 +888,8 @@ describe("snapshots", () => {
- "module": undefined,
+ "module": true,
@@ ... @@
- "filename": "[name].js",
+ "filename": "[name].mjs",
- "filename": "[root][name].js",
+ "filename": "[root][name].mjs",
@@ ... @@
- "hotUpdateChunkFilename": "[id].[fullhash].hot-update.js",
+ "hotUpdateChunkFilename": "[id].[fullhash].hot-update.mjs",
@ -994,15 +994,15 @@ describe("snapshots", () => {
+ Received
@@ ... @@
- "chunkFilename": "[name].js",
- "chunkFilename": "[root][name].js",
+ "chunkFilename": "[id].bundle.js",
@@ ... @@
- "cssChunkFilename": "[name].css",
- "cssFilename": "[name].css",
- "cssChunkFilename": "[root][name].css",
- "cssFilename": "[root][name].css",
+ "cssChunkFilename": "[id].bundle.css",
+ "cssFilename": "bundle.css",
@@ ... @@
- "filename": "[name].js",
- "filename": "[root][name].js",
+ "filename": "bundle.js",
`)
);
@ -1012,15 +1012,15 @@ describe("snapshots", () => {
+ Received
@@ ... @@
- "chunkFilename": "[name].js",
- "chunkFilename": "[root][name].js",
+ "chunkFilename": "[id].js",
@@ ... @@
- "cssChunkFilename": "[name].css",
- "cssFilename": "[name].css",
- "cssChunkFilename": "[root][name].css",
- "cssFilename": "[root][name].css",
+ "cssChunkFilename": "[id].css",
+ "cssFilename": "[id].css",
@@ ... @@
- "filename": "[name].js",
- "filename": "[root][name].js",
+ "filename": [Function filename],
`)
);

View File

@ -0,0 +1,7 @@
import fs from "fs";
import path from "path";
import txt from "asset/1.txt";
it("should compile and run", () => {
expect(fs.readFileSync(path.resolve(__dirname, "..", txt)).toString()).toMatch("text");
});

View File

@ -0,0 +1,5 @@
module.exports = {
findBundle(i) {
return `./_/bundle${i}.js`;
}
};

View File

@ -0,0 +1,36 @@
const path = require("path");
const base = {
mode: "production",
target: "node",
module: {
rules: [
{
test: /\.txt$/,
type: "asset/resource"
}
]
},
output: {
filename: "[root]../bundle0.js",
assetModuleFilename: "[root][path][name]-[hash][ext]"
},
resolve: {
modules: [path.resolve(__dirname, "..", "..", "..", "fixtures")]
},
stats: {
errorDetails: true
}
};
/** @type {import("../../../../types").Configuration[]} */
module.exports = [
base,
{
...base,
output: {
filename: "[root]../bundle1.js",
assetModuleFilename: "some/dir/[root][path][name]-[hash][ext]"
}
}
];

1
test/fixtures/asset/1.txt vendored Normal file
View File

@ -0,0 +1 @@
text

4
test/fixtures/asset/package.json vendored Normal file
View File

@ -0,0 +1,4 @@
{
"name": "asset",
"version": "1.0.0"
}