/
githubmirror
/
webpack
Обзор
Документация
Войти
/
githubmirror
/
webpack
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
test/Compiler-caching.test.js
342 строки
10 KB
Alexander Akait
test: fail tests on unexpected deprecations (#21245)
23 июн 2026, 01:28
Не верифицирован
23 июн 2026, 01:28
743256f
Код
Авторство
О чём код?
"use strict"; require("./helpers/warmup-webpack"); const path = require("path"); const fs = require("graceful-fs"); /** @type {{ sync: (pattern: string) => void }} */ const rimraf = require("rimraf"); const expectNoDeprecations = require("./helpers/expectNoDeprecations"); let fixtureCount = 0; /** * @typedef {{ mkdir: string[], writeFile: unknown[] }} CachingLogs * @typedef {import("../").StatsCompilation & { logs?: CachingLogs, assets: import("../").StatsAsset[], modules: import("../").StatsModule[] }} CachingStats */ describe("Compiler (caching)", () => { expectNoDeprecations(); /** * @param {string} entry entry file * @param {import("../").Configuration} options webpack options * @param {(stats: CachingStats, files: Record<string, string>, iteration: number) => void} callback done callback * @returns {{ compilerInstance: import("../").Compiler, runAgain: (options: Record<string, unknown> | ((stats: CachingStats, files: Record<string, string>, iteration: number) => void), callback?: (stats: CachingStats, files: Record<string, string>, iteration: number) => void) => void }} helpers */ function compile(entry, options, callback) { const webpack = require(".."); /** @type {import("../").WebpackOptionsNormalized} */ const normalizedOptions = webpack.config.getNormalizedWebpackOptions(options); normalizedOptions.mode = "none"; normalizedOptions.cache = /** @type {import("../").WebpackOptionsNormalized["cache"]} */ ( /** @type {unknown} */ (true) ); normalizedOptions.entry = /** @type {import("../").EntryNormalized} */ ( /** @type {unknown} */ (entry) ); normalizedOptions.optimization.moduleIds = "natural"; normalizedOptions.optimization.minimize = false; normalizedOptions.context = path.join(__dirname, "fixtures"); normalizedOptions.output.path = "/"; normalizedOptions.output.filename = "bundle.js"; normalizedOptions.output.pathinfo = true; /** @type {CachingLogs} */ const logs = { mkdir: [], writeFile: [] }; const c = webpack( /** @type {import("../").Configuration} */ ( /** @type {unknown} */ (normalizedOptions) ) ); /** @type {Record<string, string>} */ const files = {}; c.outputFileSystem = /** @type {import("../").OutputFileSystem} */ ( /** @type {unknown} */ ({ /** * @param {string} dirPath directory path * @param {(err: NodeJS.ErrnoException) => void} cb callback */ mkdir(dirPath, cb) { logs.mkdir.push(dirPath); const err = /** @type {NodeJS.ErrnoException} */ (new Error("error")); err.code = "EEXIST"; cb(err); }, /** * @param {string} name file name * @param {Buffer} content file content * @param {() => void} cb callback */ writeFile(name, content, cb) { logs.writeFile.push(name, content); files[name] = content.toString("utf8"); cb(); }, /** * @param {string} _filePath file path * @param {(err: Error) => void} cb callback */ stat(_filePath, cb) { cb(new Error("ENOENT")); } }) ); c.hooks.compilation.tap( "CompilerCachingTest", (compilation) => (compilation.bail = true) ); let compilerIteration = 1; /** * @param {Record<string, unknown> | ((stats: CachingStats, files: Record<string, string>, iteration: number) => void)} options run options or callback * @param {((stats: CachingStats, files: Record<string, string>, iteration: number) => void)=} callback done callback */ function runCompiler(options, callback) { if (typeof options === "function") { callback = options; options = {}; } c.run((err, rawStats) => { if (err) throw err; expect(typeof rawStats).toBe("object"); const stats = /** @type {CachingStats} */ ( /** @type {import("../").Stats} */ (rawStats).toJson({ modules: true, reasons: true }) ); expect(typeof stats).toBe("object"); expect(stats).toHaveProperty("errors"); expect(Array.isArray(stats.errors)).toBe(true); if (/** @type {Record<string, unknown>} */ (options).expectErrors) { expect(stats.errors).toHaveLength( /** @type {number} */ ( /** @type {Record<string, unknown>} */ (options).expectErrors ) ); } else if (stats.errors && stats.errors.length > 0) { expect(typeof stats.errors[0]).toBe("string"); throw new Error( /** @type {string} */ (/** @type {unknown} */ (stats.errors[0])) ); } stats.logs = logs; /** @type {(stats: CachingStats, files: Record<string, string>, iteration: number) => void} */ ( callback )(stats, files, compilerIteration++); }); } runCompiler(callback); return { compilerInstance: c, runAgain: runCompiler }; } const tempFixturePath = path.join( __dirname, "fixtures", "temp-cache-fixture" ); /** * @returns {void} */ function cleanup() { rimraf.sync(`${tempFixturePath}-*`); } beforeAll(cleanup); afterAll(cleanup); /** * @returns {{ rootPath: string, aFilepath: string, cFilepath: string }} temp fixture paths */ function createTempFixture() { const fixturePath = `${tempFixturePath}-${fixtureCount}`; const aFilepath = path.join(fixturePath, "a.js"); const cFilepath = path.join(fixturePath, "c.js"); // Remove previous copy if present rimraf.sync(fixturePath); // Copy over file since we"ll be modifying some of them fs.mkdirSync(fixturePath); fs.copyFileSync(path.join(__dirname, "fixtures", "a.js"), aFilepath); fs.copyFileSync(path.join(__dirname, "fixtures", "c.js"), cFilepath); fixtureCount++; return { rootPath: fixturePath, aFilepath, cFilepath }; } it("should cache single file (with manual 1s wait)", (done) => { const options = {}; const tempFixture = createTempFixture(); const helper = compile(tempFixture.cFilepath, options, (stats, _files) => { // Not cached the first time expect(stats.assets[0].name).toBe("bundle.js"); expect(stats.assets[0].emitted).toBe(true); helper.runAgain((stats, _files, _iteration) => { // Cached the second run expect(stats.assets[0].name).toBe("bundle.js"); expect(stats.assets[0].emitted).toBe(false); const aContent = fs .readFileSync(tempFixture.aFilepath) .toString() .replace("This is a", "This is a MODIFIED"); setTimeout(() => { fs.writeFileSync(tempFixture.aFilepath, aContent); helper.runAgain((stats, _files, _iteration) => { // Cached the third run expect(stats.assets[0].name).toBe("bundle.js"); expect(stats.assets[0].emitted).toBe(true); done(); }); }, 1100); }); }); }); it("should cache single file (even with no timeout)", (done) => { const options = {}; const tempFixture = createTempFixture(); const helper = compile(tempFixture.cFilepath, options, (stats, _files) => { // Not cached the first time expect(stats.assets[0].name).toBe("bundle.js"); expect(stats.assets[0].emitted).toBe(true); helper.runAgain((stats, files, _iteration) => { // Cached the second run expect(stats.assets[0].name).toBe("bundle.js"); expect(stats.assets[0].emitted).toBe(false); expect(files["/bundle.js"]).toMatch("This is a"); const aContent = fs .readFileSync(tempFixture.aFilepath) .toString() .replace("This is a", "This is a MODIFIED"); fs.writeFileSync(tempFixture.aFilepath, aContent); helper.runAgain((stats, files, _iteration) => { // Cached the third run expect(stats.assets[0].name).toBe("bundle.js"); expect(stats.assets[0].emitted).toBe(true); expect(files["/bundle.js"]).toMatch("This is a MODIFIED"); done(); }); }); }); }); it("should only build when modified (with manual 2s wait)", (done) => { const options = {}; const tempFixture = createTempFixture(); const helper = compile(tempFixture.cFilepath, options, (stats, _files) => { // Built the first time expect(stats.modules[0].name).toMatch("c.js"); expect(stats.modules[0].built).toBe(true); expect(stats.modules[1].name).toMatch("a.js"); expect(stats.modules[1].built).toBe(true); setTimeout(() => { helper.runAgain((stats, _files, _iteration) => { // Not built when cached the second run expect(stats.modules[0].name).toMatch("c.js"); // expect(stats.modules[0].built).toBe(false); expect(stats.modules[1].name).toMatch("a.js"); // expect(stats.modules[1].built).toBe(false); const aContent = fs .readFileSync(tempFixture.aFilepath) .toString() .replace("This is a", "This is a MODIFIED"); setTimeout(() => { fs.writeFileSync(tempFixture.aFilepath, aContent); helper.runAgain((stats, _files, _iteration) => { // And only a.js built after it was modified expect(stats.modules[0].name).toMatch("c.js"); expect(stats.modules[0].built).toBe(false); expect(stats.modules[1].name).toMatch("a.js"); expect(stats.modules[1].built).toBe(true); done(); }); }, 2100); }); }, 4100); }); }); it("should build when modified (even with no timeout)", (done) => { const options = {}; const tempFixture = createTempFixture(); const helper = compile(tempFixture.cFilepath, options, (stats, _files) => { // Built the first time expect(stats.modules[0].name).toMatch("c.js"); expect(stats.modules[0].built).toBe(true); expect(stats.modules[1].name).toMatch("a.js"); expect(stats.modules[1].built).toBe(true); helper.runAgain((stats, _files, _iteration) => { // Not built when cached the second run expect(stats.modules[0].name).toMatch("c.js"); // expect(stats.modules[0].built).toBe(false); expect(stats.modules[1].name).toMatch("a.js"); // expect(stats.modules[1].built).toBe(false); const aContent = fs .readFileSync(tempFixture.aFilepath) .toString() .replace("This is a", "This is a MODIFIED"); fs.writeFileSync(tempFixture.aFilepath, aContent); helper.runAgain((stats, _files, _iteration) => { // And only a.js built after it was modified expect(stats.modules[0].name).toMatch("c.js"); // expect(stats.modules[0].built).toBe(false); expect(stats.modules[1].name).toMatch("a.js"); expect(stats.modules[1].built).toBe(true); done(); }); }); }); }); });