From b425189b359ac3de91c1282f608bb565dd7e4393 Mon Sep 17 00:00:00 2001 From: Hana Date: Mon, 6 May 2024 19:55:50 +0800 Subject: [PATCH] export `OutputFileSystem` --- crates/node_binding/binding.d.ts | 10 +- crates/rspack_fs_node/src/node.rs | 10 +- .../tests/build/issue-6359/rspack.config.js | 6 +- packages/rspack-dev-server/src/middleware.ts | 4 +- .../tests/normalizeOptions.test.ts | 4 +- packages/rspack-test-tools/etc/api.md | 2 + .../src/processor/snapshot.ts | 2 +- .../src/processor/stats-api.ts | 4 +- .../tests/errorCases/error-test-shift.js | 60 +- .../tests/errorCases/error-test-splice-1.js | 52 +- .../tests/errorCases/warning-test-push.js | 4 +- .../tests/errorCases/warning-test-shift.js | 4 +- .../tests/errorCases/warning-test-splice-1.js | 4 +- .../tests/errorCases/warning-test-splice-2.js | 4 +- .../tests/legacy-test/Output.test.js | 2 +- .../tests/statsAPICases/cache-disabled.js | 2 +- .../tests/statsAPICases/cache-enabled.js | 2 +- .../tests/statsAPICases/child-compiler.js | 1 + .../tests/statsAPICases/placeholders.js | 2 +- packages/rspack/etc/api.md | 195 ++- packages/rspack/src/ChunkGroup.ts | 13 +- packages/rspack/src/Compilation.ts | 1 - packages/rspack/src/Compiler.ts | 1241 +++++++++-------- packages/rspack/src/MultiCompiler.ts | 35 +- packages/rspack/src/Watching.ts | 5 +- .../src/builtin-plugin/SplitChunksPlugin.ts | 2 +- packages/rspack/src/config/adapterRuleUse.ts | 5 +- packages/rspack/src/exports.ts | 2 + packages/rspack/src/fileSystem.ts | 90 +- packages/rspack/src/loader-runner/index.ts | 22 +- packages/rspack/src/logging/Logger.ts | 2 +- .../rspack/src/node/NodeEnvironmentPlugin.ts | 2 +- packages/rspack/src/util/fs.ts | 206 +++ packages/rspack/src/util/index.ts | 9 + 34 files changed, 1181 insertions(+), 828 deletions(-) diff --git a/crates/node_binding/binding.d.ts b/crates/node_binding/binding.d.ts index a109fc6fa17..bb6d35b6e9c 100644 --- a/crates/node_binding/binding.d.ts +++ b/crates/node_binding/binding.d.ts @@ -1435,10 +1435,10 @@ export interface RegisterJsTaps { export function runBuiltinLoader(builtin: string, options: string | undefined | null, loaderContext: JsLoaderContext): Promise export interface ThreadsafeNodeFS { - writeFile: (name: string, content: Buffer) => void - removeFile: (name: string) => void - mkdir: (name: string) => void - mkdirp: (name: string) => string | void - removeDirAll: (name: string) => string | void + writeFile: (name: string, content: Buffer) => Promise | void + removeFile: (name: string) => Promise | void + mkdir: (name: string) => Promise | void + mkdirp: (name: string) => Promise | string | void + removeDirAll: (name: string) => Promise | string | void } diff --git a/crates/rspack_fs_node/src/node.rs b/crates/rspack_fs_node/src/node.rs index ad934d5067d..823aa022488 100644 --- a/crates/rspack_fs_node/src/node.rs +++ b/crates/rspack_fs_node/src/node.rs @@ -61,15 +61,15 @@ cfg_async! { #[napi(object, object_to_js = false, js_name = "ThreadsafeNodeFS")] pub struct ThreadsafeNodeFS { - #[napi(ts_type = "(name: string, content: Buffer) => void")] + #[napi(ts_type = "(name: string, content: Buffer) => Promise | void")] pub write_file: ThreadsafeFunction<(String, Buffer), ()>, - #[napi(ts_type = "(name: string) => void")] + #[napi(ts_type = "(name: string) => Promise | void")] pub remove_file: ThreadsafeFunction, - #[napi(ts_type = "(name: string) => void")] + #[napi(ts_type = "(name: string) => Promise | void")] pub mkdir: ThreadsafeFunction, - #[napi(ts_type = "(name: string) => string | void")] + #[napi(ts_type = "(name: string) => Promise | string | void")] pub mkdirp: ThreadsafeFunction>, - #[napi(ts_type = "(name: string) => string | void")] + #[napi(ts_type = "(name: string) => Promise | string | void")] pub remove_dir_all: ThreadsafeFunction>, } } diff --git a/packages/rspack-cli/tests/build/issue-6359/rspack.config.js b/packages/rspack-cli/tests/build/issue-6359/rspack.config.js index ef0d639ed64..0327f8f30ca 100644 --- a/packages/rspack-cli/tests/build/issue-6359/rspack.config.js +++ b/packages/rspack-cli/tests/build/issue-6359/rspack.config.js @@ -1,8 +1,12 @@ +const path = require("path"); const { WEBPACK_SERVE } = process.env; module.exports = /** @type {import('@rspack/cli').Configuration} */ { mode: "production", entry: "./entry.js", - output: { clean: true }, + output: { + clean: true, + path: path.resolve(__dirname, "dist") + }, plugins: [ { apply(compiler) { diff --git a/packages/rspack-dev-server/src/middleware.ts b/packages/rspack-dev-server/src/middleware.ts index d31d00cc901..b1d23670145 100644 --- a/packages/rspack-dev-server/src/middleware.ts +++ b/packages/rspack-dev-server/src/middleware.ts @@ -37,14 +37,14 @@ export function getRspackMemoryAssets( : // @ts-expect-error path.slice(1); const buffer = - compiler.getAsset(filename) ?? + compiler._lastCompilation?.getAsset(filename) ?? (() => { const { index } = rdm.context.options; const indexValue = typeof index === "undefined" || typeof index === "boolean" ? "index.html" : index; - return compiler.getAsset(filename + indexValue); + return compiler._lastCompilation?.getAsset(filename + indexValue); })(); if (!buffer) { return next(); diff --git a/packages/rspack-dev-server/tests/normalizeOptions.test.ts b/packages/rspack-dev-server/tests/normalizeOptions.test.ts index b8e5a14e438..d4915b2b9af 100644 --- a/packages/rspack-dev-server/tests/normalizeOptions.test.ts +++ b/packages/rspack-dev-server/tests/normalizeOptions.test.ts @@ -79,7 +79,7 @@ describe("normalize options snapshot", () => { }); const server = new RspackDevServer({}, compiler); await server.start(); - const hmrPlugins = compiler.builtinPlugins.filter( + const hmrPlugins = compiler.__internal__builtinPlugins.filter( p => p.name === "HotModuleReplacementPlugin" ); expect(hmrPlugins.length).toBe(1); @@ -149,7 +149,7 @@ async function getAdditionEntries( const server = new RspackDevServer(serverConfig, compiler); await server.start(); - const entries = compiler.builtinPlugins + const entries = compiler.__internal__builtinPlugins .filter(p => p.name === "EntryPlugin") .map(p => p.options) .reduce((acc, cur: any) => { diff --git a/packages/rspack-test-tools/etc/api.md b/packages/rspack-test-tools/etc/api.md index a6beaecc310..87fad291094 100644 --- a/packages/rspack-test-tools/etc/api.md +++ b/packages/rspack-test-tools/etc/api.md @@ -633,6 +633,8 @@ export interface IStatsAPITaskProcessorOptions { // (undocumented) check?: (stats: TCompilerStats, compiler: TCompiler) => Promise; // (undocumented) + compiler?: (context: ITestContext, compiler: TCompiler) => Promise; + // (undocumented) compilerType: T; // (undocumented) cwd?: string; diff --git a/packages/rspack-test-tools/src/processor/snapshot.ts b/packages/rspack-test-tools/src/processor/snapshot.ts index d8c5a47b64d..eebaf05006b 100644 --- a/packages/rspack-test-tools/src/processor/snapshot.ts +++ b/packages/rspack-test-tools/src/processor/snapshot.ts @@ -46,7 +46,7 @@ export class SnapshotProcessor< ); } const compilation = - (c as RspackCompiler).compilation || + (c as RspackCompiler)._lastCompilation || ( c as WebpackCompiler & { _lastCompilation: WebpackCompilation; diff --git a/packages/rspack-test-tools/src/processor/stats-api.ts b/packages/rspack-test-tools/src/processor/stats-api.ts index a98d7e76e10..6091094691e 100644 --- a/packages/rspack-test-tools/src/processor/stats-api.ts +++ b/packages/rspack-test-tools/src/processor/stats-api.ts @@ -16,6 +16,7 @@ export interface IStatsAPITaskProcessorOptions { name: string; cwd?: string; compilerType: T; + compiler?: (context: ITestContext, compiler: TCompiler) => Promise; build?: (context: ITestContext, compiler: TCompiler) => Promise; check?: (stats: TCompilerStats, compiler: TCompiler) => Promise; } @@ -28,7 +29,8 @@ export class StatsAPITaskProcessor< options: _statsAPIOptions.options, build: _statsAPIOptions.build, compilerType: _statsAPIOptions.compilerType, - name: _statsAPIOptions.name + name: _statsAPIOptions.name, + compiler: _statsAPIOptions.compiler }); } diff --git a/packages/rspack-test-tools/tests/errorCases/error-test-shift.js b/packages/rspack-test-tools/tests/errorCases/error-test-shift.js index d76f96cbfee..13d8caa0c71 100644 --- a/packages/rspack-test-tools/tests/errorCases/error-test-shift.js +++ b/packages/rspack-test-tools/tests/errorCases/error-test-shift.js @@ -1,33 +1,33 @@ /** @type {import('../..').TErrorCaseConfig} */ module.exports = { - description: "Testing proxy methods on errors: test shift&unshift", - options() { - return { - entry: "./resolve-fail-esm", - plugins: [ - compiler => { - compiler.hooks.afterCompile.tap( - "test shift and unshift", - compilation => { - compilation.errors.shift(); - compilation.errors.unshift("test unshift"); - } - ); - } - ] - }; - }, - async check(diagnostics) { - expect(diagnostics).toMatchInlineSnapshot(` - Object { - "errors": Array [ - Object { - "formatted": " × test unshift\\n", - "message": " × test unshift\\n", - }, - ], - "warnings": Array [], - } - `); - } + description: "Testing proxy methods on errors: test shift&unshift", + options() { + return { + entry: "./resolve-fail-esm", + plugins: [ + compiler => { + compiler.hooks.afterCompile.tap( + "test shift and unshift", + compilation => { + compilation.errors.shift(); + compilation.errors.unshift("test unshift"); + } + ); + } + ] + }; + }, + async check(diagnostics) { + expect(diagnostics).toMatchInlineSnapshot(` + Object { + "errors": Array [ + Object { + "formatted": " × test unshift\\n", + "message": " × test unshift\\n", + }, + ], + "warnings": Array [], + } + `); + } }; diff --git a/packages/rspack-test-tools/tests/errorCases/error-test-splice-1.js b/packages/rspack-test-tools/tests/errorCases/error-test-splice-1.js index 8c12c33cc9b..27769318b47 100644 --- a/packages/rspack-test-tools/tests/errorCases/error-test-splice-1.js +++ b/packages/rspack-test-tools/tests/errorCases/error-test-splice-1.js @@ -1,29 +1,29 @@ /** @type {import('../..').TErrorCaseConfig} */ module.exports = { - description: "Testing proxy methods on errors: test splice 1", - options() { - return { - entry: "./resolve-fail-esm", - plugins: [ - compiler => { - compiler.hooks.afterCompile.tap("test splice", compilation => { - compilation.errors.splice(0, 1, "test splice"); - }); - } - ] - }; - }, - async check(diagnostics) { - expect(diagnostics).toMatchInlineSnapshot(` - Object { - "errors": Array [ - Object { - "formatted": " × test splice\\n", - "message": " × test splice\\n", - }, - ], - "warnings": Array [], - } - `); - } + description: "Testing proxy methods on errors: test splice 1", + options() { + return { + entry: "./resolve-fail-esm", + plugins: [ + compiler => { + compiler.hooks.afterCompile.tap("test splice", compilation => { + compilation.errors.splice(0, 1, "test splice"); + }); + } + ] + }; + }, + async check(diagnostics) { + expect(diagnostics).toMatchInlineSnapshot(` + Object { + "errors": Array [ + Object { + "formatted": " × test splice\\n", + "message": " × test splice\\n", + }, + ], + "warnings": Array [], + } + `); + } }; diff --git a/packages/rspack-test-tools/tests/errorCases/warning-test-push.js b/packages/rspack-test-tools/tests/errorCases/warning-test-push.js index a13ba23db6a..4c0c5b655cf 100644 --- a/packages/rspack-test-tools/tests/errorCases/warning-test-push.js +++ b/packages/rspack-test-tools/tests/errorCases/warning-test-push.js @@ -19,8 +19,8 @@ module.exports = { "errors": Array [], "warnings": Array [ Object { - "formatted": " ⚠ Error: test push\\n │ at packages/rspack-test-tools/tests/errorCases/warning-test-push.js:10:33\\n │ at Hook.eval [as callAsync] (eval at create (node_modules/tapable/lib/HookCodeFactory.js:33:10), :9:1)\\n │ at Hook.CALL_ASYNC_DELEGATE [as _callAsync] (node_modules/tapable/lib/Hook.js:18:14)\\n │ at packages/rspack/dist/Compiler.js:419:41\\n │ at packages/rspack/dist/Compiler.js:751:65\\n", - "message": " ⚠ Error: test push\\n │ at packages/rspack-test-tools/tests/errorCases/warning-test-push.js:10:33\\n │ at Hook.eval [as callAsync] (eval at create (node_modules/tapable/lib/HookCodeFactory.js:33:10), :9:1)\\n │ at Hook.CALL_ASYNC_DELEGATE [as _callAsync] (node_modules/tapable/lib/Hook.js:18:14)\\n │ at packages/rspack/dist/Compiler.js:419:41\\n │ at packages/rspack/dist/Compiler.js:751:65\\n", + "formatted": " ⚠ Error: test push\\n │ at packages/rspack-test-tools/tests/errorCases/warning-test-push.js:10:33\\n │ at Hook.eval [as callAsync] (eval at create (node_modules/tapable/lib/HookCodeFactory.js:33:10), :9:1)\\n │ at Hook.CALL_ASYNC_DELEGATE [as _callAsync] (node_modules/tapable/lib/Hook.js:18:14)\\n │ at packages/rspack/dist/Compiler.js:466:41\\n │ at packages/rspack/dist/Compiler.js:533:65\\n", + "message": " ⚠ Error: test push\\n │ at packages/rspack-test-tools/tests/errorCases/warning-test-push.js:10:33\\n │ at Hook.eval [as callAsync] (eval at create (node_modules/tapable/lib/HookCodeFactory.js:33:10), :9:1)\\n │ at Hook.CALL_ASYNC_DELEGATE [as _callAsync] (node_modules/tapable/lib/Hook.js:18:14)\\n │ at packages/rspack/dist/Compiler.js:466:41\\n │ at packages/rspack/dist/Compiler.js:533:65\\n", }, Object { "formatted": " ⚠ Module parse warning:\\n ╰─▶ ⚠ Module parse failed: require.main.require() is not supported by Rspack.\\n ╭────\\n 1 │ require.main.require('./file');\\n · ──────────────────────────────\\n ╰────\\n \\n", diff --git a/packages/rspack-test-tools/tests/errorCases/warning-test-shift.js b/packages/rspack-test-tools/tests/errorCases/warning-test-shift.js index ed239f1456c..13469964ac8 100644 --- a/packages/rspack-test-tools/tests/errorCases/warning-test-shift.js +++ b/packages/rspack-test-tools/tests/errorCases/warning-test-shift.js @@ -23,8 +23,8 @@ module.exports = { "errors": Array [], "warnings": Array [ Object { - "formatted": " ⚠ Error: test unshift\\n │ at packages/rspack-test-tools/tests/errorCases/warning-test-shift.js:13:37\\n │ at Hook.eval [as callAsync] (eval at create (node_modules/tapable/lib/HookCodeFactory.js:33:10), :9:1)\\n │ at Hook.CALL_ASYNC_DELEGATE [as _callAsync] (node_modules/tapable/lib/Hook.js:18:14)\\n │ at packages/rspack/dist/Compiler.js:419:41\\n │ at packages/rspack/dist/Compiler.js:751:65\\n", - "message": " ⚠ Error: test unshift\\n │ at packages/rspack-test-tools/tests/errorCases/warning-test-shift.js:13:37\\n │ at Hook.eval [as callAsync] (eval at create (node_modules/tapable/lib/HookCodeFactory.js:33:10), :9:1)\\n │ at Hook.CALL_ASYNC_DELEGATE [as _callAsync] (node_modules/tapable/lib/Hook.js:18:14)\\n │ at packages/rspack/dist/Compiler.js:419:41\\n │ at packages/rspack/dist/Compiler.js:751:65\\n", + "formatted": " ⚠ Error: test unshift\\n │ at packages/rspack-test-tools/tests/errorCases/warning-test-shift.js:13:37\\n │ at Hook.eval [as callAsync] (eval at create (node_modules/tapable/lib/HookCodeFactory.js:33:10), :9:1)\\n │ at Hook.CALL_ASYNC_DELEGATE [as _callAsync] (node_modules/tapable/lib/Hook.js:18:14)\\n │ at packages/rspack/dist/Compiler.js:466:41\\n │ at packages/rspack/dist/Compiler.js:533:65\\n", + "message": " ⚠ Error: test unshift\\n │ at packages/rspack-test-tools/tests/errorCases/warning-test-shift.js:13:37\\n │ at Hook.eval [as callAsync] (eval at create (node_modules/tapable/lib/HookCodeFactory.js:33:10), :9:1)\\n │ at Hook.CALL_ASYNC_DELEGATE [as _callAsync] (node_modules/tapable/lib/Hook.js:18:14)\\n │ at packages/rspack/dist/Compiler.js:466:41\\n │ at packages/rspack/dist/Compiler.js:533:65\\n", }, ], } diff --git a/packages/rspack-test-tools/tests/errorCases/warning-test-splice-1.js b/packages/rspack-test-tools/tests/errorCases/warning-test-splice-1.js index f1b86d30985..78ce130bbbf 100644 --- a/packages/rspack-test-tools/tests/errorCases/warning-test-splice-1.js +++ b/packages/rspack-test-tools/tests/errorCases/warning-test-splice-1.js @@ -19,8 +19,8 @@ module.exports = { "errors": Array [], "warnings": Array [ Object { - "formatted": " ⚠ Error: test splice\\n │ at packages/rspack-test-tools/tests/errorCases/warning-test-splice-1.js:10:41\\n │ at Hook.eval [as callAsync] (eval at create (node_modules/tapable/lib/HookCodeFactory.js:33:10), :9:1)\\n │ at Hook.CALL_ASYNC_DELEGATE [as _callAsync] (node_modules/tapable/lib/Hook.js:18:14)\\n │ at packages/rspack/dist/Compiler.js:419:41\\n │ at packages/rspack/dist/Compiler.js:751:65\\n", - "message": " ⚠ Error: test splice\\n │ at packages/rspack-test-tools/tests/errorCases/warning-test-splice-1.js:10:41\\n │ at Hook.eval [as callAsync] (eval at create (node_modules/tapable/lib/HookCodeFactory.js:33:10), :9:1)\\n │ at Hook.CALL_ASYNC_DELEGATE [as _callAsync] (node_modules/tapable/lib/Hook.js:18:14)\\n │ at packages/rspack/dist/Compiler.js:419:41\\n │ at packages/rspack/dist/Compiler.js:751:65\\n", + "formatted": " ⚠ Error: test splice\\n │ at packages/rspack-test-tools/tests/errorCases/warning-test-splice-1.js:10:41\\n │ at Hook.eval [as callAsync] (eval at create (node_modules/tapable/lib/HookCodeFactory.js:33:10), :9:1)\\n │ at Hook.CALL_ASYNC_DELEGATE [as _callAsync] (node_modules/tapable/lib/Hook.js:18:14)\\n │ at packages/rspack/dist/Compiler.js:466:41\\n │ at packages/rspack/dist/Compiler.js:533:65\\n", + "message": " ⚠ Error: test splice\\n │ at packages/rspack-test-tools/tests/errorCases/warning-test-splice-1.js:10:41\\n │ at Hook.eval [as callAsync] (eval at create (node_modules/tapable/lib/HookCodeFactory.js:33:10), :9:1)\\n │ at Hook.CALL_ASYNC_DELEGATE [as _callAsync] (node_modules/tapable/lib/Hook.js:18:14)\\n │ at packages/rspack/dist/Compiler.js:466:41\\n │ at packages/rspack/dist/Compiler.js:533:65\\n", }, ], } diff --git a/packages/rspack-test-tools/tests/errorCases/warning-test-splice-2.js b/packages/rspack-test-tools/tests/errorCases/warning-test-splice-2.js index 016b2f215cd..3e9eed58e77 100644 --- a/packages/rspack-test-tools/tests/errorCases/warning-test-splice-2.js +++ b/packages/rspack-test-tools/tests/errorCases/warning-test-splice-2.js @@ -19,8 +19,8 @@ module.exports = { "errors": Array [], "warnings": Array [ Object { - "formatted": " ⚠ Error: test splice\\n │ at packages/rspack-test-tools/tests/errorCases/warning-test-splice-2.js:10:41\\n │ at Hook.eval [as callAsync] (eval at create (node_modules/tapable/lib/HookCodeFactory.js:33:10), :9:1)\\n │ at Hook.CALL_ASYNC_DELEGATE [as _callAsync] (node_modules/tapable/lib/Hook.js:18:14)\\n │ at packages/rspack/dist/Compiler.js:419:41\\n │ at packages/rspack/dist/Compiler.js:751:65\\n", - "message": " ⚠ Error: test splice\\n │ at packages/rspack-test-tools/tests/errorCases/warning-test-splice-2.js:10:41\\n │ at Hook.eval [as callAsync] (eval at create (node_modules/tapable/lib/HookCodeFactory.js:33:10), :9:1)\\n │ at Hook.CALL_ASYNC_DELEGATE [as _callAsync] (node_modules/tapable/lib/Hook.js:18:14)\\n │ at packages/rspack/dist/Compiler.js:419:41\\n │ at packages/rspack/dist/Compiler.js:751:65\\n", + "formatted": " ⚠ Error: test splice\\n │ at packages/rspack-test-tools/tests/errorCases/warning-test-splice-2.js:10:41\\n │ at Hook.eval [as callAsync] (eval at create (node_modules/tapable/lib/HookCodeFactory.js:33:10), :9:1)\\n │ at Hook.CALL_ASYNC_DELEGATE [as _callAsync] (node_modules/tapable/lib/Hook.js:18:14)\\n │ at packages/rspack/dist/Compiler.js:466:41\\n │ at packages/rspack/dist/Compiler.js:533:65\\n", + "message": " ⚠ Error: test splice\\n │ at packages/rspack-test-tools/tests/errorCases/warning-test-splice-2.js:10:41\\n │ at Hook.eval [as callAsync] (eval at create (node_modules/tapable/lib/HookCodeFactory.js:33:10), :9:1)\\n │ at Hook.CALL_ASYNC_DELEGATE [as _callAsync] (node_modules/tapable/lib/Hook.js:18:14)\\n │ at packages/rspack/dist/Compiler.js:466:41\\n │ at packages/rspack/dist/Compiler.js:533:65\\n", }, Object { "formatted": " ⚠ Module parse warning:\\n ╰─▶ ⚠ Module parse failed: require.main.require() is not supported by Rspack.\\n ╭────\\n 1 │ require.main.require('./file');\\n · ──────────────────────────────\\n ╰────\\n \\n", diff --git a/packages/rspack-test-tools/tests/legacy-test/Output.test.js b/packages/rspack-test-tools/tests/legacy-test/Output.test.js index 411f5c32808..4361e3df2d2 100644 --- a/packages/rspack-test-tools/tests/legacy-test/Output.test.js +++ b/packages/rspack-test-tools/tests/legacy-test/Output.test.js @@ -52,7 +52,7 @@ describe("Output", () => { }); it("should be cleared the build directory", done => { - const outputDist = "dist/output"; + const outputDist = path.resolve(__dirname, "../js/legacy-test/output-clear-build-directory"); compile( "./a", { diff --git a/packages/rspack-test-tools/tests/statsAPICases/cache-disabled.js b/packages/rspack-test-tools/tests/statsAPICases/cache-disabled.js index e8ec58e1e6b..d2f4dfcd7fc 100644 --- a/packages/rspack-test-tools/tests/statsAPICases/cache-disabled.js +++ b/packages/rspack-test-tools/tests/statsAPICases/cache-disabled.js @@ -33,7 +33,7 @@ module.exports = { }); }, async check(_, compiler) { - const stats = new Stats(compiler.compilation).toString({ + const stats = new Stats(compiler._lastCompilation).toString({ all: false, logging: "verbose" }); diff --git a/packages/rspack-test-tools/tests/statsAPICases/cache-enabled.js b/packages/rspack-test-tools/tests/statsAPICases/cache-enabled.js index 124b761be5c..d892d550cf4 100644 --- a/packages/rspack-test-tools/tests/statsAPICases/cache-enabled.js +++ b/packages/rspack-test-tools/tests/statsAPICases/cache-enabled.js @@ -34,7 +34,7 @@ module.exports = { }); }, async check(_, compiler) { - const stats = new Stats(compiler.compilation).toString({ + const stats = new Stats(compiler._lastCompilation).toString({ all: false, logging: "verbose" }); diff --git a/packages/rspack-test-tools/tests/statsAPICases/child-compiler.js b/packages/rspack-test-tools/tests/statsAPICases/child-compiler.js index cbb5acf74df..388f580381c 100644 --- a/packages/rspack-test-tools/tests/statsAPICases/child-compiler.js +++ b/packages/rspack-test-tools/tests/statsAPICases/child-compiler.js @@ -1,3 +1,4 @@ +const { createFsFromVolume, Volume } = require("memfs") let statsJson; class TestPlugin { diff --git a/packages/rspack-test-tools/tests/statsAPICases/placeholders.js b/packages/rspack-test-tools/tests/statsAPICases/placeholders.js index fd2e0a108b4..7f0a0bc6783 100644 --- a/packages/rspack-test-tools/tests/statsAPICases/placeholders.js +++ b/packages/rspack-test-tools/tests/statsAPICases/placeholders.js @@ -4,7 +4,7 @@ class TestPlugin { apply(compiler) { compiler.hooks.thisCompilation.tap("custom", compilation => { compilation.hooks.optimizeModules.tap("test plugin", () => { - stats = compiler.compilation.getStats().toJson({}); + stats = compiler._lastCompilation.getStats().toJson({}); }); }); } diff --git a/packages/rspack/etc/api.md b/packages/rspack/etc/api.md index cecb6bc9864..ecfb427ec69 100644 --- a/packages/rspack/etc/api.md +++ b/packages/rspack/etc/api.md @@ -19,10 +19,9 @@ import { RawEvalDevToolModulePluginOptions as EvalDevToolModulePluginOptions } f import { EventEmitter } from 'events'; import { cleanupGlobalTrace as experimental_cleanupGlobalTrace } from '@rspack/binding'; import { registerGlobalTrace as experimental_registerGlobalTrace } from '@rspack/binding'; -import { exports as exports_2 } from './exports'; import type { ExternalObject } from '@rspack/binding'; -import { fs } from 'fs'; -import { default as fs_2 } from 'graceful-fs'; +import fs from 'graceful-fs'; +import { fs as fs_2 } from 'fs'; import Hash = require('../util/hash'); import { HookMap as HookMap_2 } from 'tapable'; import { JsAssetInfo } from '@rspack/binding'; @@ -65,7 +64,6 @@ import { RawSourceMapDevToolPluginOptions } from '@rspack/binding'; import { RawSwcJsMinimizerRspackPluginOptions } from '@rspack/binding'; import { ResolveRequest } from 'enhanced-resolve'; import ResolverFactory = require('./ResolverFactory'); -import { rspack as rspack_3 } from './rspack'; import { RspackOptionsNormalized as RspackOptionsNormalized_2 } from '.'; import { Source } from 'webpack-sources'; import { SyncBailHook as SyncBailHook_2 } from 'tapable'; @@ -99,9 +97,6 @@ export type AmdContainer = z.infer; // @public (undocumented) const amdContainer: z.ZodString; -// @public (undocumented) -type Any = any; - // @public (undocumented) type Append = { 0: [U]; @@ -1176,23 +1171,21 @@ export interface CompilationParams { // @public (undocumented) export class Compiler { constructor(context: string, options: RspackOptionsNormalized); + // @internal + get __internal__builtinPlugins(): binding.BuiltinPlugin[]; // (undocumented) __internal__getModuleExecutionResult(id: number): any; // @internal __internal__rebuild(modifiedFiles?: ReadonlySet, removedFiles?: ReadonlySet, callback?: (error: Error | null) => void): void; // (undocumented) __internal__registerBuiltinPlugin(plugin: binding.BuiltinPlugin): void; - // (undocumented) - builtinPlugins: binding.BuiltinPlugin[]; + // @internal + get __internal__ruleSet(): RuleSetCompiler; // (undocumented) cache: Cache_2; // (undocumented) close(callback: (error?: Error | null) => void): void; // (undocumented) - compilation?: Compilation; - // (undocumented) - compilationParams?: CompilationParams; - // (undocumented) compile(callback: Callback_2): void; // (undocumented) compilerPath: string; @@ -1205,11 +1198,11 @@ export class Compiler { // (undocumented) fileTimestamps?: ReadonlyMap; // (undocumented) - getAsset(name: string): Buffer | null; + fsStartTime?: number; // (undocumented) getCache(name: string): CacheFacade; // (undocumented) - getInfrastructureLogger(name: string | Function): Logger; + getInfrastructureLogger(name: string | (() => string)): Logger; // (undocumented) hooks: { done: tapable.AsyncSeriesHook; @@ -1245,6 +1238,8 @@ export class Compiler { // (undocumented) idle: boolean; // (undocumented) + get immutablePaths(): never; + // (undocumented) infrastructureLogger: any; // (undocumented) inputFileSystem: any; @@ -1253,13 +1248,17 @@ export class Compiler { // (undocumented) isChild(): boolean; // (undocumented) + get _lastCompilation(): Compilation | undefined; + // (undocumented) + get managedPaths(): never; + // (undocumented) modifiedFiles?: ReadonlySet; // (undocumented) name?: string; // (undocumented) options: RspackOptionsNormalized; // (undocumented) - outputFileSystem: fs; + outputFileSystem: OutputFileSystem | null; // (undocumented) outputPath: string; // (undocumented) @@ -1267,32 +1266,33 @@ export class Compiler { // (undocumented) purgeInputFileSystem(): void; // (undocumented) + records: Record; + // (undocumented) + get recordsInputPath(): never; + // (undocumented) + get recordsOutputPath(): never; + // (undocumented) removedFiles?: ReadonlySet; // (undocumented) resolverFactory: ResolverFactory; // (undocumented) root: Compiler; // (undocumented) - ruleSet: RuleSetCompiler; - // (undocumented) run(callback: Callback_2): void; // (undocumented) - runAsChild(callback: any): void; + runAsChild(callback: (err?: null | Error, entries?: Chunk[], compilation?: Compilation) => any): void; // (undocumented) running: boolean; // (undocumented) watch(watchOptions: Watchpack.WatchOptions, handler: Callback_2): Watching; // (undocumented) - watchFileSystem: WatchFileSystem; + watchFileSystem: WatchFileSystem | null; // (undocumented) watching?: Watching; // (undocumented) watchMode: boolean; // (undocumented) - webpack: rspack_3 & exports_2 & { - rspack: rspack_3 & exports_2 & any; - webpack: rspack_3 & exports_2 & any; - }; + webpack: typeof rspack; } // @public (undocumented) @@ -1742,13 +1742,13 @@ class DirectoryWatcher extends EventEmitter { // (undocumented) nestedWatching: boolean; // (undocumented) - onChange(filePath: string, stat: fs_2.Stats): void; + onChange(filePath: string, stat: fs.Stats): void; // (undocumented) onDirectoryAdded(directoryPath: string): void; // (undocumented) onDirectoryUnlinked(directoryPath: string): void; // (undocumented) - onFileAdded(filePath: string, stat: fs_2.Stats): void; + onFileAdded(filePath: string, stat: fs.Stats): void; // (undocumented) onFileUnlinked(filePath: string): void; // (undocumented) @@ -1768,7 +1768,7 @@ class DirectoryWatcher extends EventEmitter { // (undocumented) watch(filePath: string, startTime: number): Watcher_2; // (undocumented) - watcher: fs_2.FSWatcher; + watcher: fs.FSWatcher; // (undocumented) watchers: { [path: string]: Watcher_2[]; @@ -3837,6 +3837,26 @@ const htmlRspackPluginOptions: z.ZodObject<{ meta?: Record> | undefined; }>; +// @public (undocumented) +interface IDirent { + // (undocumented) + isBlockDevice: () => boolean; + // (undocumented) + isCharacterDevice: () => boolean; + // (undocumented) + isDirectory: () => boolean; + // (undocumented) + isFIFO: () => boolean; + // (undocumented) + isFile: () => boolean; + // (undocumented) + isSocket: () => boolean; + // (undocumented) + isSymbolicLink: () => boolean; + // (undocumented) + name: string | Buffer; +} + // @public (undocumented) type IfSet = X extends UnsetAdditionalOptions ? {} : X; @@ -3910,6 +3930,60 @@ const infrastructureLogging: z.ZodObject<{ // @public (undocumented) type InnerCallback = (error?: E | null | false, result?: T) => void; +// @public (undocumented) +interface IStats { + // (undocumented) + atime: Date; + // (undocumented) + atimeMs: number | bigint; + // (undocumented) + birthtime: Date; + // (undocumented) + birthtimeMs: number | bigint; + // (undocumented) + blksize: number | bigint; + // (undocumented) + blocks: number | bigint; + // (undocumented) + ctime: Date; + // (undocumented) + ctimeMs: number | bigint; + // (undocumented) + dev: number | bigint; + // (undocumented) + gid: number | bigint; + // (undocumented) + ino: number | bigint; + // (undocumented) + isBlockDevice: () => boolean; + // (undocumented) + isCharacterDevice: () => boolean; + // (undocumented) + isDirectory: () => boolean; + // (undocumented) + isFIFO: () => boolean; + // (undocumented) + isFile: () => boolean; + // (undocumented) + isSocket: () => boolean; + // (undocumented) + isSymbolicLink: () => boolean; + // (undocumented) + mode: number | bigint; + // (undocumented) + mtime: Date; + // (undocumented) + mtimeMs: number | bigint; + // (undocumented) + nlink: number | bigint; + // (undocumented) + rdev: number | bigint; + // (undocumented) + size: number | bigint; + // (undocumented) + uid: number | bigint; +} + // @public (undocumented) interface JavaScript { // (undocumented) @@ -4382,7 +4456,7 @@ export interface LoaderContext { // (undocumented) clearDependencies(): void; // (undocumented) - _compilation: Compiler["compilation"]; + _compilation: Compilation; // (undocumented) _compiler: Compiler; // (undocumented) @@ -4532,7 +4606,7 @@ export interface LogEntry { } // @public (undocumented) -type LogFunction = (type: LogTypeEnum, args?: any[]) => void; +type LogFunction = (type: LogTypeEnum, args: any[]) => void; // @public (undocumented) class Logger { @@ -5391,8 +5465,6 @@ export class MultiCompiler { // (undocumented) compilers: Compiler[]; // (undocumented) - context: string; - // (undocumented) dependencies: WeakMap; // (undocumented) getInfrastructureLogger(name: string): Logger_2; @@ -5401,40 +5473,28 @@ export class MultiCompiler { done: SyncHook_2; invalid: MultiHook>; run: MultiHook>; - watchClose: SyncHook_2; - watchRun: MultiHook; - infrastructureLog: MultiHook; + watchClose: SyncHook_2<[]>; + watchRun: MultiHook>; + infrastructureLog: MultiHook>; }; // (undocumented) - infrastructureLogger: Any; - // (undocumented) get inputFileSystem(): void; set inputFileSystem(value: void); // (undocumented) - get intermediateFileSystem(): any; - set intermediateFileSystem(value: any); - // (undocumented) - name: string; + get intermediateFileSystem(): void; + set intermediateFileSystem(value: void); // (undocumented) - get options(): RspackOptionsNormalized_2[] & { - parallelism?: number | undefined; - }; + get options(): RspackOptionsNormalized_2[] & MultiCompilerOptions; // (undocumented) - _options: { - parallelism?: number; - }; + _options: MultiCompilerOptions; // (undocumented) - get outputFileSystem(): fs; - set outputFileSystem(value: fs); + get outputFileSystem(): fs_2; + set outputFileSystem(value: fs_2); // (undocumented) get outputPath(): string; // (undocumented) purgeInputFileSystem(): void; // (undocumented) - resolverFactory: ResolverFactory; - // (undocumented) - root: Compiler; - // (undocumented) run(callback: Callback_2): void; // (undocumented) running: boolean; @@ -5447,10 +5507,6 @@ export class MultiCompiler { // (undocumented) get watchFileSystem(): WatchFileSystem; set watchFileSystem(value: WatchFileSystem); - // (undocumented) - watching: Watching; - // (undocumented) - watchMode: boolean; } // @public (undocumented) @@ -6564,6 +6620,32 @@ const output: z.ZodObject<{ devtoolFallbackModuleFilenameTemplate?: string | ((args_0: any) => any) | undefined; }>; +// @public (undocumented) +export interface OutputFileSystem { + // (undocumented) + dirname?: (arg0: string) => string; + // (undocumented) + join?: (arg0: string, arg1: string) => string; + // (undocumented) + lstat?: (arg0: string, arg1: (arg0?: null | NodeJS.ErrnoException, arg1?: IStats) => void) => void; + // (undocumented) + mkdir: (arg0: string, arg1: (arg0?: null | NodeJS.ErrnoException) => void) => void; + // (undocumented) + readdir: (arg0: string, arg1: (arg0?: null | NodeJS.ErrnoException, arg1?: (string | Buffer)[] | IDirent[]) => void) => void; + // (undocumented) + readFile: (arg0: string, arg1: (arg0?: null | NodeJS.ErrnoException, arg1?: string | Buffer) => void) => void; + // (undocumented) + relative?: (arg0: string, arg1: string) => string; + // (undocumented) + rmdir: (arg0: string, arg1: (arg0?: null | NodeJS.ErrnoException) => void) => void; + // (undocumented) + stat: (arg0: string, arg1: (arg0?: null | NodeJS.ErrnoException, arg1?: IStats) => void) => void; + // (undocumented) + unlink: (arg0: string, arg1: (arg0?: null | NodeJS.ErrnoException) => void) => void; + // (undocumented) + writeFile: (arg0: string, arg1: string | Buffer, arg2: (arg0?: null | NodeJS.ErrnoException) => void) => void; +} + // @public (undocumented) export type OutputModule = z.infer; @@ -7492,6 +7574,7 @@ declare namespace rspackExports { sources, config, util, + OutputFileSystem, experimental_registerGlobalTrace, experimental_cleanupGlobalTrace, EntryOptionPlugin, diff --git a/packages/rspack/src/ChunkGroup.ts b/packages/rspack/src/ChunkGroup.ts index b44f7dda530..c0bdc8fb120 100644 --- a/packages/rspack/src/ChunkGroup.ts +++ b/packages/rspack/src/ChunkGroup.ts @@ -3,6 +3,7 @@ import { type JsChunkGroup, type JsCompilation } from "@rspack/binding"; + import { Chunk } from "./Chunk"; export class ChunkGroup { @@ -40,6 +41,12 @@ export class ChunkGroup { }); } + get chunks(): Chunk[] { + return this.#inner.chunks.map(c => + Chunk.__from_binding(c, this.#inner_compilation) + ); + } + get index(): number | undefined { return this.#inner.index; } @@ -48,12 +55,6 @@ export class ChunkGroup { return this.#inner.name; } - get chunks(): Chunk[] { - return this.#inner.chunks.map(c => - Chunk.__from_binding(c, this.#inner_compilation) - ); - } - __internal_inner_ukey() { return this.#inner.__inner_ukey; } diff --git a/packages/rspack/src/Compilation.ts b/packages/rspack/src/Compilation.ts index 6568262fd25..7e2d3350cca 100644 --- a/packages/rspack/src/Compilation.ts +++ b/packages/rspack/src/Compilation.ts @@ -814,7 +814,6 @@ BREAKING CHANGE: Asset processing hooks in Compilation has been merged into a si const logEntry: LogEntry = { time: Date.now(), type, - // @ts-expect-error args, // @ts-expect-error trace diff --git a/packages/rspack/src/Compiler.ts b/packages/rspack/src/Compiler.ts index bf9084bb6d5..08913452108 100644 --- a/packages/rspack/src/Compiler.ts +++ b/packages/rspack/src/Compiler.ts @@ -27,7 +27,7 @@ import { Compilation, CompilationParams } from "./Compilation"; import { ContextModuleFactory } from "./ContextModuleFactory"; import ResolverFactory = require("./ResolverFactory"); import ConcurrentCompilationError from "./error/ConcurrentCompilationError"; -import { createThreadsafeNodeFSFromRaw } from "./fileSystem"; +import { ThreadsafeWritableNodeFS } from "./fileSystem"; import Cache = require("./lib/Cache"); import CacheFacade = require("./lib/CacheFacade"); import { Logger } from "./logging/Logger"; @@ -35,7 +35,7 @@ import { NormalModuleCreateData, NormalModuleFactory } from "./NormalModuleFactory"; -import { WatchFileSystem } from "./util/fs"; +import { OutputFileSystem, WatchFileSystem } from "./util/fs"; import { checkVersion } from "./util/bindingVersionCheck"; import { Watching } from "./Watching"; import { @@ -57,6 +57,8 @@ import { canInherentFromParent } from "./builtin-plugin/base"; import ExecuteModulePlugin from "./ExecuteModulePlugin"; import { Chunk } from "./Chunk"; import { Source } from "webpack-sources"; +import { unsupported } from "./util"; +import { makePathsRelative } from "./util/identifier"; export interface AssetEmittedInfo { content: Buffer; @@ -68,39 +70,20 @@ export interface AssetEmittedInfo { class Compiler { #instance?: binding.Rspack; + #initial: boolean; + + #compilation?: Compilation; + #compilationParams?: CompilationParams; + + #builtinPlugins: binding.BuiltinPlugin[]; + + #moduleExecutionResultsMap: Map; + + #nonSkippableRegisters: binding.RegisterJsTapKind[]; + #registers?: binding.RegisterJsTaps; + + #ruleSet: RuleSetCompiler; - webpack = rspack; - compilation?: Compilation; - compilationParams?: CompilationParams; - // TODO: remove this after remove rebuild on the rust side. - #initial: boolean = true; - builtinPlugins: binding.BuiltinPlugin[]; - root: Compiler; - running: boolean; - idle: boolean; - resolverFactory: ResolverFactory; - infrastructureLogger: any; - watching?: Watching; - outputPath!: string; - name?: string; - inputFileSystem: any; - outputFileSystem: typeof import("fs"); - ruleSet: RuleSetCompiler; - // @ts-expect-error - watchFileSystem: WatchFileSystem; - intermediateFileSystem: any; - // @ts-expect-error - watchMode: boolean; - context: string; - cache: Cache; - compilerPath: string; - modifiedFiles?: ReadonlySet; - removedFiles?: ReadonlySet; - fileTimestamps?: ReadonlyMap; - contextTimestamps?: ReadonlyMap< - string, - FileSystemInfoEntry | "ignore" | null - >; hooks: { done: tapable.AsyncSeriesHook; afterDone: tapable.SyncHook; @@ -132,28 +115,50 @@ class Compiler { finishMake: liteTapable.AsyncSeriesHook<[Compilation]>; entryOption: tapable.SyncBailHook<[string, EntryNormalized], any>; }; - options: RspackOptionsNormalized; - #disabledHooks: string[]; - #nonSkippableRegisters: binding.RegisterJsTapKind[]; - #registers?: binding.RegisterJsTaps; + + webpack: typeof rspack; + name?: string; parentCompilation?: Compilation; + root: Compiler; + outputPath: string; - #moduleExecutionResultsMap: Map; + running: boolean; + idle: boolean; + resolverFactory: ResolverFactory; + infrastructureLogger: any; + watching?: Watching; + + inputFileSystem: any; + intermediateFileSystem: any; + outputFileSystem: OutputFileSystem | null; + watchFileSystem: WatchFileSystem | null; + + records: Record; + modifiedFiles?: ReadonlySet; + removedFiles?: ReadonlySet; + fileTimestamps?: ReadonlyMap; + contextTimestamps?: ReadonlyMap< + string, + FileSystemInfoEntry | "ignore" | null + >; + fsStartTime?: number; + + watchMode: boolean; + context: string; + cache: Cache; + compilerPath: string; + options: RspackOptionsNormalized; constructor(context: string, options: RspackOptionsNormalized) { - this.outputFileSystem = fs; - this.options = options; - this.cache = new Cache(); - this.compilerPath = ""; - this.builtinPlugins = []; - this.root = this; - this.ruleSet = new RuleSetCompiler(); - this.running = false; - this.idle = false; - this.context = context; - this.resolverFactory = new ResolverFactory(); - this.modifiedFiles = undefined; - this.removedFiles = undefined; + this.#initial = true; + + this.#builtinPlugins = []; + + this.#nonSkippableRegisters = []; + this.#moduleExecutionResultsMap = new Map(); + + this.#ruleSet = new RuleSetCompiler(); + this.hooks = { initialize: new SyncHook([]), shouldEmit: new liteTapable.SyncBailHook(["compilation"]), @@ -194,16 +199,71 @@ class Compiler { finishMake: new liteTapable.AsyncSeriesHook(["compilation"]), entryOption: new tapable.SyncBailHook(["context", "entry"]) }; - this.modifiedFiles = undefined; - this.removedFiles = undefined; - this.#disabledHooks = []; - this.#nonSkippableRegisters = []; - this.#moduleExecutionResultsMap = new Map(); + + this.webpack = rspack; + this.root = this; + this.outputPath = ""; + + this.inputFileSystem = null; + this.intermediateFileSystem = null; + this.outputFileSystem = null; + this.watchFileSystem = null; + + this.records = {}; + + this.resolverFactory = new ResolverFactory(); + this.options = options; + this.context = context; + this.cache = new Cache(); + + this.compilerPath = ""; + + this.running = false; + + this.idle = false; + + this.watchMode = false; new JsLoaderRspackPlugin(this).apply(this); new ExecuteModulePlugin().apply(this); } + get recordsInputPath() { + return unsupported("Compiler.recordsInputPath"); + } + + get recordsOutputPath() { + return unsupported("Compiler.recordsOutputPath"); + } + + get managedPaths() { + return unsupported("Compiler.managedPaths"); + } + + get immutablePaths() { + return unsupported("Compiler.immutablePaths"); + } + + get _lastCompilation() { + return this.#compilation; + } + + /** + * Note: This is not a webpack public API, maybe removed in future. + * @internal + */ + get __internal__builtinPlugins() { + return this.#builtinPlugins; + } + + /** + * Note: This is not a webpack public API, maybe removed in future. + * @internal + */ + get __internal__ruleSet() { + return this.#ruleSet; + } + /** * @param name - cache name * @returns the cache facade instance @@ -216,6 +276,447 @@ class Compiler { ); } + /** + * @param name - name of the logger, or function called once to get the logger name + * @returns a logger with that name + */ + getInfrastructureLogger(name: string | (() => string)) { + if (!name) { + throw new TypeError( + "Compiler.getInfrastructureLogger(name) called without a name" + ); + } + return new Logger( + (type, args) => { + if (typeof name === "function") { + name = name(); + if (!name) { + throw new TypeError( + "Compiler.getInfrastructureLogger(name) called with a function not returning a name" + ); + } + } else { + if ( + this.hooks.infrastructureLog.call(name, type, args) === undefined + ) { + if (this.infrastructureLogger !== undefined) { + this.infrastructureLogger(name, type, args); + } + } + } + }, + (childName): any => { + if (typeof name === "function") { + if (typeof childName === "function") { + // @ts-expect-error + return this.getInfrastructureLogger(_ => { + if (typeof name === "function") { + name = name(); + if (!name) { + throw new TypeError( + "Compiler.getInfrastructureLogger(name) called with a function not returning a name" + ); + } + } + if (typeof childName === "function") { + childName = childName(); + if (!childName) { + throw new TypeError( + "Logger.getChildLogger(name) called with a function not returning a name" + ); + } + } + return `${name}/${childName}`; + }); + } else { + return this.getInfrastructureLogger(() => { + if (typeof name === "function") { + name = name(); + if (!name) { + throw new TypeError( + "Compiler.getInfrastructureLogger(name) called with a function not returning a name" + ); + } + } + return `${name}/${childName}`; + }); + } + } else { + if (typeof childName === "function") { + return this.getInfrastructureLogger(() => { + if (typeof childName === "function") { + childName = childName(); + if (!childName) { + throw new TypeError( + "Logger.getChildLogger(name) called with a function not returning a name" + ); + } + } + return `${name}/${childName}`; + }); + } else { + return this.getInfrastructureLogger(`${name}/${childName}`); + } + } + } + ); + } + + /** + * @param watchOptions - the watcher's options + * @param handler - signals when the call finishes + * @returns a compiler watcher + */ + watch( + watchOptions: Watchpack.WatchOptions, + handler: Callback + ): Watching { + if (this.running) { + // @ts-expect-error + return handler(new ConcurrentCompilationError()); + } + this.running = true; + this.watchMode = true; + // @ts-expect-error + this.watching = new Watching(this, watchOptions, handler); + return this.watching; + } + + /** + * @param callback - signals when the call finishes + */ + run(callback: Callback) { + if (this.running) { + return callback(new ConcurrentCompilationError()); + } + const startTime = Date.now(); + this.running = true; + const doRun = () => { + // @ts-expect-error + const finalCallback = (err, stats?) => { + this.idle = true; + this.cache.beginIdle(); + this.idle = true; + this.running = false; + if (err) { + this.hooks.failed.call(err); + } + if (callback) { + callback(err, stats); + } + this.hooks.afterDone.call(stats); + }; + this.hooks.beforeRun.callAsync(this, err => { + if (err) { + return finalCallback(err); + } + this.hooks.run.callAsync(this, err => { + if (err) { + return finalCallback(err); + } + + this.compile(err => { + if (err) { + return finalCallback(err); + } + this.#compilation!.startTime = startTime; + this.#compilation!.endTime = Date.now(); + const stats = new Stats(this.#compilation!); + this.hooks.done.callAsync(stats, err => { + if (err) { + return finalCallback(err); + } else { + return finalCallback(null, stats); + } + }); + }); + }); + }); + }; + + if (this.idle) { + this.cache.endIdle(err => { + if (err) return callback(err); + + this.idle = false; + doRun(); + }); + } else { + doRun(); + } + } + + runAsChild( + callback: ( + err?: null | Error, + entries?: Chunk[], + compilation?: Compilation + ) => any + ) { + const finalCallback = ( + err: Error | null, + entries?: Chunk[], + compilation?: Compilation + ) => { + try { + callback(err, entries, compilation); + } catch (e) { + const err = new Error(`compiler.runAsChild callback error: ${e}`); + // err.details = e.stack; + this.parentCompilation!.errors.push(err); + // TODO: remove once this works + console.log(e); + } + }; + + this.compile((err, compilation) => { + if (err) { + return finalCallback(err); + } + + assertNotNill(compilation); + + this.parentCompilation!.children.push(compilation); + for (const { name, source, info } of compilation.getAssets()) { + // Do not emit asset if source is not available. + // Webpack will emit it anyway. + if (source) { + this.parentCompilation!.emitAsset(name, source, info); + } + } + + const entries = []; + for (const ep of compilation.entrypoints.values()) { + entries.push(...ep.chunks); + } + + return finalCallback(null, entries, compilation); + }); + } + + purgeInputFileSystem() { + if (this.inputFileSystem && this.inputFileSystem.purge) { + this.inputFileSystem.purge(); + } + } + + /** + * @param compilation - the compilation + * @param compilerName - the compiler's name + * @param compilerIndex - the compiler's index + * @param outputOptions - the output options + * @param plugins - the plugins to apply + * @returns a child compiler + */ + createChildCompiler( + compilation: Compilation, + compilerName: string, + compilerIndex: number, + outputOptions: OutputNormalized, + plugins: RspackPluginInstance[] + ): Compiler { + const options: RspackOptionsNormalized = { + ...this.options, + output: { + ...this.options.output, + ...outputOptions + }, + // TODO: check why we need to have builtins otherwise this.#instance will fail to initialize Rspack + builtins: this.options.builtins + }; + applyRspackOptionsDefaults(options); + const childCompiler = new Compiler(this.context, options); + childCompiler.name = compilerName; + childCompiler.outputPath = this.outputPath; + childCompiler.inputFileSystem = this.inputFileSystem; + childCompiler.outputFileSystem = null; + childCompiler.resolverFactory = this.resolverFactory; + childCompiler.modifiedFiles = this.modifiedFiles; + childCompiler.removedFiles = this.removedFiles; + childCompiler.fileTimestamps = this.fileTimestamps; + childCompiler.contextTimestamps = this.contextTimestamps; + childCompiler.fsStartTime = this.fsStartTime; + childCompiler.cache = this.cache; + childCompiler.compilerPath = `${this.compilerPath}${compilerName}|${compilerIndex}|`; + + const relativeCompilerName = makePathsRelative( + this.context, + compilerName, + this.root + ); + if (!this.records[relativeCompilerName]) { + this.records[relativeCompilerName] = []; + } + if (this.records[relativeCompilerName][compilerIndex]) { + childCompiler.records = this.records[relativeCompilerName][compilerIndex]; + } else { + this.records[relativeCompilerName].push((childCompiler.records = {})); + } + + childCompiler.parentCompilation = compilation; + childCompiler.root = this.root; + if (Array.isArray(plugins)) { + for (const plugin of plugins) { + if (plugin) { + plugin.apply(childCompiler); + } + } + } + + childCompiler.#builtinPlugins = [ + ...childCompiler.#builtinPlugins, + ...this.#builtinPlugins.filter( + plugin => plugin.canInherentFromParent === true + ) + ]; + + for (const name in this.hooks) { + if (canInherentFromParent(name as keyof Compiler["hooks"])) { + //@ts-ignore + if (childCompiler.hooks[name]) { + //@ts-ignore + childCompiler.hooks[name].taps = this.hooks[name].taps.slice(); + } + } + } + + compilation.hooks.childCompiler.call( + childCompiler, + compilerName, + compilerIndex + ); + + return childCompiler; + } + + isChild() { + const isRoot = this.root === this; + return !isRoot; + } + + compile(callback: Callback) { + const startTime = Date.now(); + const params = this.#newCompilationParams(); + this.hooks.beforeCompile.callAsync(params, (err: any) => { + if (err) { + return callback(err); + } + this.hooks.compile.call(params); + this.#resetThisCompilation(); + + this.#build(err => { + if (err) { + return callback(err); + } + this.#compilation!.startTime = startTime; + this.#compilation!.endTime = Date.now(); + this.hooks.afterCompile.callAsync(this.#compilation!, err => { + if (err) { + return callback(err); + } + return callback(null, this.#compilation); + }); + }); + }); + } + + close(callback: (error?: Error | null) => void) { + if (this.watching) { + // When there is still an active watching, close this #initial + this.watching.close(() => { + this.close(callback); + }); + return; + } + this.hooks.shutdown.callAsync(err => { + if (err) return callback(err); + this.cache.shutdown(callback); + }); + } + + #build(callback?: (error: Error | null) => void) { + this.#getInstance((error, instance) => { + if (error) { + return callback?.(error); + } + if (!this.#initial) { + instance!.rebuild( + Array.from(this.modifiedFiles || []), + Array.from(this.removedFiles || []), + error => { + if (error) { + return callback?.(error); + } + callback?.(null); + } + ); + return; + } + this.#initial = false; + instance!.build(error => { + if (error) { + return callback?.(error); + } + callback?.(null); + }); + }); + } + + /** + * Note: This is not a webpack public API, maybe removed in future. + * @internal + */ + __internal__rebuild( + modifiedFiles?: ReadonlySet, + removedFiles?: ReadonlySet, + callback?: (error: Error | null) => void + ) { + this.#getInstance((error, instance) => { + if (error) { + return callback?.(error); + } + instance!.rebuild( + Array.from(modifiedFiles || []), + Array.from(removedFiles || []), + error => { + if (error) { + return callback?.(error); + } + callback?.(null); + } + ); + }); + } + + #createCompilation(native: binding.JsCompilation): Compilation { + const compilation = new Compilation(this, native); + compilation.name = this.name; + this.#compilation = compilation; + return compilation; + } + + #resetThisCompilation() { + // reassign new compilation in thisCompilation + this.#compilation = undefined; + // ensure thisCompilation must call + this.hooks.thisCompilation.intercept({ + call: () => {} + }); + } + + #newCompilationParams(): CompilationParams { + const normalModuleFactory = new NormalModuleFactory(); + this.hooks.normalModuleFactory.call(normalModuleFactory); + const contextModuleFactory = new ContextModuleFactory(); + this.hooks.contextModuleFactory.call(contextModuleFactory); + const params = { + normalModuleFactory, + contextModuleFactory + }; + this.#compilationParams = params; + return params; + } + /** * Lazy initialize instance so it could access the changed options */ @@ -246,42 +747,42 @@ class Compiler { binding.RegisterJsTapKind.CompilerThisCompilation, () => this.hooks.thisCompilation, queried => (native: binding.JsCompilation) => { - if (this.compilation === undefined) { + if (this.#compilation === undefined) { this.#createCompilation(native); } - queried.call(this.compilation!, this.compilationParams!); + queried.call(this.#compilation!, this.#compilationParams!); } ), registerCompilerCompilationTaps: this.#createHookRegisterTaps( binding.RegisterJsTapKind.CompilerCompilation, () => this.hooks.compilation, queried => () => - queried.call(this.compilation!, this.compilationParams!) + queried.call(this.#compilation!, this.#compilationParams!) ), registerCompilerMakeTaps: this.#createHookRegisterTaps( binding.RegisterJsTapKind.CompilerMake, () => this.hooks.make, - queried => async () => await queried.promise(this.compilation!) + queried => async () => await queried.promise(this.#compilation!) ), registerCompilerFinishMakeTaps: this.#createHookRegisterTaps( binding.RegisterJsTapKind.CompilerFinishMake, () => this.hooks.finishMake, - queried => async () => await queried.promise(this.compilation!) + queried => async () => await queried.promise(this.#compilation!) ), registerCompilerShouldEmitTaps: this.#createHookRegisterTaps( binding.RegisterJsTapKind.CompilerShouldEmit, () => this.hooks.shouldEmit, - queried => () => queried.call(this.compilation!) + queried => () => queried.call(this.#compilation!) ), registerCompilerEmitTaps: this.#createHookRegisterTaps( binding.RegisterJsTapKind.CompilerEmit, () => this.hooks.emit, - queried => async () => await queried.promise(this.compilation!) + queried => async () => await queried.promise(this.#compilation!) ), registerCompilerAfterEmitTaps: this.#createHookRegisterTaps( binding.RegisterJsTapKind.CompilerAfterEmit, () => this.hooks.afterEmit, - queried => async () => await queried.promise(this.compilation!) + queried => async () => await queried.promise(this.#compilation!) ), registerCompilerAssetEmittedTaps: this.#createHookRegisterTaps( binding.RegisterJsTapKind.CompilerAssetEmitted, @@ -293,7 +794,7 @@ class Compiler { outputPath }: binding.JsAssetEmittedArgs) => { return queried.promise(filename, { - compilation: this.compilation!, + compilation: this.#compilation!, targetPath, outputPath, get source() { @@ -307,13 +808,13 @@ class Compiler { ), registerCompilationRuntimeModuleTaps: this.#createHookRegisterTaps( binding.RegisterJsTapKind.CompilationRuntimeModule, - () => this.compilation!.hooks.runtimeModule, + () => this.#compilation!.hooks.runtimeModule, queried => ({ module, chunk }: binding.JsRuntimeModuleArg) => { const originSource = module.source?.source; queried.call( module, - Chunk.__from_binding(chunk, this.compilation!) + Chunk.__from_binding(chunk, this.#compilation!) ); const newSource = module.source?.source; if (newSource && newSource !== originSource) { @@ -324,25 +825,25 @@ class Compiler { ), registerCompilationBuildModuleTaps: this.#createHookRegisterTaps( binding.RegisterJsTapKind.CompilationBuildModule, - () => this.compilation!.hooks.buildModule, + () => this.#compilation!.hooks.buildModule, queired => (m: binding.JsModule) => queired.call(Module.__from_binding(m)) ), registerCompilationStillValidModuleTaps: this.#createHookRegisterTaps( binding.RegisterJsTapKind.CompilationStillValidModule, - () => this.compilation!.hooks.stillValidModule, + () => this.#compilation!.hooks.stillValidModule, queired => (m: binding.JsModule) => queired.call(Module.__from_binding(m)) ), registerCompilationSucceedModuleTaps: this.#createHookRegisterTaps( binding.RegisterJsTapKind.CompilationSucceedModule, - () => this.compilation!.hooks.succeedModule, + () => this.#compilation!.hooks.succeedModule, queired => (m: binding.JsModule) => queired.call(Module.__from_binding(m)) ), registerCompilationExecuteModuleTaps: this.#createHookRegisterTaps( binding.RegisterJsTapKind.CompilationExecuteModule, - () => this.compilation!.hooks.executeModule, + () => this.#compilation!.hooks.executeModule, queried => ({ entry, @@ -416,66 +917,67 @@ class Compiler { ), registerCompilationFinishModulesTaps: this.#createHookRegisterTaps( binding.RegisterJsTapKind.CompilationFinishModules, - () => this.compilation!.hooks.finishModules, - queried => async () => await queried.promise(this.compilation!.modules) + () => this.#compilation!.hooks.finishModules, + queried => async () => await queried.promise(this.#compilation!.modules) ), registerCompilationOptimizeModulesTaps: this.#createHookRegisterTaps( binding.RegisterJsTapKind.CompilationOptimizeModules, - () => this.compilation!.hooks.optimizeModules, - queried => () => queried.call(this.compilation!.modules) + () => this.#compilation!.hooks.optimizeModules, + queried => () => queried.call(this.#compilation!.modules) ), registerCompilationAfterOptimizeModulesTaps: this.#createHookRegisterTaps( binding.RegisterJsTapKind.CompilationAfterOptimizeModules, - () => this.compilation!.hooks.afterOptimizeModules, - queried => () => queried.call(this.compilation!.modules) + () => this.#compilation!.hooks.afterOptimizeModules, + queried => () => queried.call(this.#compilation!.modules) ), registerCompilationOptimizeTreeTaps: this.#createHookRegisterTaps( binding.RegisterJsTapKind.CompilationOptimizeTree, - () => this.compilation!.hooks.optimizeTree, + () => this.#compilation!.hooks.optimizeTree, queried => async () => await queried.promise( - this.compilation!.chunks, - this.compilation!.modules + this.#compilation!.chunks, + this.#compilation!.modules ) ), registerCompilationOptimizeChunkModulesTaps: this.#createHookRegisterTaps( binding.RegisterJsTapKind.CompilationOptimizeChunkModules, - () => this.compilation!.hooks.optimizeChunkModules, + () => this.#compilation!.hooks.optimizeChunkModules, queried => async () => await queried.promise( - this.compilation!.chunks, - this.compilation!.modules + this.#compilation!.chunks, + this.#compilation!.modules ) ), registerCompilationChunkAssetTaps: this.#createHookRegisterTaps( binding.RegisterJsTapKind.CompilationChunkAsset, - () => this.compilation!.hooks.chunkAsset, + () => this.#compilation!.hooks.chunkAsset, queried => ({ chunk, filename }: binding.JsChunkAssetArgs) => queried.call( - Chunk.__from_binding(chunk, this.compilation!), + Chunk.__from_binding(chunk, this.#compilation!), filename ) ), registerCompilationProcessAssetsTaps: this.#createHookRegisterTaps( binding.RegisterJsTapKind.CompilationProcessAssets, - () => this.compilation!.hooks.processAssets, - queried => async () => await queried.promise(this.compilation!.assets) + () => this.#compilation!.hooks.processAssets, + queried => async () => await queried.promise(this.#compilation!.assets) ), registerCompilationAfterProcessAssetsTaps: this.#createHookRegisterTaps( binding.RegisterJsTapKind.CompilationAfterProcessAssets, - () => this.compilation!.hooks.afterProcessAssets, - queried => () => queried.call(this.compilation!.assets) + () => this.#compilation!.hooks.afterProcessAssets, + queried => () => queried.call(this.#compilation!.assets) ), registerCompilationAfterSealTaps: this.#createHookRegisterTaps( binding.RegisterJsTapKind.CompilationAfterSeal, - () => this.compilation!.hooks.afterSeal, + () => this.#compilation!.hooks.afterSeal, queried => async () => await queried.promise() ), registerNormalModuleFactoryBeforeResolveTaps: this.#createHookRegisterTaps( binding.RegisterJsTapKind.NormalModuleFactoryBeforeResolve, - () => this.compilationParams!.normalModuleFactory.hooks.beforeResolve, + () => + this.#compilationParams!.normalModuleFactory.hooks.beforeResolve, queried => async (resolveData: binding.JsBeforeResolveArgs) => { const normalizedResolveData: ResolveData = { request: resolveData.request, @@ -494,7 +996,7 @@ class Compiler { this.#createHookMapRegisterTaps( binding.RegisterJsTapKind.NormalModuleFactoryResolveForScheme, () => - this.compilationParams!.normalModuleFactory.hooks.resolveForScheme, + this.#compilationParams!.normalModuleFactory.hooks.resolveForScheme, queried => async (args: binding.JsResolveForSchemeArgs) => { const ret = await queried .for(args.scheme) @@ -504,7 +1006,7 @@ class Compiler { ), registerNormalModuleFactoryAfterResolveTaps: this.#createHookRegisterTaps( binding.RegisterJsTapKind.NormalModuleFactoryAfterResolve, - () => this.compilationParams!.normalModuleFactory.hooks.afterResolve, + () => this.#compilationParams!.normalModuleFactory.hooks.afterResolve, queried => async (arg: binding.JsAfterResolveData) => { const data: ResolveData = { request: arg.request, @@ -520,286 +1022,75 @@ class Compiler { ), registerNormalModuleFactoryCreateModuleTaps: this.#createHookRegisterTaps( binding.RegisterJsTapKind.NormalModuleFactoryCreateModule, - () => this.compilationParams!.normalModuleFactory.hooks.createModule, + () => this.#compilationParams!.normalModuleFactory.hooks.createModule, queried => async (args: binding.JsNormalModuleFactoryCreateModuleArgs) => { const data: NormalModuleCreateData = { ...args, - settings: {} - }; - await queried.promise(data, {}); - } - ), - registerContextModuleFactoryBeforeResolveTaps: - this.#createHookRegisterTaps( - binding.RegisterJsTapKind.ContextModuleFactoryBeforeResolve, - () => - this.compilationParams!.contextModuleFactory.hooks.beforeResolve, - queried => - async ( - bindingData: - | false - | binding.JsContextModuleFactoryBeforeResolveData - ) => { - return queried.promise(bindingData); - } - ), - registerContextModuleFactoryAfterResolveTaps: - this.#createHookRegisterTaps( - binding.RegisterJsTapKind.ContextModuleFactoryAfterResolve, - () => this.compilationParams!.contextModuleFactory.hooks.afterResolve, - queried => - async ( - bindingData: - | false - | binding.JsContextModuleFactoryAfterResolveData - ) => { - const data = bindingData - ? ({ - resource: bindingData.resource, - regExp: bindingData.regExp - ? new RegExp(bindingData.regExp) - : undefined, - request: bindingData.request, - context: bindingData.context, - // TODO: Dependencies are not fully supported yet; this is a placeholder to prevent errors in moment-locales-webpack-plugin. - dependencies: [] - } satisfies ContextModuleFactoryAfterResolveResult) - : false; - const ret = await queried.promise(data); - const result = ret - ? ({ - resource: ret.resource, - context: ret.context, - request: ret.request, - regExp: ret.regExp?.toString() - } satisfies binding.JsContextModuleFactoryAfterResolveData) - : false; - return result; - } - ) - }; - - this.#instance = new instanceBinding.Rspack( - rawOptions, - this.builtinPlugins, - this.#registers, - createThreadsafeNodeFSFromRaw(this.outputFileSystem) - ); - - callback(null, this.#instance); - } - - createChildCompiler( - compilation: Compilation, - compilerName: string, - compilerIndex: number, - outputOptions: OutputNormalized, - plugins: RspackPluginInstance[] - ): Compiler { - const options: RspackOptionsNormalized = { - ...this.options, - output: { - ...this.options.output, - ...outputOptions - }, - // TODO: check why we need to have builtins otherwise this.#instance will fail to initialize Rspack - builtins: this.options.builtins - }; - applyRspackOptionsDefaults(options); - const childCompiler = new Compiler(this.context, options); - childCompiler.name = compilerName; - childCompiler.outputPath = this.outputPath; - childCompiler.inputFileSystem = this.inputFileSystem; - // childCompiler.outputFileSystem = null; - childCompiler.resolverFactory = this.resolverFactory; - childCompiler.modifiedFiles = this.modifiedFiles; - childCompiler.removedFiles = this.removedFiles; - // childCompiler.fileTimestamps = this.fileTimestamps; - // childCompiler.contextTimestamps = this.contextTimestamps; - // childCompiler.fsStartTime = this.fsStartTime; - childCompiler.cache = this.cache; - childCompiler.compilerPath = `${this.compilerPath}${compilerName}|${compilerIndex}|`; - // childCompiler._backCompat = this._backCompat; - - // const relativeCompilerName = makePathsRelative( - // this.context, - // compilerName, - // this.root - // ); - // if (!this.records[relativeCompilerName]) { - // this.records[relativeCompilerName] = []; - // } - // if (this.records[relativeCompilerName][compilerIndex]) { - // childCompiler.records = this.records[relativeCompilerName][compilerIndex]; - // } else { - // this.records[relativeCompilerName].push((childCompiler.records = {})); - // } - - childCompiler.parentCompilation = compilation; - childCompiler.root = this.root; - if (Array.isArray(plugins)) { - for (const plugin of plugins) { - if (plugin) { - plugin.apply(childCompiler); - } - } - } - - childCompiler.builtinPlugins = [ - ...childCompiler.builtinPlugins, - ...this.builtinPlugins.filter( - plugin => plugin.canInherentFromParent === true - ) - ]; - - for (const name in this.hooks) { - if (canInherentFromParent(name as keyof Compiler["hooks"])) { - //@ts-ignore - if (childCompiler.hooks[name]) { - //@ts-ignore - childCompiler.hooks[name].taps = this.hooks[name].taps.slice(); - } - } - } - - compilation.hooks.childCompiler.call( - childCompiler, - compilerName, - compilerIndex - ); - - return childCompiler; - } - - runAsChild(callback: any) { - const finalCallback = ( - err: Error | null, - entries?: any, - compilation?: Compilation - ) => { - try { - callback(err, entries, compilation); - } catch (e) { - const err = new Error(`compiler.runAsChild callback error: ${e}`); - // err.details = e.stack; - this.parentCompilation!.errors.push(err); - // TODO: remove once this works - console.log(e); - } - }; - - this.compile((err, compilation) => { - if (err) { - return finalCallback(err); - } - - assertNotNill(compilation); - - this.parentCompilation!.children.push(compilation); - for (const { name, source, info } of compilation.getAssets()) { - // Do not emit asset if source is not available. - // Webpack will emit it anyway. - if (source) { - this.parentCompilation!.emitAsset(name, source, info); - } - } - - const entries = []; - for (const ep of compilation.entrypoints.values()) { - entries.push(...ep.getFiles()); - } - - return finalCallback(null, entries, compilation); - }); - } - - isChild(): boolean { - const isRoot = this.root === this; - return !isRoot; - } - - getInfrastructureLogger(name: string | Function) { - if (!name) { - throw new TypeError( - "Compiler.getInfrastructureLogger(name) called without a name" - ); - } - return new Logger( - (type, args) => { - if (typeof name === "function") { - name = name(); - if (!name) { - throw new TypeError( - "Compiler.getInfrastructureLogger(name) called with a function not returning a name" - ); - } - } else { - if ( - // @ts-expect-error - this.hooks.infrastructureLog.call(name, type, args) === undefined - ) { - if (this.infrastructureLogger !== undefined) { - this.infrastructureLogger(name, type, args); - } - } - } - }, - (childName): any => { - if (typeof name === "function") { - if (typeof childName === "function") { - // @ts-expect-error - return this.getInfrastructureLogger(_ => { - if (typeof name === "function") { - name = name(); - if (!name) { - throw new TypeError( - "Compiler.getInfrastructureLogger(name) called with a function not returning a name" - ); - } - } - if (typeof childName === "function") { - childName = childName(); - if (!childName) { - throw new TypeError( - "Logger.getChildLogger(name) called with a function not returning a name" - ); - } - } - return `${name}/${childName}`; - }); - } else { - return this.getInfrastructureLogger(() => { - if (typeof name === "function") { - name = name(); - if (!name) { - throw new TypeError( - "Compiler.getInfrastructureLogger(name) called with a function not returning a name" - ); - } - } - return `${name}/${childName}`; - }); - } - } else { - if (typeof childName === "function") { - return this.getInfrastructureLogger(() => { - if (typeof childName === "function") { - childName = childName(); - if (!childName) { - throw new TypeError( - "Logger.getChildLogger(name) called with a function not returning a name" - ); - } - } - return `${name}/${childName}`; - }); - } else { - return this.getInfrastructureLogger(`${name}/${childName}`); + settings: {} + }; + await queried.promise(data, {}); } - } - } + ), + registerContextModuleFactoryBeforeResolveTaps: + this.#createHookRegisterTaps( + binding.RegisterJsTapKind.ContextModuleFactoryBeforeResolve, + () => + this.#compilationParams!.contextModuleFactory.hooks.beforeResolve, + queried => + async ( + bindingData: + | false + | binding.JsContextModuleFactoryBeforeResolveData + ) => { + return queried.promise(bindingData); + } + ), + registerContextModuleFactoryAfterResolveTaps: + this.#createHookRegisterTaps( + binding.RegisterJsTapKind.ContextModuleFactoryAfterResolve, + () => + this.#compilationParams!.contextModuleFactory.hooks.afterResolve, + queried => + async ( + bindingData: + | false + | binding.JsContextModuleFactoryAfterResolveData + ) => { + const data = bindingData + ? ({ + resource: bindingData.resource, + regExp: bindingData.regExp + ? new RegExp(bindingData.regExp) + : undefined, + request: bindingData.request, + context: bindingData.context, + // TODO: Dependencies are not fully supported yet; this is a placeholder to prevent errors in moment-locales-webpack-plugin. + dependencies: [] + } satisfies ContextModuleFactoryAfterResolveResult) + : false; + const ret = await queried.promise(data); + const result = ret + ? ({ + resource: ret.resource, + context: ret.context, + request: ret.request, + regExp: ret.regExp?.toString() + } satisfies binding.JsContextModuleFactoryAfterResolveData) + : false; + return result; + } + ) + }; + + this.#instance = new instanceBinding.Rspack( + rawOptions, + this.#builtinPlugins, + this.#registers, + ThreadsafeWritableNodeFS.__into_binding(this.outputFileSystem!) ); + + callback(null, this.#instance); } #updateNonSkippableRegisters() { @@ -905,220 +1196,8 @@ class Compiler { return getTaps; } - run(callback: Callback) { - if (this.running) { - return callback(new ConcurrentCompilationError()); - } - const startTime = Date.now(); - this.running = true; - const doRun = () => { - // @ts-expect-error - const finalCallback = (err, stats?) => { - this.idle = true; - this.cache.beginIdle(); - this.idle = true; - this.running = false; - if (err) { - this.hooks.failed.call(err); - } - if (callback) { - callback(err, stats); - } - this.hooks.afterDone.call(stats); - }; - this.hooks.beforeRun.callAsync(this, err => { - if (err) { - return finalCallback(err); - } - this.hooks.run.callAsync(this, err => { - if (err) { - return finalCallback(err); - } - - this.compile(err => { - if (err) { - return finalCallback(err); - } - this.compilation!.startTime = startTime; - this.compilation!.endTime = Date.now(); - const stats = new Stats(this.compilation!); - this.hooks.done.callAsync(stats, err => { - if (err) { - return finalCallback(err); - } else { - return finalCallback(null, stats); - } - }); - }); - }); - }); - }; - - if (this.idle) { - this.cache.endIdle(err => { - if (err) return callback(err); - - this.idle = false; - doRun(); - }); - } else { - doRun(); - } - } - #build(callback?: (error: Error | null) => void) { - this.#getInstance((error, instance) => { - if (error) { - return callback?.(error); - } - if (!this.#initial) { - instance!.rebuild( - Array.from(this.modifiedFiles || []), - Array.from(this.removedFiles || []), - error => { - if (error) { - return callback?.(error); - } - callback?.(null); - } - ); - return; - } - this.#initial = false; - instance!.build(error => { - if (error) { - return callback?.(error); - } - callback?.(null); - }); - }); - } - - /** - * * Note: This is not a webpack public API, maybe removed in future. - * @internal - */ - __internal__rebuild( - modifiedFiles?: ReadonlySet, - removedFiles?: ReadonlySet, - callback?: (error: Error | null) => void - ) { - this.#getInstance((error, instance) => { - if (error) { - return callback?.(error); - } - instance!.rebuild( - Array.from(modifiedFiles || []), - Array.from(removedFiles || []), - error => { - if (error) { - return callback?.(error); - } - callback?.(null); - } - ); - }); - } - - #createCompilation(native: binding.JsCompilation): Compilation { - const compilation = new Compilation(this, native); - compilation.name = this.name; - this.compilation = compilation; - return compilation; - } - - #resetThisCompilation() { - // reassign new compilation in thisCompilation - this.compilation = undefined; - // ensure thisCompilation must call - this.hooks.thisCompilation.intercept({ - call: () => {} - }); - } - - #newCompilationParams(): CompilationParams { - const normalModuleFactory = new NormalModuleFactory(); - this.hooks.normalModuleFactory.call(normalModuleFactory); - const contextModuleFactory = new ContextModuleFactory(); - this.hooks.contextModuleFactory.call(contextModuleFactory); - const params = { - normalModuleFactory, - contextModuleFactory - }; - this.compilationParams = params; - return params; - } - - compile(callback: Callback) { - const startTime = Date.now(); - const params = this.#newCompilationParams(); - this.hooks.beforeCompile.callAsync(params, (err: any) => { - if (err) { - return callback(err); - } - this.hooks.compile.call(params); - this.#resetThisCompilation(); - - this.#build(err => { - if (err) { - return callback(err); - } - this.compilation!.startTime = startTime; - this.compilation!.endTime = Date.now(); - this.hooks.afterCompile.callAsync(this.compilation!, err => { - if (err) { - return callback(err); - } - return callback(null, this.compilation); - }); - }); - }); - } - - watch( - watchOptions: Watchpack.WatchOptions, - handler: Callback - ): Watching { - if (this.running) { - // @ts-expect-error - return handler(new ConcurrentCompilationError()); - } - this.running = true; - this.watchMode = true; - // @ts-expect-error - this.watching = new Watching(this, watchOptions, handler); - return this.watching; - } - - purgeInputFileSystem() { - if (this.inputFileSystem && this.inputFileSystem.purge) { - this.inputFileSystem.purge(); - } - } - - close(callback: (error?: Error | null) => void) { - if (this.watching) { - // When there is still an active watching, close this #initial - this.watching.close(() => { - this.close(callback); - }); - return; - } - this.hooks.shutdown.callAsync(err => { - if (err) return callback(err); - this.cache.shutdown(callback); - }); - } - - getAsset(name: string) { - let source = this.compilation!.__internal__getAssetSource(name); - if (!source) { - return null; - } - return source.buffer(); - } - __internal__registerBuiltinPlugin(plugin: binding.BuiltinPlugin) { - this.builtinPlugins.push(plugin); + this.#builtinPlugins.push(plugin); } __internal__getModuleExecutionResult(id: number) { diff --git a/packages/rspack/src/MultiCompiler.ts b/packages/rspack/src/MultiCompiler.ts index e4545087273..e8defa8213b 100644 --- a/packages/rspack/src/MultiCompiler.ts +++ b/packages/rspack/src/MultiCompiler.ts @@ -9,10 +9,14 @@ */ import { Compiler, RspackOptions, Stats } from "."; -import ResolverFactory = require("./ResolverFactory"); import { WatchFileSystem } from "./util/fs"; -import { Watching } from "./Watching"; -import { AsyncSeriesHook, Callback, MultiHook, SyncHook } from "tapable"; +import { + AsyncSeriesHook, + Callback, + MultiHook, + SyncBailHook, + SyncHook +} from "tapable"; import MultiStats from "./MultiStats"; import asyncLib from "neo-async"; import ArrayQueue from "./util/ArrayQueue"; @@ -20,8 +24,6 @@ import ConcurrentCompilationError from "./error/ConcurrentCompilationError"; import MultiWatching from "./MultiWatching"; import { WatchOptions } from "./config"; -type Any = any; - interface Node { compiler: Compiler; children: Node[]; @@ -49,31 +51,18 @@ export type MultiRspackOptions = ReadonlyArray & MultiCompilerOptions; export class MultiCompiler { - // @ts-expect-error - context: string; compilers: Compiler[]; dependencies: WeakMap; hooks: { done: SyncHook; invalid: MultiHook>; run: MultiHook>; - watchClose: SyncHook; - watchRun: MultiHook; - infrastructureLog: MultiHook; + watchClose: SyncHook<[]>; + watchRun: MultiHook>; + infrastructureLog: MultiHook>; }; - // @ts-expect-error - name: string; - infrastructureLogger: Any; - _options: { parallelism?: number }; - // @ts-expect-error - root: Compiler; - // @ts-expect-error - resolverFactory: ResolverFactory; + _options: MultiCompilerOptions; running: boolean; - // @ts-expect-error - watching: Watching; - // @ts-expect-error - watchMode: boolean; constructor( compilers: Compiler[] | Record, @@ -190,7 +179,7 @@ export class MultiCompiler { } } - set intermediateFileSystem(value: any) { + set intermediateFileSystem(value) { for (const compiler of this.compilers) { compiler.intermediateFileSystem = value; } diff --git a/packages/rspack/src/Watching.ts b/packages/rspack/src/Watching.ts index d743771720c..7d5d66df6c9 100644 --- a/packages/rspack/src/Watching.ts +++ b/packages/rspack/src/Watching.ts @@ -75,7 +75,8 @@ export class Watching { missing: Iterable ) { this.pausedWatcher = undefined; - this.watcher = this.compiler.watchFileSystem.watch( + // SAFETY: `watchFileSystem` is expected to be initialized. + this.watcher = this.compiler.watchFileSystem!.watch( files, dirs, missing, @@ -275,7 +276,7 @@ export class Watching { const onCompile = (err: Error | null) => { if (err) return this._done(err, null); // if (this.invalid) return this._done(null); - this._done(null, this.compiler.compilation!); + this._done(null, this.compiler._lastCompilation!); }; this.compiler.compile(onCompile); diff --git a/packages/rspack/src/builtin-plugin/SplitChunksPlugin.ts b/packages/rspack/src/builtin-plugin/SplitChunksPlugin.ts index 5ffd87cdd48..750238ffb3c 100644 --- a/packages/rspack/src/builtin-plugin/SplitChunksPlugin.ts +++ b/packages/rspack/src/builtin-plugin/SplitChunksPlugin.ts @@ -78,7 +78,7 @@ function toRawSplitChunksOptions( chunks( Chunk.__from_binding( chunk, - compiler.compilation!.__internal_getInner() + compiler._lastCompilation!.__internal_getInner() ) ); } else { diff --git a/packages/rspack/src/config/adapterRuleUse.ts b/packages/rspack/src/config/adapterRuleUse.ts index bf443acaee7..2003cd9e1dc 100644 --- a/packages/rspack/src/config/adapterRuleUse.ts +++ b/packages/rspack/src/config/adapterRuleUse.ts @@ -18,6 +18,7 @@ import { resolveReact, resolveRelay } from "../builtin-loader"; +import { Compilation } from "../Compilation"; const BUILTIN_LOADER_PREFIX = "builtin:"; @@ -154,7 +155,7 @@ export interface LoaderContext { query: string | OptionsType; data: unknown; _compiler: Compiler; - _compilation: Compiler["compilation"]; + _compilation: Compilation; /** * Internal field for interoperability. * Do not use this in anywhere else. @@ -313,7 +314,7 @@ function resolveStringifyLoaders( if (use.options && typeof use.options === "object") { if (!ident) ident = "[[missing ident]]"; - compiler.ruleSet.references.set(ident, use.options); + compiler.__internal__ruleSet.references.set(ident, use.options); } return obj.path + obj.query + obj.fragment; diff --git a/packages/rspack/src/exports.ts b/packages/rspack/src/exports.ts index 1ed69d78c8d..45a210c421a 100644 --- a/packages/rspack/src/exports.ts +++ b/packages/rspack/src/exports.ts @@ -81,6 +81,8 @@ import { createHash } from "./util/createHash"; import { cachedCleverMerge as cleverMerge } from "./util/cleverMerge"; export const util = { createHash, cleverMerge }; +export { type OutputFileSystem } from "./util/fs"; + export { registerGlobalTrace as experimental_registerGlobalTrace, cleanupGlobalTrace as experimental_cleanupGlobalTrace diff --git a/packages/rspack/src/fileSystem.ts b/packages/rspack/src/fileSystem.ts index 9d1743a7625..2f455593ce2 100644 --- a/packages/rspack/src/fileSystem.ts +++ b/packages/rspack/src/fileSystem.ts @@ -1,66 +1,40 @@ import util from "util"; -import { join } from "path"; +import { ThreadsafeNodeFS } from "@rspack/binding"; + import { memoizeFn } from "./util/memoize"; +import { OutputFileSystem, rmrf, mkdirp } from "./util/fs"; -export interface ThreadsafeWritableNodeFS { - writeFile: (...args: any[]) => any; - removeFile: (...args: any[]) => any; - mkdir: (...args: any[]) => any; - mkdirp: (...args: any[]) => any; - removeDirAll: (...args: any[]) => any; -} +const NOOP_FILESYSTEM: ThreadsafeNodeFS = { + writeFile() {}, + removeFile() {}, + mkdir() {}, + mkdirp() {}, + removeDirAll() {} +}; -function createThreadsafeNodeFSFromRaw( - fs: typeof import("fs") -): ThreadsafeWritableNodeFS { - let writeFile = memoizeFn(() => util.promisify(fs.writeFile.bind(fs))); - let removeFile = memoizeFn(() => util.promisify(fs.unlink.bind(fs))); - let mkdir = memoizeFn(() => util.promisify(fs.mkdir.bind(fs))); - return { - writeFile, - removeFile, - mkdir, - mkdirp: dir => { - return mkdir(dir, { - recursive: true - }); - }, - removeDirAll: dir => { - // memfs don't support rmSync - return rmrfBuild(fs)(dir); - } - }; -} +class ThreadsafeWritableNodeFS implements ThreadsafeNodeFS { + writeFile!: (name: string, content: Buffer) => Promise | void; + removeFile!: (name: string) => Promise | void; + mkdir!: (name: string) => Promise | void; + mkdirp!: (name: string) => Promise | string | void; + removeDirAll!: (name: string) => Promise | string | void; -const rmrfBuild = (fs: typeof import("fs")) => { - async function exists(path: string) { - try { - await util.promisify(fs.access.bind(fs))(path); - return true; - } catch { - return false; + constructor(fs?: OutputFileSystem) { + if (!fs) { + // This happens when located in a child compiler. + Object.assign(this, NOOP_FILESYSTEM); + return; } + this.writeFile = memoizeFn(() => util.promisify(fs.writeFile.bind(fs))); + this.removeFile = memoizeFn(() => util.promisify(fs.unlink.bind(fs))); + this.mkdir = memoizeFn(() => util.promisify(fs.mkdir.bind(fs))); + this.mkdirp = memoizeFn(() => util.promisify(mkdirp.bind(null, fs))); + this.removeDirAll = memoizeFn(() => util.promisify(rmrf.bind(null, fs))); } - const rmrf = async (dir: string) => { - if (await exists(dir)) { - const files = await util.promisify(fs.readdir.bind(fs))(dir); - await Promise.all( - files - .map(f => join(dir, f)) - .map(async filePath => { - if ( - (await util.promisify(fs.lstat.bind(fs))(filePath)).isDirectory() - ) { - await rmrf(filePath); - } else { - await util.promisify(fs.unlink.bind(fs))(filePath); - } - }) - ); - await util.promisify(fs.rmdir.bind(fs))(dir); - } - }; - return rmrf; -}; -export { createThreadsafeNodeFSFromRaw }; + static __into_binding(fs?: OutputFileSystem) { + return new this(fs); + } +} + +export { ThreadsafeWritableNodeFS }; diff --git a/packages/rspack/src/loader-runner/index.ts b/packages/rspack/src/loader-runner/index.ts index 69bf0f64d10..3edf00fc0f4 100644 --- a/packages/rspack/src/loader-runner/index.ts +++ b/packages/rspack/src/loader-runner/index.ts @@ -193,7 +193,7 @@ export async function runLoaders( "provide an 'ident' property for referenced loader options." ); } - obj.options = compiler.ruleSet.references.get(ident); + obj.options = compiler.__internal__ruleSet.references.get(ident); if (obj.options === undefined) { throw new Error( `Invalid ident("${ident}") is provided by referenced loader` @@ -250,7 +250,7 @@ export async function runLoaders( if (!callback) { return new Promise((resolve, reject) => { compiler - .compilation!.__internal_getInner() + ._lastCompilation!.__internal_getInner() .importModule( request, options.publicPath, @@ -281,7 +281,7 @@ export async function runLoaders( }); } return compiler - .compilation!.__internal_getInner() + ._lastCompilation!.__internal_getInner() .importModule( request, options.publicPath, @@ -461,7 +461,7 @@ export async function runLoaders( }; }; loaderContext.getLogger = function getLogger(name) { - return compiler.compilation!.getLogger( + return compiler._lastCompilation!.getLogger( [name, resource].filter(Boolean).join("|") ); }; @@ -470,7 +470,7 @@ export async function runLoaders( const title = "Module Error"; const message = error instanceof Error ? concatErrorMsgAndStack(error) : error; - compiler.compilation!.pushDiagnostic( + compiler._lastCompilation!.pushDiagnostic( "error", title, `${message}\n(from: ${stringifyLoaderObject( @@ -482,7 +482,7 @@ export async function runLoaders( const title = "Module Warning"; const message = warning instanceof Error ? concatErrorMsgAndStack(warning) : warning; - compiler.compilation!.pushDiagnostic( + compiler._lastCompilation!.pushDiagnostic( "warning", title, `${message}\n(from: ${stringifyLoaderObject( @@ -492,7 +492,7 @@ export async function runLoaders( }; loaderContext.__internal__pushNativeDiagnostics = function __internal__pushNativeDiagnostics(diagnostics) { - compiler.compilation!.__internal__pushNativeDiagnostics(diagnostics); + compiler._lastCompilation!.__internal__pushNativeDiagnostics(diagnostics); }; loaderContext.emitFile = function emitFile( name, @@ -530,7 +530,7 @@ export async function runLoaders( } assetFilenames.push(name), // @ts-expect-error - compiler.compilation.emitAsset(name, source, assetInfo); + compiler._lastCompilation.emitAsset(name, source, assetInfo); }; loaderContext.fs = compiler.inputFileSystem; @@ -556,7 +556,7 @@ export async function runLoaders( }, createHash: type => { return createHash( - type || compiler.compilation!.outputOptions.hashFunction + type || compiler._lastCompilation!.outputOptions.hashFunction ); } }; @@ -590,7 +590,7 @@ export async function runLoaders( return missingDependencies.slice(); }; loaderContext._compiler = compiler; - loaderContext._compilation = compiler.compilation; + loaderContext._compilation = compiler._lastCompilation!; loaderContext.getOptions = function () { const loader = getCurrentLoader(loaderContext); let options = loader?.options; @@ -615,7 +615,7 @@ export async function runLoaders( return options; }; - let compilation: Compilation | undefined = compiler.compilation; + let compilation: Compilation | undefined = compiler._lastCompilation; let step = 0; while (compilation) { NormalModule.getCompilationHooks(compilation).loader.call(loaderContext); diff --git a/packages/rspack/src/logging/Logger.ts b/packages/rspack/src/logging/Logger.ts index f291c0f03f8..eb72b37d469 100644 --- a/packages/rspack/src/logging/Logger.ts +++ b/packages/rspack/src/logging/Logger.ts @@ -45,7 +45,7 @@ const LOG_SYMBOL = Symbol("webpack logger raw log method"); const TIMERS_SYMBOL = Symbol("webpack logger times"); const TIMERS_AGGREGATES_SYMBOL = Symbol("webpack logger aggregated times"); -export type LogFunction = (type: LogTypeEnum, args?: any[]) => void; +export type LogFunction = (type: LogTypeEnum, args: any[]) => void; export type GetChildLogger = (name: string | (() => string)) => Logger; export class Logger { diff --git a/packages/rspack/src/node/NodeEnvironmentPlugin.ts b/packages/rspack/src/node/NodeEnvironmentPlugin.ts index 87b3aaa2fb3..20379e50c27 100644 --- a/packages/rspack/src/node/NodeEnvironmentPlugin.ts +++ b/packages/rspack/src/node/NodeEnvironmentPlugin.ts @@ -49,7 +49,7 @@ export default class NodeEnvironmentPlugin { ); compiler.hooks.beforeRun.tap("NodeEnvironmentPlugin", compiler => { if (compiler.inputFileSystem === inputFileSystem) { - (compiler as any).fsStartTime = Date.now(); + compiler.fsStartTime = Date.now(); inputFileSystem.purge(); } }); diff --git a/packages/rspack/src/util/fs.ts b/packages/rspack/src/util/fs.ts index a9b8781410d..c957cb397c8 100644 --- a/packages/rspack/src/util/fs.ts +++ b/packages/rspack/src/util/fs.ts @@ -1,3 +1,16 @@ +/** + * The following code is modified based on + * https://github.com/webpack/webpack/blob/4b4ca3b/lib/util/fs.js + * + * MIT Licensed + * Author Tobias Koppers @sokra + * Copyright (c) JS Foundation and other contributors + * https://github.com/webpack/webpack/blob/main/LICENSE + */ + +import path from "path"; +import assert from "assert"; + import { WatchOptions } from "../config"; export interface Watcher { @@ -17,6 +30,199 @@ export interface WatcherInfo { contextTimeInfoEntries: Map; // get info about directories } +interface IDirent { + isFile: () => boolean; + isDirectory: () => boolean; + isBlockDevice: () => boolean; + isCharacterDevice: () => boolean; + isSymbolicLink: () => boolean; + isFIFO: () => boolean; + isSocket: () => boolean; + name: string | Buffer; +} + +interface IStats { + isFile: () => boolean; + isDirectory: () => boolean; + isBlockDevice: () => boolean; + isCharacterDevice: () => boolean; + isSymbolicLink: () => boolean; + isFIFO: () => boolean; + isSocket: () => boolean; + dev: number | bigint; + ino: number | bigint; + mode: number | bigint; + nlink: number | bigint; + uid: number | bigint; + gid: number | bigint; + rdev: number | bigint; + size: number | bigint; + blksize: number | bigint; + blocks: number | bigint; + atimeMs: number | bigint; + mtimeMs: number | bigint; + ctimeMs: number | bigint; + birthtimeMs: number | bigint; + atime: Date; + mtime: Date; + ctime: Date; + birthtime: Date; +} + +export interface OutputFileSystem { + writeFile: ( + arg0: string, + arg1: string | Buffer, + arg2: (arg0?: null | NodeJS.ErrnoException) => void + ) => void; + mkdir: ( + arg0: string, + arg1: (arg0?: null | NodeJS.ErrnoException) => void + ) => void; + readdir: ( + arg0: string, + arg1: ( + arg0?: null | NodeJS.ErrnoException, + arg1?: (string | Buffer)[] | IDirent[] + ) => void + ) => void; + rmdir: ( + arg0: string, + arg1: (arg0?: null | NodeJS.ErrnoException) => void + ) => void; + unlink: ( + arg0: string, + arg1: (arg0?: null | NodeJS.ErrnoException) => void + ) => void; + stat: ( + arg0: string, + arg1: (arg0?: null | NodeJS.ErrnoException, arg1?: IStats) => void + ) => void; + lstat?: ( + arg0: string, + arg1: (arg0?: null | NodeJS.ErrnoException, arg1?: IStats) => void + ) => void; + readFile: ( + arg0: string, + arg1: (arg0?: null | NodeJS.ErrnoException, arg1?: string | Buffer) => void + ) => void; + join?: (arg0: string, arg1: string) => string; + relative?: (arg0: string, arg1: string) => string; + dirname?: (arg0: string) => string; +} + +export function rmrf( + fs: OutputFileSystem, + p: string, + callback: (err?: Error | null) => void +) { + fs.stat(p, (err, stats) => { + if (err) { + if (err.code === "ENOENT") { + return callback(); + } + return callback(err); + } + if (stats!.isDirectory()) { + fs.readdir(p, (err, files) => { + if (err) { + return callback(err); + } + let count = files!.length; + if (count === 0) { + fs.rmdir(p, callback); + } else { + files!.forEach(file => { + assert(typeof file === "string"); + const fullPath = join(fs, p, file); + rmrf(fs, fullPath, err => { + if (err) { + return callback(err); + } + count--; + if (count === 0) { + fs.rmdir(p, callback); + } + }); + }); + } + }); + } else { + fs.unlink(p, callback); + } + }); +} + +const join = (fs: OutputFileSystem, rootPath: string, filename: string) => { + if (fs && fs.join) { + return fs.join(rootPath, filename); + } else if (path.posix.isAbsolute(rootPath)) { + return path.posix.join(rootPath, filename); + } else if (path.win32.isAbsolute(rootPath)) { + return path.win32.join(rootPath, filename); + } else { + throw new Error( + `${rootPath} is neither a posix nor a windows path, and there is no 'join' method defined in the file system` + ); + } +}; + +const dirname = (fs: OutputFileSystem, absPath: string) => { + if (fs && fs.dirname) { + return fs.dirname(absPath); + } else if (path.posix.isAbsolute(absPath)) { + return path.posix.dirname(absPath); + } else if (path.win32.isAbsolute(absPath)) { + return path.win32.dirname(absPath); + } else { + throw new Error( + `${absPath} is neither a posix nor a windows path, and there is no 'dirname' method defined in the file system` + ); + } +}; + +export const mkdirp = ( + fs: OutputFileSystem, + p: string, + callback: (error?: Error) => void +) => { + fs.mkdir(p, err => { + if (err) { + if (err.code === "ENOENT") { + const dir = dirname(fs, p); + if (dir === p) { + callback(err); + return; + } + mkdirp(fs, dir, err => { + if (err) { + callback(err); + return; + } + fs.mkdir(p, err => { + if (err) { + if (err.code === "EEXIST") { + callback(); + return; + } + callback(err); + return; + } + callback(); + }); + }); + return; + } else if (err.code === "EEXIST") { + callback(); + return; + } + callback(err); + return; + } + callback(); + }); +}; + export interface FileSystemInfoEntry { safeTime: number; timestamp?: number; diff --git a/packages/rspack/src/util/index.ts b/packages/rspack/src/util/index.ts index a7f60dfd726..eb709ae1fa5 100644 --- a/packages/rspack/src/util/index.ts +++ b/packages/rspack/src/util/index.ts @@ -126,6 +126,7 @@ const getDeprecationStatus = () => { }; const yellow = (content: string) => `\u001b[1m\u001b[33m${content}\u001b[39m\u001b[22m`; + export const deprecatedWarn = ( content: string, enable = getDeprecationStatus() @@ -140,3 +141,11 @@ export const deprecatedWarn = ( ); } }; + +export const unsupported = (name: string, issue?: string) => { + let s = `${name} is not supported by rspack.`; + if (issue) { + s += ` Please refer to issue ${issue} for more information.`; + } + throw new Error(s); +};