/
githubmirror
/
webpack
Обзор
Документация
Войти
/
githubmirror
/
webpack
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
v5.105.1
test/PersistentCaching.test.js
282 строки
7 KB
Xiao
feat: add `snapshot.contextModule `to configure snapshots for context modules
25 авг 2025, 22:16
Не верифицирован
25 авг 2025, 22:16
d224b7b
Код
Авторство
О чём код?
"use strict"; require("./helpers/warmup-webpack"); const fs = require("fs"); const path = require("path"); const util = require("util"); const vm = require("vm"); const rimraf = require("rimraf"); const readdir = util.promisify(fs.readdir); const writeFile = util.promisify(fs.writeFile); const utimes = util.promisify(fs.utimes); const mkdir = util.promisify(fs.mkdir); describe("Persistent Caching", () => { const tempPath = path.resolve(__dirname, "js", "persistent-caching"); const outputPath = path.resolve(tempPath, "output"); const cachePath = path.resolve(tempPath, "cache"); const srcPath = path.resolve(tempPath, "src"); const config = { mode: "none", context: tempPath, cache: { type: "filesystem", buildDependencies: { // avoid rechecking build dependencies // for performance // this is already covered by another test case defaultWebpack: [] }, cacheLocation: cachePath }, experiments: { css: true }, resolve: { alias: { "image.png": false, "image1.png": false } }, target: "node", output: { library: { type: "commonjs-module", export: "default" }, path: outputPath } }; beforeEach((done) => { rimraf(tempPath, done); }); const updateSrc = async (data) => { const ts = new Date(Date.now() - 10000); await mkdir(srcPath, { recursive: true }); for (const key of Object.keys(data)) { const p = path.resolve(srcPath, key); await writeFile(p, data[key]); await utimes(p, ts, ts); } }; const compile = async (configAdditions = {}) => new Promise((resolve, reject) => { const webpack = require("../"); webpack( { ...config, ...configAdditions, cache: { ...config.cache, ...configAdditions.cache } }, (err, stats) => { if (err) return reject(err); if (stats.hasErrors()) { return reject(stats.toString({ preset: "errors-only" })); } resolve(stats); } ); }); const getCacheFileTimes = async () => { const cacheFiles = (await readdir(cachePath)).sort(); return new Map( cacheFiles.map((f) => [ f, fs.statSync(path.join(cachePath, f)).mtime.toString() ]) ); }; const execute = () => { const cache = {}; const require = (name) => { if (cache[name]) return cache[name].exports; if (!name.endsWith(".js")) name += ".js"; const p = path.resolve(outputPath, name); const source = fs.readFileSync(p, "utf8"); const context = {}; const fn = vm.runInThisContext( `(function(require, module, exports) { ${source} })`, context, { filename: p } ); const m = { exports: {} }; cache[name] = m; fn(require, m, m.exports); return m.exports; }; return require("./main"); }; it("should compile fine (warmup)", async () => { const data = { "index.js": `import file from "./file.js"; export default 40 + file; `, "file.js": "export default 2;" }; await updateSrc(data); await compile(); expect(execute()).toBe(42); }, 100000); it("should merge multiple small files", async () => { const files = Array.from({ length: 30 }).map((_, i) => `file${i}.js`); const data = { "index.js": ` import * as style from "./style.modules.css"; ${files.map((f, i) => `import f${i} from "./${f}";`).join("\n")} export default ${files.map((_, i) => `f${i}`).join(" + ")}; export { style }; `, "style.modules.css": `.class { color: red; background: url('image.png'); }` }; for (const file of files) { data[file] = "export default 1;"; } await updateSrc(data); await compile({ cache: { compression: false } }); expect(execute()).toBe(30); for (let i = 0; i < 30; i++) { updateSrc({ [files[i]]: "export default 2;", "style.modules.css": `.class-${i} { color: red; background: url('image1.png'); }` }); await compile({ cache: { compression: false } }); expect(execute()).toBe(31 + i); } const cacheFiles = await readdir(cachePath); expect(cacheFiles.length).toBeLessThan(20); expect(cacheFiles.length).toBeGreaterThan(10); }, 120000); it("should optimize unused content", async () => { const data = { "a.js": 'import "react-dom";', "b.js": 'import "acorn";', "c.js": 'import "core-js";', "d.js": 'import "date-fns";', "e.js": 'import "lodash";' }; await updateSrc(data); const c = (items) => { const entry = {}; for (const item of items) entry[item] = `./src/${item}.js`; return compile({ entry, cache: { compression: false } }); }; await c("abcde"); await c("abc"); await c("cde"); await c("acd"); await c("bce"); await c("abcde"); const cacheFiles = await readdir(cachePath); expect(cacheFiles.length).toBeGreaterThan(4); }, 120000); it("should allow persistent caching of container related objects", async () => { const data = { "index.js": "export default import('container/src/exposed').then(m => m.default);", "exposed.js": "import lib from 'lib'; export default 21 + lib;", "lib.js": "export default 20", "lib2.js": "export default 21" }; await updateSrc(data); const webpack = require("../"); const configAdditions = { plugins: [ new webpack.container.ModuleFederationPlugin({ name: "container", library: { type: "commonjs-module" }, exposes: ["./src/exposed"], remotes: { container: ["./no-container", "./container"] }, shared: { lib: { import: "./src/lib", shareKey: "lib", version: "1.2.0", requiredVersion: "^1.0.0" }, "./src/lib2": { shareKey: "lib", version: "1.2.3" } } }) ] }; await compile(configAdditions); await expect(execute()).resolves.toBe(42); await updateSrc({ "exposed.js": "module.exports = { ok: true };" }); await compile(configAdditions); await expect(execute()).resolves.toEqual({ ok: true }); }, 120000); it("should not overwrite cache files if readonly = true", async () => { await updateSrc({ "main.js": ` import { sum } from 'lodash'; sum([1,2,3]) ` }); await compile({ entry: "./src/main.js" }); const firstCacheFileTimes = await getCacheFileTimes(); await updateSrc({ "main.js": ` import 'lodash'; ` }); await compile({ entry: "./src/main.js", cache: { ...config.cache, readonly: true } }); await expect(getCacheFileTimes()).resolves.toEqual(firstCacheFileTimes); }, 20000); it("should not invalidate cache files if timestamps changed with dynamic import()", async () => { const configAdditions = { entry: "./src/main.js", snapshot: { resolve: { hash: true }, module: { hash: true }, contextModule: { hash: true } } }; await updateSrc({ "newer.js": "export default 2;", // eslint-disable-next-line no-template-curly-in-string "main.js": 'const f = "newer.js"; import(`./${f}`);' }); await compile(configAdditions); const firstCacheFileTimes = await getCacheFileTimes(); await utimes(path.resolve(srcPath, "newer.js"), new Date(), new Date()); await compile(configAdditions); await expect(getCacheFileTimes()).resolves.toEqual(firstCacheFileTimes); }, 20000); });