mirror of https://github.com/webpack/webpack.git
Compare commits
6 Commits
7ba7bbe7f7
...
a1d92f3758
Author | SHA1 | Date |
---|---|---|
|
a1d92f3758 | |
|
3c08fd105c | |
|
f508e8b705 | |
|
5c11f27b6b | |
|
5e51e31eb8 | |
|
6f3ac96bc1 |
|
@ -214,7 +214,7 @@ jobs:
|
||||||
|
|
||||||
# Install old `jest` version and deps for legacy node versions
|
# Install old `jest` version and deps for legacy node versions
|
||||||
- run: |
|
- run: |
|
||||||
yarn upgrade jest@^27.5.0 jest-circus@^27.5.0 jest-cli@^27.5.0 jest-diff@^27.5.0 jest-environment-node@^27.5.0 jest-junit@^13.0.0 @types/jest@^27.4.0 pretty-format@^27.0.2 husky@^8.0.3 lint-staged@^13.2.1 cspell@^6.31.1 open-cli@^7.2.0 coffee-loader@^1.0.0 babel-loader@^8.1.0 style-loader@^2.0.0 css-loader@^5.0.1 less-loader@^8.1.1 mini-css-extract-plugin@^1.6.1 nyc@^15.1.0 --ignore-engines
|
yarn upgrade jest@^27.5.0 jest-circus@^27.5.0 jest-cli@^27.5.0 jest-diff@^27.5.0 jest-environment-node@^27.5.0 jest-junit@^13.0.0 @types/jest@^27.4.0 pretty-format@^27.0.2 husky@^8.0.3 lint-staged@^13.2.1 cspell@^6.31.1 open-cli@^7.2.0 coffee-loader@^1.0.0 babel-loader@^8.1.0 style-loader@^2.0.0 css-loader@^5.0.1 less-loader@^8.1.1 mini-css-extract-plugin@^1.6.1 nyc@^15.1.0 memfs@4.14.0 --ignore-engines
|
||||||
yarn --frozen-lockfile --ignore-engines
|
yarn --frozen-lockfile --ignore-engines
|
||||||
if: matrix.node-version == '10.x' || matrix.node-version == '12.x' || matrix.node-version == '14.x'
|
if: matrix.node-version == '10.x' || matrix.node-version == '12.x' || matrix.node-version == '14.x'
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ const mime = require("mime-types");
|
||||||
const Chunk = require("./Chunk");
|
const Chunk = require("./Chunk");
|
||||||
const Module = require("./Module");
|
const Module = require("./Module");
|
||||||
const { parseResource } = require("./util/identifier");
|
const { parseResource } = require("./util/identifier");
|
||||||
|
const nonNumericOnlyHash = require("./util/nonNumericOnlyHash");
|
||||||
|
|
||||||
/** @typedef {import("./ChunkGraph")} ChunkGraph */
|
/** @typedef {import("./ChunkGraph")} ChunkGraph */
|
||||||
/** @typedef {import("./ChunkGraph").ModuleId} ModuleId */
|
/** @typedef {import("./ChunkGraph").ModuleId} ModuleId */
|
||||||
|
@ -63,7 +64,7 @@ const hashLength = (replacer, handler, assetInfo, hashName) => {
|
||||||
} else {
|
} else {
|
||||||
const hash = replacer(match, arg, input);
|
const hash = replacer(match, arg, input);
|
||||||
|
|
||||||
result = length ? hash.slice(0, length) : hash;
|
result = length ? nonNumericOnlyHash(hash, length) : hash;
|
||||||
}
|
}
|
||||||
if (assetInfo) {
|
if (assetInfo) {
|
||||||
assetInfo.immutable = true;
|
assetInfo.immutable = true;
|
||||||
|
|
|
@ -115,7 +115,7 @@ class ImportMetaPlugin {
|
||||||
new ModuleDependencyWarning(
|
new ModuleDependencyWarning(
|
||||||
parser.state.module,
|
parser.state.module,
|
||||||
new CriticalDependencyWarning(
|
new CriticalDependencyWarning(
|
||||||
"Accessing import.meta directly is unsupported (only property access or destructuring is supported)"
|
"'import.meta' cannot be used as a standalone expression. For static analysis, its properties must be accessed directly (e.g., 'import.meta.url') or through destructuring."
|
||||||
),
|
),
|
||||||
/** @type {DependencyLocation} */ (metaProperty.loc)
|
/** @type {DependencyLocation} */ (metaProperty.loc)
|
||||||
)
|
)
|
||||||
|
|
24
package.json
24
package.json
|
@ -111,16 +111,16 @@
|
||||||
"@babel/core": "^7.27.1",
|
"@babel/core": "^7.27.1",
|
||||||
"@babel/preset-react": "^7.27.1",
|
"@babel/preset-react": "^7.27.1",
|
||||||
"@codspeed/core": "^4.0.1",
|
"@codspeed/core": "^4.0.1",
|
||||||
"@eslint/js": "^9.29.0",
|
"@eslint/js": "^9.36.0",
|
||||||
"@eslint/markdown": "^7.1.0",
|
"@eslint/markdown": "^7.3.0",
|
||||||
"@stylistic/eslint-plugin": "^5.2.2",
|
"@stylistic/eslint-plugin": "^5.4.0",
|
||||||
"@types/glob-to-regexp": "^0.4.4",
|
"@types/glob-to-regexp": "^0.4.4",
|
||||||
"@types/graceful-fs": "^4.1.9",
|
"@types/graceful-fs": "^4.1.9",
|
||||||
"@types/jest": "^30.0.0",
|
"@types/jest": "^30.0.0",
|
||||||
"@types/mime-types": "^2.1.4",
|
"@types/mime-types": "^2.1.4",
|
||||||
"@types/node": "^24.1.0",
|
"@types/node": "^24.5.2",
|
||||||
"@types/xxhashjs": "^0.2.4",
|
"@types/xxhashjs": "^0.2.4",
|
||||||
"assemblyscript": "^0.28.5",
|
"assemblyscript": "^0.28.8",
|
||||||
"babel-loader": "^10.0.0",
|
"babel-loader": "^10.0.0",
|
||||||
"bundle-loader": "^0.5.6",
|
"bundle-loader": "^0.5.6",
|
||||||
"coffee-loader": "^5.0.0",
|
"coffee-loader": "^5.0.0",
|
||||||
|
@ -131,13 +131,13 @@
|
||||||
"date-fns": "^4.0.0",
|
"date-fns": "^4.0.0",
|
||||||
"es5-ext": "^0.10.53",
|
"es5-ext": "^0.10.53",
|
||||||
"es6-promise-polyfill": "^1.2.0",
|
"es6-promise-polyfill": "^1.2.0",
|
||||||
"eslint": "^9.29.0",
|
"eslint": "^9.36.0",
|
||||||
"eslint-config-prettier": "^10.1.1",
|
"eslint-config-prettier": "^10.1.1",
|
||||||
"eslint-config-webpack": "^4.5.1",
|
"eslint-config-webpack": "^4.5.1",
|
||||||
"eslint-plugin-import": "^2.32.0",
|
"eslint-plugin-import": "^2.32.0",
|
||||||
"eslint-plugin-jest": "^29.0.1",
|
"eslint-plugin-jest": "^29.0.1",
|
||||||
"eslint-plugin-jsdoc": "^51.2.3",
|
"eslint-plugin-jsdoc": "^51.2.3",
|
||||||
"eslint-plugin-n": "^17.21.0",
|
"eslint-plugin-n": "^17.23.1",
|
||||||
"eslint-plugin-prettier": "^5.5.0",
|
"eslint-plugin-prettier": "^5.5.0",
|
||||||
"eslint-plugin-unicorn": "^61.0.1",
|
"eslint-plugin-unicorn": "^61.0.1",
|
||||||
"file-loader": "^6.0.0",
|
"file-loader": "^6.0.0",
|
||||||
|
@ -146,11 +146,11 @@
|
||||||
"hash-wasm": "^4.9.0",
|
"hash-wasm": "^4.9.0",
|
||||||
"husky": "^9.0.11",
|
"husky": "^9.0.11",
|
||||||
"istanbul": "^0.4.5",
|
"istanbul": "^0.4.5",
|
||||||
"jest": "^30.1.2",
|
"jest": "^30.2.0",
|
||||||
"jest-circus": "^30.1.2",
|
"jest-circus": "^30.2.0",
|
||||||
"jest-cli": "^30.1.2",
|
"jest-cli": "^30.2.0",
|
||||||
"jest-diff": "^30.1.2",
|
"jest-diff": "^30.2.0",
|
||||||
"jest-environment-node": "^30.1.2",
|
"jest-environment-node": "^30.2.0",
|
||||||
"jest-junit": "^16.0.0",
|
"jest-junit": "^16.0.0",
|
||||||
"json-loader": "^0.5.7",
|
"json-loader": "^0.5.7",
|
||||||
"json5": "^2.1.3",
|
"json5": "^2.1.3",
|
||||||
|
|
|
@ -0,0 +1,143 @@
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
const TemplatedPathPlugin = require("../lib/TemplatedPathPlugin");
|
||||||
|
|
||||||
|
describe("TemplatedPathPlugin", () => {
|
||||||
|
describe("hash should be non-numeric", () => {
|
||||||
|
// Move capturedPathReplacer to higher scope to be accessible in all describe blocks
|
||||||
|
let capturedPathReplacer;
|
||||||
|
|
||||||
|
// Set up capturedPathReplacer for all tests
|
||||||
|
beforeEach(() => {
|
||||||
|
const mockCompilation = {
|
||||||
|
hooks: {
|
||||||
|
assetPath: {
|
||||||
|
tap: jest.fn((pluginName, pathReplacerFn) => {
|
||||||
|
capturedPathReplacer = pathReplacerFn;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockCompiler = {
|
||||||
|
hooks: {
|
||||||
|
compilation: {
|
||||||
|
tap: jest.fn((pluginName, compilationFn) => {
|
||||||
|
compilationFn(mockCompilation);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Apply the plugin to capture the path replacer function
|
||||||
|
const plugin = new TemplatedPathPlugin();
|
||||||
|
plugin.apply(mockCompiler);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should prevent numeric-only chunkhash in filename templates", () => {
|
||||||
|
const mockChunk = {
|
||||||
|
id: "test-chunk",
|
||||||
|
name: "test-chunk",
|
||||||
|
renderedHash: "123456789012345678901234567890",
|
||||||
|
hash: "123456789012345678901234567890"
|
||||||
|
};
|
||||||
|
|
||||||
|
const pathData = {
|
||||||
|
chunk: mockChunk,
|
||||||
|
chunkGraph: {},
|
||||||
|
runtime: undefined
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = capturedPathReplacer("[name].[chunkhash:8].js", pathData);
|
||||||
|
|
||||||
|
// Should convert numeric-only hash to include letter prefix
|
||||||
|
expect(result).toBe("test-chunk.b2345678.js");
|
||||||
|
expect(result).toMatch(/^test-chunk\.[a-f]\d{7}\.js$/);
|
||||||
|
expect(result).not.toMatch(/^test-chunk\.\d{8}\.js$/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should prevent numeric-only contenthash in filename templates", () => {
|
||||||
|
const mockChunk = {
|
||||||
|
id: "content-chunk",
|
||||||
|
name: "content-chunk",
|
||||||
|
renderedHash: "abc123def456",
|
||||||
|
hash: "abc123def456",
|
||||||
|
contentHash: {
|
||||||
|
javascript: "987654321098765432109876543210"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const pathData = {
|
||||||
|
chunk: mockChunk,
|
||||||
|
contentHashType: "javascript",
|
||||||
|
chunkGraph: {},
|
||||||
|
runtime: undefined
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = capturedPathReplacer(
|
||||||
|
"[name].[contenthash:6].js",
|
||||||
|
pathData
|
||||||
|
);
|
||||||
|
|
||||||
|
// Should convert numeric-only hash to include letter prefix
|
||||||
|
expect(result).toBe("content-chunk.d87654.js");
|
||||||
|
expect(result).toMatch(/^content-chunk\.[a-f]\d{5}\.js$/);
|
||||||
|
expect(result).not.toMatch(/^content-chunk\.\d{6}\.js$/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should prevent numeric-only fullhash in filename templates", () => {
|
||||||
|
const pathData = {
|
||||||
|
hash: "111111111111111111111111111111",
|
||||||
|
chunkGraph: {},
|
||||||
|
runtime: undefined
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = capturedPathReplacer("bundle.[fullhash:10].js", pathData);
|
||||||
|
|
||||||
|
// Should convert numeric-only hash to include letter prefix
|
||||||
|
expect(result).toBe("bundle.b111111111.js");
|
||||||
|
expect(result).toMatch(/^bundle\.[a-f]\d{9}\.js$/);
|
||||||
|
expect(result).not.toMatch(/^bundle\.\d{10}\.js$/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should preserve alphanumeric hashes unchanged", () => {
|
||||||
|
const mockChunk = {
|
||||||
|
id: "mixed-chunk",
|
||||||
|
name: "mixed-chunk",
|
||||||
|
renderedHash: "abc123def456ghi789jkl012mno345",
|
||||||
|
hash: "abc123def456ghi789jkl012mno345"
|
||||||
|
};
|
||||||
|
|
||||||
|
const pathData = {
|
||||||
|
chunk: mockChunk,
|
||||||
|
chunkGraph: {},
|
||||||
|
runtime: undefined
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = capturedPathReplacer("[name].[chunkhash:8].js", pathData);
|
||||||
|
|
||||||
|
// Should preserve original hash since it contains non-numeric chars
|
||||||
|
expect(result).toBe("mixed-chunk.abc123de.js");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should handle zero-length hash parameter", () => {
|
||||||
|
const mockChunk = {
|
||||||
|
id: "zero-chunk",
|
||||||
|
name: "zero-chunk",
|
||||||
|
renderedHash: "123456789012345678901234567890",
|
||||||
|
hash: "123456789012345678901234567890"
|
||||||
|
};
|
||||||
|
|
||||||
|
const pathData = {
|
||||||
|
chunk: mockChunk,
|
||||||
|
chunkGraph: {},
|
||||||
|
runtime: undefined
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = capturedPathReplacer("[name].[chunkhash:0].js", pathData);
|
||||||
|
|
||||||
|
// When length is 0, it's treated as falsy and returns the full hash
|
||||||
|
expect(result).toBe("zero-chunk.123456789012345678901234567890.js");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -1,3 +1,7 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
module.exports = [[/Critical dependency: Accessing import\.meta/]];
|
module.exports = [
|
||||||
|
[
|
||||||
|
/Critical dependency: 'import\.meta' cannot be used as a standalone expression\. For static analysis, its properties must be accessed directly \(e\.g\., 'import\.meta\.url'\) or through destructuring\./
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
|
@ -2,6 +2,6 @@
|
||||||
|
|
||||||
module.exports = [
|
module.exports = [
|
||||||
[
|
[
|
||||||
/Accessing import.meta directly is unsupported \(only property access or destructuring is supported\)/
|
/'import\.meta' cannot be used as a standalone expression\. For static analysis, its properties must be accessed directly \(e\.g\., 'import\.meta\.url'\) or through destructuring\./
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
|
Loading…
Reference in New Issue