diff --git a/.gitignore b/.gitignore index 85dd9babd828..a6bbd260a61b 100644 --- a/.gitignore +++ b/.gitignore @@ -68,6 +68,10 @@ jspm_packages/ # Snowpack dependency directory (https://snowpack.dev/) web_modules/ +# Temp files +.cache +.temp + # TypeScript cache *.tsbuildinfo @@ -77,15 +81,6 @@ web_modules/ # Optional eslint cache .eslintcache -# Optional stylelint cache -.stylelintcache - -# Microbundle cache -.rpt2_cache/ -.rts2_cache_cjs/ -.rts2_cache_es/ -.rts2_cache_umd/ - # Optional REPL history .node_repl_history @@ -102,50 +97,14 @@ web_modules/ .env.production.local .env.local -# parcel-bundler cache (https://parceljs.org/) -.cache -.parcel-cache - -# Next.js build output -.next -out - -# Nuxt.js build / generate output -.nuxt - # Dist files dist compiled webpack-dist -# Gatsby files -.cache/ -# Comment in the public line in if your project uses Gatsby and not Next.js -# https://nextjs.org/blog/next-9-1#public-directory-support -# public - -# vuepress build output -.vuepress/dist - -# vuepress v2.x temp and cache directory -.temp -.cache - -# Docusaurus cache and generated files -.docusaurus - # Serverless directories .serverless/ -# FuseBox cache -.fusebox/ - -# DynamoDB Local files -.dynamodb/ - -# TernJS port file -.tern-port - # Stores VSCode versions used for testing VSCode extensions .vscode-test @@ -163,7 +122,6 @@ webpack-dist # os .DS_Store - # Do not ignore this for binding test # crates/node_binding/binding.d.ts @@ -174,20 +132,12 @@ tests/e2e/temp packages/*/tests/js tests/rspack-test/js - # Benchmark /github/ # profile profile.json -# esbuild trace -esbuild.trace - -# esbuild cpuprofile -esbuild.cpuprofile - - # this node_modules is used for tree-shaking snapshot !tests/rspack-test/treeShakingCases/node_modules @@ -210,12 +160,6 @@ npm/**/*.node !npm/win32-ia32-msvc !npm/win32-x64-msvc/ -# Precompiled config schema -packages/rspack/src/config/schema.check.js - -## Angular Incremental Build Cache -**/.angular/ - smoke-example diff_output @@ -235,7 +179,7 @@ diff_output trace.json *.pftrace -# Rsapck bench +# Rspack bench .bench # Claude diff --git a/crates/rspack_hash/src/lib.rs b/crates/rspack_hash/src/lib.rs index bc6a32fa3794..3f1bc3e2e4be 100644 --- a/crates/rspack_hash/src/lib.rs +++ b/crates/rspack_hash/src/lib.rs @@ -21,7 +21,10 @@ impl From<&str> for HashFunction { "xxhash64" => HashFunction::Xxhash64, "md4" => HashFunction::MD4, "sha256" => HashFunction::SHA256, - _ => unimplemented!("{}", value), + _ => panic!( + "Unsupported hash function: '{}'. Expected one of: xxhash64, md4, sha256", + value + ), } } } @@ -35,7 +38,7 @@ impl From<&str> for HashDigest { fn from(value: &str) -> Self { match value { "hex" => HashDigest::Hex, - _ => unimplemented!(), + _ => panic!("Unsupported hash digest: '{}'. Expected: hex", value), } } } diff --git a/packages/rspack-cli/src/cli.ts b/packages/rspack-cli/src/cli.ts index 6c2db54948ea..36d26be39466 100644 --- a/packages/rspack-cli/src/cli.ts +++ b/packages/rspack-cli/src/cli.ts @@ -46,8 +46,6 @@ export class RspackCLI { rspackCommand: Command, callback?: (e: Error | null, res?: Stats | MultiStats) => void ) { - process.env.RSPACK_CONFIG_VALIDATE ??= "loose"; - let { config, pathMap } = await this.loadConfig(options); config = await this.buildConfig(config, pathMap, options, rspackCommand); diff --git a/packages/rspack-cli/src/commands/build.ts b/packages/rspack-cli/src/commands/build.ts index ccd30cae4b7b..188fac975eed 100644 --- a/packages/rspack-cli/src/commands/build.ts +++ b/packages/rspack-cli/src/commands/build.ts @@ -49,9 +49,7 @@ async function runBuild(cli: RspackCLI, options: BuildOptions): Promise { item.options ? item.options.stats : undefined ) } - : compiler.options - ? compiler.options.stats - : undefined; + : compiler.options?.stats; if (options.json && createJsonStringifyStream) { const handleWriteError = (error: Error) => { diff --git a/packages/rspack/etc/core.api.md b/packages/rspack/etc/core.api.md index a4b3dcc5906b..87c05cad69e4 100644 --- a/packages/rspack/etc/core.api.md +++ b/packages/rspack/etc/core.api.md @@ -6294,6 +6294,7 @@ declare namespace rspackExports { NormalModuleFactory, RspackError, RspackSeverity, + ValidationError, RuntimeGlobals, RuntimeModule, StatsAsset, @@ -6309,7 +6310,6 @@ declare namespace rspackExports { Watching, sources, config, - ValidationError, util, BannerPluginArgument, DefinePluginOptions, diff --git a/packages/rspack/package.json b/packages/rspack/package.json index 9c9e22f8d08f..d74d65f43b74 100644 --- a/packages/rspack/package.json +++ b/packages/rspack/package.json @@ -29,7 +29,12 @@ "api-extractor": "api-extractor run --verbose", "api-extractor:ci": "api-extractor run --verbose || diff temp/core.api.md etc/core.api.md" }, - "files": ["dist", "hot", "compiled", "module.d.ts"], + "files": [ + "dist", + "hot", + "compiled", + "module.d.ts" + ], "engines": { "node": ">=18.12.0" }, @@ -45,6 +50,7 @@ "@rsbuild/plugin-node-polyfill": "^1.4.2", "@rslib/core": "0.15.1", "@swc/types": "0.1.25", + "@types/node": "^20.19.21", "@types/watchpack": "^2.4.4", "browserslist-load-config": "^1.0.1", "enhanced-resolve": "5.18.3", @@ -55,9 +61,7 @@ "tsx": "^4.20.6", "typescript": "^5.9.3", "watchpack": "^2.4.4", - "webpack-sources": "3.3.3", - "zod": "^4.1.12", - "zod-validation-error": "^4.0.2" + "webpack-sources": "3.3.3" }, "dependencies": { "@module-federation/runtime-tools": "0.20.0", diff --git a/packages/rspack/rslib.config.mts b/packages/rspack/rslib.config.mts index 38d8ab467f9a..954cd271c4c7 100644 --- a/packages/rspack/rslib.config.mts +++ b/packages/rspack/rslib.config.mts @@ -63,45 +63,6 @@ const commonLibConfig: LibConfig = { } }; -/** - * The `zod` dependency is bundled by Rslib. Since Rspack's public APIs - * do not depend on `zod` types, we add `@ts-ignore` to prevent type errors - * when users set `skipLibCheck: false` in their tsconfig.json file. - */ -const fixZodTypePlugin: rsbuild.RsbuildPlugin = { - name: "fix-zod-type", - setup(api) { - api.onAfterBuild(async () => { - const schemaDir = path.join(api.context.distPath, "schema"); - - if (!fs.existsSync(schemaDir)) { - throw new Error(`Schema directory not found: ${schemaDir}`); - } - - const files = await fs.promises.readdir(schemaDir); - const dtsFiles = files.filter(file => file.endsWith(".d.ts")); - - for (const file of dtsFiles) { - const filePath = path.join(schemaDir, file); - const content = await fs.promises.readFile(filePath, "utf-8"); - const newContent = content - .replace( - `import * as z from "zod";`, - `// @ts-ignore\nimport * as z from "zod";` - ) - .replace( - `import type { z } from "zod";`, - `// @ts-ignore\nimport type { z } from "zod";` - ); - - if (content !== newContent) { - await fs.promises.writeFile(filePath, newContent); - } - } - }); - } -}; - const mfRuntimePlugin: rsbuild.RsbuildPlugin = { name: "mf-runtime", setup(api) { @@ -169,7 +130,7 @@ const codmodPlugin: rsbuild.RsbuildPlugin = { }; export default defineConfig({ - plugins: [fixZodTypePlugin, mfRuntimePlugin, codmodPlugin], + plugins: [mfRuntimePlugin, codmodPlugin], lib: [ merge(commonLibConfig, { dts: { diff --git a/packages/rspack/scripts/check-documentation-coverage.ts b/packages/rspack/scripts/check-documentation-coverage.ts index c38baf10e652..5886f1155fa5 100644 --- a/packages/rspack/scripts/check-documentation-coverage.ts +++ b/packages/rspack/scripts/check-documentation-coverage.ts @@ -3,9 +3,6 @@ import { basename, dirname, extname, join, resolve } from "node:path"; import { fileURLToPath } from "node:url"; import { ApiItemKind, ApiModel } from "@microsoft/api-extractor-model"; -// import { ZodObject, ZodOptional, ZodUnion } from "zod"; -// import { rspackOptions } from "../src/config/zod.ts"; - const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); @@ -157,7 +154,7 @@ type Section = { /** * The process of checking the documentation coverage of Rspack configuration * - * 1. Retrieve and traverse all implemented Rspack configurations through zod declaration. + * 1. Retrieve and traverse all implemented Rspack configurations. * 2. Traverse the configurations and determine whether they match the any level titles of the Markdown files under the config directory of the document site: * 1. If so, pass. * 2. If not, judge whether the introduction of the configuration exists in the body of the parent configuration: @@ -167,35 +164,6 @@ type Section = { function checkConfigsDocumentationCoverage() { const CONFIG_DOCS_DIR = resolve(__dirname, "../../../website/docs/en/config"); - // function getImplementedConfigs() { - // const implementedConfigs: string[] = []; - // function visit(zod, path = "") { - // if (zod instanceof ZodObject) { - // for (const [key, schema] of Object.entries(zod.shape)) { - // const next = (() => { - // if (key.includes("/")) { - // return `${path}["${key}"]`; - // } - // if (path) { - // return `${path}.${key}`; - // } - // return key; - // })(); - // implementedConfigs.push(next); - // visit(schema, next); - // } - // } else if (zod instanceof ZodOptional) { - // visit(zod.unwrap(), path); - // } else if (zod instanceof ZodUnion) { - // for (const schema of zod.options) { - // visit(schema, path); - // } - // } - // } - // visit(rspackOptions); - // return implementedConfigs; - // } - function parseConfigDocuments() { function parseMarkdownContent(content) { const sections: Section[] = []; diff --git a/packages/rspack/src/Compiler.ts b/packages/rspack/src/Compiler.ts index f7889826fbbf..0b71c602ebfc 100644 --- a/packages/rspack/src/Compiler.ts +++ b/packages/rspack/src/Compiler.ts @@ -849,11 +849,12 @@ class Compiler { return callback(null, this.#instance); } - const options = this.options; + const { options } = this; const rawOptions = getRawOptions(options, this); rawOptions.__references = Object.fromEntries( this.#ruleSet.builtinReferences.entries() ); + rawOptions.__virtual_files = VirtualModulesPlugin.__internal__take_virtual_files(this); @@ -867,20 +868,35 @@ class Compiler { ? ThreadsafeInputNodeFS.__to_binding(this.inputFileSystem) : undefined; - this.#instance = new instanceBinding.JsCompiler( - this.compilerPath, - rawOptions, - this.#builtinPlugins, - this.#registers, - ThreadsafeOutputNodeFS.__to_binding(this.outputFileSystem!), - this.intermediateFileSystem - ? ThreadsafeIntermediateNodeFS.__to_binding(this.intermediateFileSystem) - : undefined, - inputFileSystem, - ResolverFactory.__to_binding(this.resolverFactory) - ); + try { + this.#instance = new instanceBinding.JsCompiler( + this.compilerPath, + rawOptions, + this.#builtinPlugins, + this.#registers, + ThreadsafeOutputNodeFS.__to_binding(this.outputFileSystem!), + this.intermediateFileSystem + ? ThreadsafeIntermediateNodeFS.__to_binding( + this.intermediateFileSystem + ) + : undefined, + inputFileSystem, + ResolverFactory.__to_binding(this.resolverFactory) + ); - callback(null, this.#instance); + callback(null, this.#instance); + } catch (err) { + if (err instanceof Error) { + // hide unnecessary stack trace + delete err.stack; + } + callback( + new Error( + "Failed to create Rspack compiler instance, check the Rspack configuration.", + { cause: err } + ) + ); + } } #createHooksRegisters(): binding.RegisterJsTaps { diff --git a/packages/rspack/src/RspackError.ts b/packages/rspack/src/RspackError.ts index 42e2eda2ff5c..773f4850fe6d 100644 --- a/packages/rspack/src/RspackError.ts +++ b/packages/rspack/src/RspackError.ts @@ -19,3 +19,11 @@ export class DeadlockRiskError extends Error { this.stack = ""; } } + +// This type is no longer used and will be removed in Rspack 2.0 +export class ValidationError extends Error { + constructor(message: string) { + super(message); + this.name = "ValidationError"; + } +} diff --git a/packages/rspack/src/builtin-plugin/IgnorePlugin.ts b/packages/rspack/src/builtin-plugin/IgnorePlugin.ts index 8fcb720eb4b8..c7fe37f1128a 100644 --- a/packages/rspack/src/builtin-plugin/IgnorePlugin.ts +++ b/packages/rspack/src/builtin-plugin/IgnorePlugin.ts @@ -2,8 +2,6 @@ import { BuiltinPluginName, type RawIgnorePluginOptions } from "@rspack/binding"; -import { getIgnorePluginOptionsSchema } from "../schema/plugins"; -import { validate } from "../schema/validate"; import { create } from "./base"; export type IgnorePluginOptions = @@ -22,8 +20,6 @@ export type IgnorePluginOptions = export const IgnorePlugin = create( BuiltinPluginName.IgnorePlugin, (options: IgnorePluginOptions): RawIgnorePluginOptions => { - validate(options, getIgnorePluginOptionsSchema); - return options; } ); diff --git a/packages/rspack/src/builtin-plugin/RsdoctorPlugin.ts b/packages/rspack/src/builtin-plugin/RsdoctorPlugin.ts index 66f8cee6f1f7..650dbb9f7232 100644 --- a/packages/rspack/src/builtin-plugin/RsdoctorPlugin.ts +++ b/packages/rspack/src/builtin-plugin/RsdoctorPlugin.ts @@ -27,8 +27,6 @@ import { import * as liteTapable from "@rspack/lite-tapable"; import { type Compilation, checkCompilation } from "../Compilation"; import type { Compiler } from "../Compiler"; -import { getRsdoctorPluginSchema } from "../schema/plugins"; -import { validate } from "../schema/validate"; import type { CreatePartialRegisters } from "../taps/types"; import { create } from "./base"; @@ -77,7 +75,6 @@ const RsdoctorPluginImpl = create( chunkGraphFeatures: true } ): RawRsdoctorPluginOptions { - validate(c, getRsdoctorPluginSchema); return { moduleGraphFeatures: c.moduleGraphFeatures ?? true, chunkGraphFeatures: c.chunkGraphFeatures ?? true, diff --git a/packages/rspack/src/builtin-plugin/SubresourceIntegrityPlugin.ts b/packages/rspack/src/builtin-plugin/SubresourceIntegrityPlugin.ts index 218393940978..f37e2d95a635 100644 --- a/packages/rspack/src/builtin-plugin/SubresourceIntegrityPlugin.ts +++ b/packages/rspack/src/builtin-plugin/SubresourceIntegrityPlugin.ts @@ -4,15 +4,12 @@ import { join, relative, sep } from "node:path"; import { BuiltinPluginName, type RawIntegrityData, - type RawSubresourceIntegrityPluginOptions, - type RspackError + type RawSubresourceIntegrityPluginOptions } from "@rspack/binding"; import type { AsyncSeriesWaterfallHook } from "@rspack/lite-tapable"; import type { Compilation } from "../Compilation"; import type { Compiler } from "../Compiler"; import type { CrossOriginLoading } from "../config/types"; -import { getSRIPluginOptionsSchema } from "../schema/plugins"; -import { validate } from "../schema/validate"; import { create } from "./base"; const PLUGIN_NAME = "SubresourceIntegrityPlugin"; @@ -102,29 +99,17 @@ const NativeSubresourceIntegrityPlugin = create( export class SubresourceIntegrityPlugin extends NativeSubresourceIntegrityPlugin { private integrities: Map = new Map(); private options: SubresourceIntegrityPluginOptions; - private validateError: Error | null = null; + constructor(options: SubresourceIntegrityPluginOptions = {}) { - let validateError: Error | null = null; if (typeof options !== "object") { throw new Error("SubResourceIntegrity: argument must be an object"); } - try { - validateSubresourceIntegrityPluginOptions(options); - } catch (e) { - validateError = e as Error; - } - const finalOptions = validateError - ? { - hashFuncNames: ["sha384"], - htmlPlugin: NATIVE_HTML_PLUGIN, - enabled: false - } - : { - hashFuncNames: options.hashFuncNames ?? ["sha384"], - htmlPlugin: options.htmlPlugin ?? NATIVE_HTML_PLUGIN, - enabled: options.enabled ?? "auto" - }; + const finalOptions = { + hashFuncNames: options.hashFuncNames ?? ["sha384"], + htmlPlugin: options.htmlPlugin ?? NATIVE_HTML_PLUGIN, + enabled: options.enabled ?? "auto" + }; super({ ...finalOptions, integrityCallback: (data: RawIntegrityData) => { @@ -133,7 +118,7 @@ export class SubresourceIntegrityPlugin extends NativeSubresourceIntegrityPlugin ); } }); - this.validateError = validateError; + this.options = finalOptions as SubresourceIntegrityPluginOptions; } @@ -218,11 +203,6 @@ export class SubresourceIntegrityPlugin extends NativeSubresourceIntegrityPlugin apply(compiler: Compiler): void { if (!this.isEnabled(compiler)) { - if (this.validateError) { - compiler.hooks.compilation.tap(PLUGIN_NAME, compilation => { - compilation.errors.push(this.validateError as unknown as RspackError); - }); - } return; } @@ -313,12 +293,6 @@ export class SubresourceIntegrityPlugin extends NativeSubresourceIntegrityPlugin } } -function validateSubresourceIntegrityPluginOptions( - options: SubresourceIntegrityPluginOptions -) { - validate(options, getSRIPluginOptionsSchema); -} - function isErrorWithCode(obj: T): boolean { return ( obj instanceof Error && diff --git a/packages/rspack/src/builtin-plugin/html-plugin/options.ts b/packages/rspack/src/builtin-plugin/html-plugin/options.ts index 7ed5a6952be0..3301b51c19a4 100644 --- a/packages/rspack/src/builtin-plugin/html-plugin/options.ts +++ b/packages/rspack/src/builtin-plugin/html-plugin/options.ts @@ -1,6 +1,4 @@ import { Compilation } from "../../Compilation"; -import { getHtmlPluginOptionsSchema } from "../../schema/plugins"; -import { validate } from "../../schema/validate"; const compilationOptionsMap: WeakMap = new WeakMap(); @@ -106,10 +104,6 @@ export type HtmlRspackPluginOptions = { [key: string]: any; }; -export function validateHtmlPluginOptions(options: HtmlRspackPluginOptions) { - return validate(options, getHtmlPluginOptionsSchema); -} - export const getPluginOptions = (compilation: Compilation, uid: number) => { if (!(compilation instanceof Compilation)) { throw new TypeError( diff --git a/packages/rspack/src/builtin-plugin/html-plugin/plugin.ts b/packages/rspack/src/builtin-plugin/html-plugin/plugin.ts index b82d97684766..01d8cb1934c8 100644 --- a/packages/rspack/src/builtin-plugin/html-plugin/plugin.ts +++ b/packages/rspack/src/builtin-plugin/html-plugin/plugin.ts @@ -17,8 +17,7 @@ import { import { cleanPluginOptions, type HtmlRspackPluginOptions, - setPluginOptions, - validateHtmlPluginOptions + setPluginOptions } from "./options"; type HtmlPluginTag = { @@ -37,7 +36,6 @@ const HtmlRspackPluginImpl = create( this: Compiler, c: HtmlRspackPluginOptions = {} ): RawHtmlRspackPluginOptions { - validateHtmlPluginOptions(c); const uid = HTML_PLUGIN_UID++; const meta: Record> = {}; for (const key in c.meta) { diff --git a/packages/rspack/src/container/ModuleFederationPlugin.ts b/packages/rspack/src/container/ModuleFederationPlugin.ts index df747f5af33a..66238ad1e905 100644 --- a/packages/rspack/src/container/ModuleFederationPlugin.ts +++ b/packages/rspack/src/container/ModuleFederationPlugin.ts @@ -1,7 +1,5 @@ import type { Compiler } from "../Compiler"; import type { ExternalsType } from "../config"; -import { getExternalsTypeSchema } from "../schema/config"; -import { isValidate } from "../schema/validate"; import type { ModuleFederationPluginV1Options } from "./ModuleFederationPluginV1"; import { ModuleFederationRuntimePlugin } from "./ModuleFederationRuntimePlugin"; import { parseOptions } from "./options"; @@ -96,9 +94,8 @@ function getRemoteInfos(options: ModuleFederationPluginOptions): RemoteInfos { const remoteType = options.remoteType || - (options.library && isValidate(options.library.type, getExternalsTypeSchema) - ? (options.library.type as ExternalsType) - : "script"); + (options.library ? (options.library.type as ExternalsType) : "script"); + const remotes = parseOptions( options.remotes, item => ({ diff --git a/packages/rspack/src/container/ModuleFederationPluginV1.ts b/packages/rspack/src/container/ModuleFederationPluginV1.ts index a6a752049ff0..851c7f89cb11 100644 --- a/packages/rspack/src/container/ModuleFederationPluginV1.ts +++ b/packages/rspack/src/container/ModuleFederationPluginV1.ts @@ -1,7 +1,5 @@ import type { Compiler } from "../Compiler"; import type { EntryRuntime, ExternalsType, LibraryOptions } from "../config"; -import { getExternalsTypeSchema } from "../schema/config"; -import { isValidate } from "../schema/validate"; import { type Shared, SharePlugin } from "../sharing/SharePlugin"; import { ShareRuntimePlugin } from "../sharing/ShareRuntimePlugin"; import { ContainerPlugin, type Exposes } from "./ContainerPlugin"; @@ -33,10 +31,8 @@ export class ModuleFederationPluginV1 { const library = options.library || { type: "var", name: options.name }; const remoteType = options.remoteType || - (options.library && - isValidate(options.library.type, getExternalsTypeSchema) - ? (options.library.type as ExternalsType) - : "script"); + (options.library ? (options.library.type as ExternalsType) : "script"); + if ( library && !compiler.options.output.enabledLibraryTypes!.includes(library.type) diff --git a/packages/rspack/src/exports.ts b/packages/rspack/src/exports.ts index 0bd5db2f9316..40fef1ca250e 100644 --- a/packages/rspack/src/exports.ts +++ b/packages/rspack/src/exports.ts @@ -37,7 +37,11 @@ export type { default as ModuleGraph } from "./ModuleGraph"; export { MultiStats } from "./MultiStats"; export { NormalModule } from "./NormalModule"; export type { NormalModuleFactory } from "./NormalModuleFactory"; -export type { RspackError, RspackSeverity } from "./RspackError"; +export { + type RspackError, + type RspackSeverity, + ValidationError +} from "./RspackError"; export { RuntimeGlobals } from "./RuntimeGlobals"; export { RuntimeModule } from "./RuntimeModule"; export type { @@ -86,10 +90,6 @@ export const config: Config = { export type * from "./config"; -import { ValidationError } from "./schema/validate"; - -export { ValidationError }; - import { cachedCleverMerge as cleverMerge } from "./util/cleverMerge"; import { createHash } from "./util/createHash"; diff --git a/packages/rspack/src/lib/DllPlugin.ts b/packages/rspack/src/lib/DllPlugin.ts index 2989f162edb3..6d83eb5ca6bc 100644 --- a/packages/rspack/src/lib/DllPlugin.ts +++ b/packages/rspack/src/lib/DllPlugin.ts @@ -12,8 +12,6 @@ import { LibManifestPlugin } from "../builtin-plugin"; import { DllEntryPlugin } from "../builtin-plugin/DllEntryPlugin"; import { FlagAllModulesAsUsedPlugin } from "../builtin-plugin/FlagAllModulesAsUsedPlugin"; import type { Compiler } from "../Compiler"; -import { getDllPluginOptionsSchema } from "../schema/plugins"; -import { validate } from "../schema/validate"; export type DllPluginOptions = { /** @@ -52,7 +50,6 @@ export class DllPlugin { private options: DllPluginOptions; constructor(options: DllPluginOptions) { - validate(options, getDllPluginOptionsSchema); this.options = { ...options, entryOnly: options.entryOnly !== false diff --git a/packages/rspack/src/lib/DllReferencePlugin.ts b/packages/rspack/src/lib/DllReferencePlugin.ts index ea24e848e196..55bda0c7e313 100644 --- a/packages/rspack/src/lib/DllReferencePlugin.ts +++ b/packages/rspack/src/lib/DllReferencePlugin.ts @@ -7,13 +7,10 @@ * Copyright (c) JS Foundation and other contributors * https://github.com/webpack/webpack/blob/main/LICENSE */ - import type { JsBuildMeta } from "@rspack/binding"; import { DllReferenceAgencyPlugin } from "../builtin-plugin"; import type { CompilationParams } from "../Compilation"; import type { Compiler } from "../Compiler"; -import { getDllReferencePluginOptionsSchema } from "../schema/plugins"; -import { validate } from "../schema/validate"; import { makePathsRelative } from "../util/identifier"; import WebpackError from "./WebpackError"; @@ -143,8 +140,6 @@ export class DllReferencePlugin { private errors: WeakMap; constructor(options: DllReferencePluginOptions) { - validate(options, getDllReferencePluginOptionsSchema); - this.options = options; this.errors = new WeakMap(); } diff --git a/packages/rspack/src/rspack.ts b/packages/rspack/src/rspack.ts index 803714dec77f..3da6aca5e1cd 100644 --- a/packages/rspack/src/rspack.ts +++ b/packages/rspack/src/rspack.ts @@ -10,7 +10,6 @@ import assert from "node:assert"; import util from "node:util"; import type { Callback } from "@rspack/lite-tapable"; - import { Compiler } from "./Compiler"; import { applyRspackOptionsBaseDefaults, @@ -28,9 +27,8 @@ import MultiStats from "./MultiStats"; import NodeEnvironmentPlugin from "./node/NodeEnvironmentPlugin"; import { RspackOptionsApply } from "./rspackOptionsApply"; import { Stats } from "./Stats"; -import { getRspackOptionsSchema } from "./schema/config"; -import { validate } from "./schema/validate"; -import { asArray, isNil } from "./util"; +import { isNil } from "./util"; +import { validateRspackConfig } from "./util/validateConfig"; function createMultiCompiler(options: MultiRspackOptions): MultiCompiler { const compilers = options.map(createCompiler); @@ -104,16 +102,21 @@ function rspack( callback?: Callback | Callback ) { try { - for (const o of asArray(options)) { - validate(o, getRspackOptionsSchema); + if (isMultiRspackOptions(options)) { + for (const option of options) { + validateRspackConfig(option); + } + } else { + validateRspackConfig(options); } - } catch (e) { - if (e instanceof Error && callback) { - callback(e); + } catch (err) { + if (err instanceof Error && callback) { + callback(err); return null; } - throw e; + throw err; } + const create = () => { if (isMultiRspackOptions(options)) { const compiler = createMultiCompiler(options); diff --git a/packages/rspack/src/schema/config.ts b/packages/rspack/src/schema/config.ts deleted file mode 100644 index c73dcbe68a7a..000000000000 --- a/packages/rspack/src/schema/config.ts +++ /dev/null @@ -1,1554 +0,0 @@ -import nodePath from "node:path"; -import * as z from "zod"; -import { createErrorMap, fromZodError } from "zod-validation-error"; -import type * as t from "../config/types"; -import { memoize } from "../util/memoize"; -import { getZodSwcLoaderOptionsSchema } from "./loaders"; -import { anyFunction, intOrInfinity, numberOrInfinity } from "./utils"; - -z.config({ - jitless: true, - customError: createErrorMap() -}); - -export const getExternalsTypeSchema = memoize( - () => - z.enum([ - "var", - "module", - "assign", - "this", - "window", - "self", - "global", - "commonjs", - "commonjs2", - "commonjs-module", - "commonjs-static", - "amd", - "amd-require", - "umd", - "umd2", - "jsonp", - "system", - "promise", - "import", - "module-import", - "script", - "node-commonjs", - "commonjs-import" - ]) satisfies z.ZodType -); - -export const getRspackOptionsSchema = memoize(() => { - const filenameTemplate = z.string() satisfies z.ZodType; - - const filename = filenameTemplate.or( - anyFunction - ) satisfies z.ZodType; - - //#region Name - const name = z.string() satisfies z.ZodType; - //#endregion - - //#region Dependencies - const dependencies = z.array(name) satisfies z.ZodType; - //#endregion - - //#region Context - const context = z.string().refine(val => nodePath.isAbsolute(val), { - error: issue => - `The provided value ${JSON.stringify(issue.input)} must be an absolute path` - }) satisfies z.ZodType; - //#endregion - - //#region Mode - const mode = z.enum([ - "development", - "production", - "none" - ]) satisfies z.ZodType; - //#endregion - - //#region Falsy - const falsy = z.union([ - z.literal(false), - z.literal(0), - z.literal(""), - z.null(), - z.undefined() - ]) satisfies z.ZodType; - - //#endregion - - //#region Entry - const publicPath = z - .literal("auto") - .or(filename) satisfies z.ZodType; - - const baseUri = z.string() satisfies z.ZodType; - - const chunkLoadingType = z - .enum(["jsonp", "import-scripts", "require", "async-node", "import"]) - .or(z.string()) satisfies z.ZodType; - - const chunkLoading = z - .literal(false) - .or(chunkLoadingType) satisfies z.ZodType; - - const asyncChunks = z.boolean() satisfies z.ZodType; - - const wasmLoadingType = z - .enum(["fetch-streaming", "fetch", "async-node"]) - .or(z.string()) satisfies z.ZodType; - - const wasmLoading = z - .literal(false) - .or(wasmLoadingType) satisfies z.ZodType; - - const scriptType = z - .enum(["text/javascript", "module"]) - .or(z.literal(false)) satisfies z.ZodType; - - const libraryCustomUmdObject = z - .strictObject({ - amd: z.string(), - commonjs: z.string(), - root: z.string().or(z.array(z.string())) - }) - .partial() satisfies z.ZodType; - - const libraryName = z - .string() - .or(z.array(z.string())) - .or(libraryCustomUmdObject) satisfies z.ZodType; - - const libraryCustomUmdCommentObject = z - .strictObject({ - amd: z.string(), - commonjs: z.string(), - commonjs2: z.string(), - root: z.string() - }) - .partial() satisfies z.ZodType; - - const amdContainer = z.string() satisfies z.ZodType; - - const auxiliaryComment = z - .string() - .or(libraryCustomUmdCommentObject) satisfies z.ZodType; - - const libraryExport = z - .string() - .or(z.array(z.string())) satisfies z.ZodType; - - const libraryType = z - .enum([ - "var", - "module", - "assign", - "assign-properties", - "this", - "window", - "self", - "global", - "commonjs", - "commonjs2", - "commonjs-module", - "commonjs-static", - "amd", - "amd-require", - "umd", - "umd2", - "jsonp", - "system" - ]) - .or(z.string()) satisfies z.ZodType; - - const umdNamedDefine = z.boolean() satisfies z.ZodType; - - const libraryOptions = z.strictObject({ - amdContainer: amdContainer.optional(), - auxiliaryComment: auxiliaryComment.optional(), - export: libraryExport.optional(), - name: libraryName.optional(), - type: libraryType, - umdNamedDefine: umdNamedDefine.optional() - }) satisfies z.ZodType; - - const library = libraryName - .or(libraryOptions) - .optional() satisfies z.ZodType; - - const layer = z.string().or(z.null()) satisfies z.ZodType; - - const entryFilename = filename satisfies z.ZodType; - - const entryRuntime = z - .literal(false) - .or(z.string()) satisfies z.ZodType; - - const entryItem = z - .string() - .or(z.array(z.string())) satisfies z.ZodType; - - const entryDependOn = z - .string() - .or(z.array(z.string())) satisfies z.ZodType; - - const entryDescription = z.strictObject({ - import: entryItem, - runtime: entryRuntime.optional(), - publicPath: publicPath.optional(), - baseUri: baseUri.optional(), - chunkLoading: chunkLoading.optional(), - asyncChunks: asyncChunks.optional(), - wasmLoading: wasmLoading.optional(), - filename: entryFilename.optional(), - library: libraryOptions.optional(), - dependOn: entryDependOn.optional(), - layer: layer.optional() - }) satisfies z.ZodType; - - const entryUnnamed = entryItem satisfies z.ZodType; - - const entryObject = z.record( - z.string(), - entryItem.or(entryDescription) - ) satisfies z.ZodType; - - const entryStatic = entryObject.or( - entryUnnamed - ) satisfies z.ZodType; - - const entryDynamic = anyFunction satisfies z.ZodType; - - const entry = entryStatic.or(entryDynamic) satisfies z.ZodType; - //#endregion - - //#region Output - const path = z.string() satisfies z.ZodType; - - const pathinfo = z - .boolean() - .or(z.literal("verbose")) satisfies z.ZodType; - - const assetModuleFilename = - filename satisfies z.ZodType; - - const webassemblyModuleFilename = - z.string() satisfies z.ZodType; - - const chunkFilename = filename satisfies z.ZodType; - - const crossOriginLoading = z - .literal(false) - .or( - z.enum(["anonymous", "use-credentials"]) - ) satisfies z.ZodType; - - const cssFilename = filename satisfies z.ZodType; - - const cssChunkFilename = filename satisfies z.ZodType; - - const hotUpdateChunkFilename = - filenameTemplate satisfies z.ZodType; - - const hotUpdateMainFilename = - filenameTemplate satisfies z.ZodType; - - const hotUpdateGlobal = z.string() satisfies z.ZodType; - - const uniqueName = z.string() satisfies z.ZodType; - - const chunkLoadingGlobal = - z.string() satisfies z.ZodType; - - const enabledLibraryTypes = z.array( - libraryType - ) satisfies z.ZodType; - - const clean = z.union([ - z.boolean(), - z - .strictObject({ - keep: z.instanceof(RegExp).or(z.string()).or(anyFunction) - }) - .partial() - ]) satisfies z.ZodType; - - const outputModule = z.boolean() satisfies z.ZodType; - - const strictModuleExceptionHandling = - z.boolean() satisfies z.ZodType; - - const strictModuleErrorHandling = - z.boolean() satisfies z.ZodType; - - const globalObject = z.string() satisfies z.ZodType; - - const enabledWasmLoadingTypes = z.array( - wasmLoadingType - ) satisfies z.ZodType; - - const importFunctionName = - z.string() satisfies z.ZodType; - - const importMetaName = z.string() satisfies z.ZodType; - - const iife = z.boolean() satisfies z.ZodType; - - const enabledChunkLoadingTypes = z.array( - chunkLoadingType - ) satisfies z.ZodType; - - const chunkFormat = z - .literal(false) - .or(z.string()) satisfies z.ZodType; - - const workerPublicPath = z.string() satisfies z.ZodType; - - const trustedTypes = z - .strictObject({ - policyName: z.string(), - onPolicyCreationFailure: z.enum(["continue", "stop"]) - }) - .partial() satisfies z.ZodType; - - const hashDigest = z.string() satisfies z.ZodType; - - const hashDigestLength = z.int() satisfies z.ZodType; - - const hashFunction = z.enum([ - "md4", - "xxhash64", - "sha256" - ]) satisfies z.ZodType; - - const hashSalt = z.string() satisfies z.ZodType; - - const sourceMapFilename = z.string() satisfies z.ZodType; - - const devtoolNamespace = z.string() satisfies z.ZodType; - - const devtoolModuleFilenameTemplate = z.union([ - z.string(), - anyFunction - ]) satisfies z.ZodType; - - const devtoolFallbackModuleFilenameTemplate = - devtoolModuleFilenameTemplate satisfies z.ZodType; - - const environment = z - .strictObject({ - arrowFunction: z.boolean(), - asyncFunction: z.boolean(), - bigIntLiteral: z.boolean(), - const: z.boolean(), - destructuring: z.boolean(), - document: z.boolean(), - dynamicImport: z.boolean(), - dynamicImportInWorker: z.boolean(), - forOf: z.boolean(), - globalThis: z.boolean(), - module: z.boolean(), - nodePrefixForCoreModules: z.boolean(), - optionalChaining: z.boolean(), - templateLiteral: z.boolean() - }) - .partial() satisfies z.ZodType; - - const output = z - .strictObject({ - path: path, - pathinfo: pathinfo, - clean: clean, - publicPath: publicPath, - filename: filename, - chunkFilename: chunkFilename, - crossOriginLoading: crossOriginLoading, - cssFilename: cssFilename, - cssHeadDataCompression: z.boolean(), - cssChunkFilename: cssChunkFilename, - hotUpdateMainFilename: hotUpdateMainFilename, - hotUpdateChunkFilename: hotUpdateChunkFilename, - hotUpdateGlobal: hotUpdateGlobal, - assetModuleFilename: assetModuleFilename, - uniqueName: uniqueName, - chunkLoadingGlobal: chunkLoadingGlobal, - enabledLibraryTypes: enabledLibraryTypes, - library: library, - libraryExport: libraryExport, - libraryTarget: libraryType, - umdNamedDefine: umdNamedDefine, - auxiliaryComment: auxiliaryComment, - module: outputModule, - strictModuleExceptionHandling: strictModuleExceptionHandling, - strictModuleErrorHandling: strictModuleErrorHandling, - globalObject: globalObject, - importFunctionName: importFunctionName, - importMetaName: importMetaName, - iife: iife, - wasmLoading: wasmLoading, - enabledWasmLoadingTypes: enabledWasmLoadingTypes, - webassemblyModuleFilename: webassemblyModuleFilename, - chunkFormat: chunkFormat, - chunkLoading: chunkLoading, - enabledChunkLoadingTypes: enabledChunkLoadingTypes, - trustedTypes: z.literal(true).or(z.string()).or(trustedTypes), - sourceMapFilename: sourceMapFilename, - hashDigest: hashDigest, - hashDigestLength: hashDigestLength, - hashFunction: hashFunction, - hashSalt: hashSalt, - asyncChunks: asyncChunks, - workerChunkLoading: chunkLoading, - workerWasmLoading: wasmLoading, - workerPublicPath: workerPublicPath, - scriptType: scriptType, - devtoolNamespace: devtoolNamespace, - devtoolModuleFilenameTemplate: devtoolModuleFilenameTemplate, - devtoolFallbackModuleFilenameTemplate: - devtoolFallbackModuleFilenameTemplate, - chunkLoadTimeout: numberOrInfinity, - charset: z.boolean(), - environment: environment, - compareBeforeEmit: z.boolean() - }) - .partial() satisfies z.ZodType; - //#endregion - - //#region Resolve - const resolveAlias = z - .record( - z.string(), - z - .literal(false) - .or(z.string()) - .or(z.array(z.string().or(z.literal(false)))) - ) - .or(z.literal(false)) satisfies z.ZodType; - - const resolveTsConfigFile = z.string(); - const resolveTsConfig = resolveTsConfigFile.or( - z.strictObject({ - configFile: resolveTsConfigFile, - references: z.array(z.string()).or(z.literal("auto")).optional() - }) - ) satisfies z.ZodType; - - const baseResolveOptions = z - .strictObject({ - alias: resolveAlias, - conditionNames: z.array(z.string()), - extensions: z.array(z.string()), - fallback: resolveAlias, - mainFields: z.array(z.string()), - mainFiles: z.array(z.string()), - modules: z.array(z.string()), - preferRelative: z.boolean(), - preferAbsolute: z.boolean(), - symlinks: z.boolean(), - enforceExtension: z.boolean(), - importsFields: z.array(z.string()), - descriptionFiles: z.array(z.string()), - tsConfig: resolveTsConfig, - fullySpecified: z.boolean(), - exportsFields: z.array(z.string()), - extensionAlias: z.record(z.string(), z.string().or(z.array(z.string()))), - aliasFields: z.array(z.string()), - restrictions: z.array(z.string()), - roots: z.array(z.string()), - pnp: z.boolean() - }) - .partial() satisfies z.ZodType; - - const resolveOptions: z.ZodType = baseResolveOptions.extend( - { - byDependency: z - .lazy(() => z.record(z.string(), resolveOptions)) - .optional() - } - ); - - //#endregion - - //#region Module - const baseRuleSetCondition = z - .instanceof(RegExp) - .or(z.string()) - .or(anyFunction); - - const ruleSetCondition: z.ZodType = baseRuleSetCondition - .or(z.lazy(() => ruleSetConditions)) - .or(z.lazy(() => ruleSetLogicalConditions)); - - const ruleSetConditions: z.ZodType = z.lazy(() => - z.array(ruleSetCondition) - ); - - const ruleSetLogicalConditions: z.ZodType = z - .strictObject({ - and: ruleSetConditions, - or: ruleSetConditions, - not: ruleSetCondition - }) - .partial(); - - const ruleSetLoader = z.string() satisfies z.ZodType; - - const ruleSetLoaderOptions = z - .string() - .or( - z.record(z.string(), z.any()) - ) satisfies z.ZodType; - - const ruleSetLoaderWithOptions = z.strictObject({ - ident: z.string().optional(), - loader: ruleSetLoader, - options: ruleSetLoaderOptions.optional(), - parallel: z.boolean().optional() - }) satisfies z.ZodType; - - const builtinSWCLoaderChecker: z.core.CheckFn< - t.RuleSetLoaderWithOptions | t.RuleSetRule | undefined - > = ctx => { - const data = ctx.value; - if ( - data?.loader !== "builtin:swc-loader" || - typeof data?.options !== "object" - ) { - return; - } - - const res = getZodSwcLoaderOptionsSchema().safeParse(data.options); - - if (!res.success) { - const validationErr = fromZodError(res.error, { - prefix: "Invalid options for 'builtin:swc-loader'" - }); - ctx.issues.push({ - code: "custom", - message: validationErr.message, - input: data.options - }); - } - }; - - const ruleSetUseItem = ruleSetLoader.or( - ruleSetLoaderWithOptions.check(builtinSWCLoaderChecker) - ) satisfies z.ZodType; - - const ruleSetUse = ruleSetUseItem - .or(ruleSetUseItem.array()) - .or(anyFunction) satisfies z.ZodType; - - const baseRuleSetRule = z - .strictObject({ - test: ruleSetCondition, - exclude: ruleSetCondition, - include: ruleSetCondition, - issuer: ruleSetCondition, - issuerLayer: ruleSetCondition, - dependency: ruleSetCondition, - resource: ruleSetCondition, - resourceFragment: ruleSetCondition, - resourceQuery: ruleSetCondition, - scheme: ruleSetCondition, - mimetype: ruleSetCondition, - descriptionData: z.record(z.string(), ruleSetCondition), - with: z.record(z.string(), ruleSetCondition), - type: z.string(), - layer: z.string(), - loader: ruleSetLoader, - options: ruleSetLoaderOptions, - use: ruleSetUse, - parser: z.record(z.string(), z.any()), - generator: z.record(z.string(), z.any()), - resolve: resolveOptions, - sideEffects: z.boolean(), - enforce: z.literal("pre").or(z.literal("post")), - extractSourceMap: z.boolean() - }) - .partial() satisfies z.ZodType; - - const extendedBaseRuleSetRule: z.ZodType = - baseRuleSetRule.extend({ - oneOf: z.lazy(() => ruleSetRule.or(falsy).array()).optional(), - rules: z.lazy(() => ruleSetRule.or(falsy).array()).optional() - }) satisfies z.ZodType; - - const ruleSetRule = extendedBaseRuleSetRule.check(builtinSWCLoaderChecker); - - const ruleSetRules = z.array( - z.literal("...").or(ruleSetRule).or(falsy) - ) satisfies z.ZodType; - - const assetParserDataUrlOptions = z - .strictObject({ - maxSize: numberOrInfinity - }) - .partial() satisfies z.ZodType; - - const assetParserDataUrl = - assetParserDataUrlOptions satisfies z.ZodType; - - const assetParserOptions = z - .strictObject({ - dataUrlCondition: assetParserDataUrl - }) - .partial() satisfies z.ZodType; - - const cssParserNamedExports = - z.boolean() satisfies z.ZodType; - - const cssParserUrl = z.boolean() satisfies z.ZodType; - - const cssParserOptions = z - .strictObject({ - namedExports: cssParserNamedExports, - url: cssParserUrl - }) - .partial() satisfies z.ZodType; - - const cssAutoParserOptions = z - .strictObject({ - namedExports: cssParserNamedExports, - url: cssParserUrl - }) - .partial() satisfies z.ZodType; - - const cssModuleParserOptions = z - .strictObject({ - namedExports: cssParserNamedExports, - url: cssParserUrl - }) - .partial() satisfies z.ZodType; - - const dynamicImportMode = z.enum(["eager", "lazy", "weak", "lazy-once"]); - const dynamicImportPreload = z.union([z.boolean(), numberOrInfinity]); - const dynamicImportPrefetch = z.union([z.boolean(), numberOrInfinity]); - const dynamicImportFetchPriority = z.enum(["low", "high", "auto"]); - const javascriptParserUrl = z.union([ - z.literal("relative"), - z.literal("new-url-relative"), - z.boolean() - ]); - const exprContextCritical = z.boolean(); - const wrappedContextCritical = z.boolean(); - const unknownContextCritical = z.boolean(); - const wrappedContextRegExp = z.instanceof(RegExp); - const exportsPresence = z - .enum(["error", "warn", "auto"]) - .or(z.literal(false)); - const importExportsPresence = z - .enum(["error", "warn", "auto"]) - .or(z.literal(false)); - const reexportExportsPresence = z - .enum(["error", "warn", "auto"]) - .or(z.literal(false)); - const strictExportPresence = z.boolean(); - const worker = z.array(z.string()).or(z.boolean()); - const overrideStrict = z.enum(["strict", "non-strict"]); - const requireAsExpression = z.boolean(); - const requireDynamic = z.boolean(); - const requireResolve = z.boolean(); - const commonjsExports = z.union([z.boolean(), z.literal("skipInEsm")]); - const commonjs = z.boolean().or( - z - .strictObject({ - exports: commonjsExports - }) - .partial() - ); - const importDynamic = z.boolean(); - const commonjsMagicComments = z.boolean(); - const inlineConst = z.boolean(); - const typeReexportsPresence = z.enum([ - "no-tolerant", - "tolerant", - "tolerant-no-check" - ]); - const jsx = z.boolean(); - - const javascriptParserOptions = z - .strictObject({ - dynamicImportMode: dynamicImportMode, - dynamicImportPreload: dynamicImportPreload, - dynamicImportPrefetch: dynamicImportPrefetch, - dynamicImportFetchPriority: dynamicImportFetchPriority, - importMeta: z.boolean(), - url: javascriptParserUrl, - exprContextCritical: exprContextCritical, - wrappedContextCritical: wrappedContextCritical, - unknownContextCritical: unknownContextCritical, - wrappedContextRegExp: wrappedContextRegExp, - exportsPresence: exportsPresence, - importExportsPresence: importExportsPresence, - reexportExportsPresence: reexportExportsPresence, - strictExportPresence: strictExportPresence, - worker: worker, - overrideStrict: overrideStrict, - commonjsMagicComments: commonjsMagicComments, - // #region Not available in webpack yet. - requireAsExpression: requireAsExpression, - requireDynamic: requireDynamic, - requireResolve: requireResolve, - commonjs: commonjs, - importDynamic: importDynamic, - inlineConst: inlineConst, - typeReexportsPresence: typeReexportsPresence, - jsx: jsx - // #endregion - }) - .partial() satisfies z.ZodType; - - const parserOptionsByModuleTypeKnown = z - .strictObject({ - asset: assetParserOptions, - css: cssParserOptions, - "css/auto": cssAutoParserOptions, - "css/module": cssModuleParserOptions, - javascript: javascriptParserOptions, - "javascript/auto": javascriptParserOptions, - "javascript/dynamic": javascriptParserOptions, - "javascript/esm": javascriptParserOptions - }) - .partial() satisfies z.ZodType; - - const parserOptionsByModuleType = parserOptionsByModuleTypeKnown; - - const assetGeneratorDataUrlOptions = z - .strictObject({ - encoding: z.literal(false).or(z.literal("base64")), - mimetype: z.string() - }) - .partial() satisfies z.ZodType; - - const assetGeneratorDataUrlFunction = - anyFunction satisfies z.ZodType; - - const assetGeneratorDataUrl = assetGeneratorDataUrlOptions.or( - assetGeneratorDataUrlFunction - ) satisfies z.ZodType; - - const assetInlineGeneratorOptions = z - .strictObject({ - dataUrl: assetGeneratorDataUrl - }) - .partial() satisfies z.ZodType; - - const assetResourceGeneratorOptions = z - .strictObject({ - emit: z.boolean(), - filename: filename, - publicPath: publicPath, - outputPath: filename - }) - .partial() satisfies z.ZodType; - - const assetGeneratorOptions = assetInlineGeneratorOptions.merge( - assetResourceGeneratorOptions - ) satisfies z.ZodType; - - const cssGeneratorExportsConvention = z.enum([ - "as-is", - "camel-case", - "camel-case-only", - "dashes", - "dashes-only" - ]) satisfies z.ZodType; - - const cssGeneratorExportsOnly = - z.boolean() satisfies z.ZodType; - - const cssGeneratorLocalIdentName = - z.string() satisfies z.ZodType; - - const cssGeneratorEsModule = - z.boolean() satisfies z.ZodType; - - const cssGeneratorOptions = z - .strictObject({ - exportsOnly: cssGeneratorExportsOnly, - esModule: cssGeneratorEsModule - }) - .partial() satisfies z.ZodType; - - const cssAutoGeneratorOptions = z - .strictObject({ - exportsConvention: cssGeneratorExportsConvention, - exportsOnly: cssGeneratorExportsOnly, - localIdentName: cssGeneratorLocalIdentName, - esModule: cssGeneratorEsModule - }) - .partial() satisfies z.ZodType; - - const cssModuleGeneratorOptions = z - .strictObject({ - exportsConvention: cssGeneratorExportsConvention, - exportsOnly: cssGeneratorExportsOnly, - localIdentName: cssGeneratorLocalIdentName, - esModule: cssGeneratorEsModule - }) - .partial() satisfies z.ZodType; - - const jsonGeneratorOptions = z - .strictObject({ - JSONParse: z.boolean() - }) - .partial() satisfies z.ZodType; - - const generatorOptionsByModuleTypeKnown = z - .strictObject({ - asset: assetGeneratorOptions, - "asset/inline": assetInlineGeneratorOptions, - "asset/resource": assetResourceGeneratorOptions, - css: cssGeneratorOptions, - "css/auto": cssAutoGeneratorOptions, - "css/module": cssModuleGeneratorOptions, - json: jsonGeneratorOptions - }) - .partial() satisfies z.ZodType; - - const generatorOptionsByModuleType = generatorOptionsByModuleTypeKnown; - - const noParseOptionSingle = z - .string() - .or(z.instanceof(RegExp)) - .or(anyFunction); - const noParseOption = noParseOptionSingle.or( - z.array(noParseOptionSingle) - ) satisfies z.ZodType; - - const moduleOptions = z - .strictObject({ - defaultRules: ruleSetRules, - rules: ruleSetRules, - parser: parserOptionsByModuleType, - generator: generatorOptionsByModuleType, - noParse: noParseOption - }) - .partial() satisfies z.ZodType; - //#endregion - - //#region Target - const allowTarget = z.union([ - z.enum([ - "web", - "webworker", - "es3", - "es5", - "es2015", - "es2016", - "es2017", - "es2018", - "es2019", - "es2020", - "es2021", - "es2022", - "es2023", - "es2024", - "es2025" - ]), - z.literal("node"), - z.literal("async-node"), - z.custom<`node${number}`>( - value => typeof value === "string" && /^node\d+$/.test(value) - ), - z.custom<`async-node${number}`>( - value => typeof value === "string" && /^async-node\d+$/.test(value) - ), - z.custom<`node${number}.${number}`>( - value => typeof value === "string" && /^node\d+\.\d+$/.test(value) - ), - z.custom<`async-node${number}.${number}`>( - value => typeof value === "string" && /^async-node\d+\.\d+$/.test(value) - ), - z.literal("electron-main"), - z.custom<`electron${number}-main`>( - value => typeof value === "string" && /^electron\d+-main$/.test(value) - ), - z.custom<`electron${number}.${number}-main`>( - value => - typeof value === "string" && /^electron\d+\.\d+-main$/.test(value) - ), - z.literal("electron-renderer"), - z.custom<`electron${number}-renderer`>( - value => typeof value === "string" && /^electron\d+-renderer$/.test(value) - ), - z.custom<`electron${number}.${number}-renderer`>( - value => - typeof value === "string" && /^electron\d+\.\d+-renderer$/.test(value) - ), - z.literal("electron-preload"), - z.custom<`electron${number}-preload`>( - value => typeof value === "string" && /^electron\d+-preload$/.test(value) - ), - z.custom<`electron${number}.${number}-preload`>( - value => - typeof value === "string" && /^electron\d+\.\d+-preload$/.test(value) - ), - z.literal("nwjs"), - z.custom<`nwjs${number}`>( - value => typeof value === "string" && /^nwjs\d+$/.test(value) - ), - z.custom<`nwjs${number}.${number}`>( - value => typeof value === "string" && /^nwjs\d+\.\d+$/.test(value) - ), - z.literal("node-webkit"), - z.custom<`node-webkit${number}`>( - value => typeof value === "string" && /^node-webkit\d+$/.test(value) - ), - z.custom<`node-webkit${number}.${number}`>( - value => typeof value === "string" && /^node-webkit\d+\.\d+$/.test(value) - ), - z.literal("browserslist"), - z.custom<`browserslist:${string}`>( - value => typeof value === "string" && /^browserslist:(.+)$/.test(value) - ) - ]); - - const target = z.union([ - z.literal(false), - allowTarget, - allowTarget.array() - ]) satisfies z.ZodType; - //#endregion - - const externalItemObjectValue = z.record( - z.string(), - z.string().or(z.string().array()) - ) satisfies z.ZodType; - - const externalItemUmdValue = z.strictObject({ - root: z.string().or(z.string().array()), - commonjs: z.string().or(z.string().array()), - commonjs2: z.string().or(z.string().array()), - amd: z.string().or(z.string().array()) - }) satisfies z.ZodType; - - const externalUmdChecker: z.core.CheckFn = ctx => { - let isLibraryUmd = false; - const config = ctx.value; - const library = config?.output?.library; - if (typeof library === "object" && "type" in library) { - isLibraryUmd = library.type === "umd"; - } else { - isLibraryUmd = config?.output?.libraryTarget === "umd"; - } - - if (!isLibraryUmd) { - return; - } - - if ( - config?.externalsType !== undefined && - config?.externalsType !== "umd" - ) { - return; - } - - if (!Array.isArray(config?.externals)) { - checkExternalItem(config?.externals, ["externals"]); - } else { - config.externals.forEach((external, index) => - checkExternalItem(external, ["externals", index]) - ); - } - - function checkExternalItem( - externalItem: t.ExternalItem | undefined, - path: (string | number)[] - ) { - if (typeof externalItem === "object" && externalItem !== null) { - for (const [key, value] of Object.entries(externalItem)) { - checkExternalItemValue(value, [...path, key]); - } - } - } - - function checkExternalItemValue( - externalItemValue: t.ExternalItemValue | undefined, - path: (string | number)[] - ) { - if (typeof externalItemValue === "object" && externalItemValue !== null) { - const result = externalItemUmdValue.safeParse(externalItemValue); - if (!result.success) { - ctx.issues.push({ - code: "custom", - message: `External object must have "root", "commonjs", "commonjs2", "amd" properties when "libraryType" or "externalsType" is "umd"`, - input: externalItemValue, - path - }); - } - return; - } - } - }; - - // #region Externals - const externalItemValue = z - .string() - .or(z.boolean()) - .or(z.string().array().min(1)) - .or(externalItemObjectValue) satisfies z.ZodType; - - const externalItemObjectUnknown = z.record( - z.string(), - externalItemValue - ) satisfies z.ZodType; - - const externalItem = z - .string() - .or(z.instanceof(RegExp)) - .or(externalItemObjectUnknown) - .or(anyFunction) satisfies z.ZodType; - - const externals = externalItem - .array() - .or(externalItem) satisfies z.ZodType; - - //#region ExternalsPresets - const externalsPresets = z - .strictObject({ - node: z.boolean(), - web: z.boolean(), - webAsync: z.boolean(), - electron: z.boolean(), - electronMain: z.boolean(), - electronPreload: z.boolean(), - electronRenderer: z.boolean(), - nwjs: z.boolean() - }) - .partial() satisfies z.ZodType; - //#endregion - - //#region InfrastructureLogging - const filterItemTypes = z - .instanceof(RegExp) - .or(z.string()) - .or(anyFunction) satisfies z.ZodType; - - const filterTypes = filterItemTypes - .array() - .or(filterItemTypes) satisfies z.ZodType; - - const infrastructureLogging = z - .strictObject({ - appendOnly: z.boolean(), - colors: z.boolean(), - console: z.custom(), - debug: z.boolean().or(filterTypes), - level: z.enum(["none", "error", "warn", "info", "log", "verbose"]), - stream: z.custom() - }) - .partial() satisfies z.ZodType; - //#endregion - - //#region DevTool - const devTool = z - .literal(false) - .or(z.literal("eval")) - .or( - z.string().refine( - val => { - // Pattern: [inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map[-debugids] - const pattern = - /^(inline-|hidden-|eval-)?(nosources-)?(cheap-(module-)?)?source-map(-debugids)?$/; - return pattern.test(val); - }, - { - error: - "Expect value to match the pattern: [inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map[-debugids]" - } - ) as z.ZodType - ) satisfies z.ZodType; - //#endregion - - //#region Node - const nodeOptions = z - .strictObject({ - __dirname: z - .boolean() - .or(z.enum(["warn-mock", "mock", "eval-only", "node-module"])), - __filename: z - .boolean() - .or(z.enum(["warn-mock", "mock", "eval-only", "node-module"])), - global: z.boolean().or(z.literal("warn")) - }) - .partial() satisfies z.ZodType; - - const node = z.literal(false).or(nodeOptions) satisfies z.ZodType; - - const loader = z.record(z.string(), z.any()) satisfies z.ZodType; - //#endregion - - //#region Snapshot - const snapshotOptions = z.strictObject( - {} - ) satisfies z.ZodType; - //#endregion - - //#region Cache - const cacheOptions = z.boolean() satisfies z.ZodType; - //#endregion - - //#region Stats - const statsPresets = z.enum([ - "normal", - "none", - "verbose", - "errors-only", - "errors-warnings", - "minimal", - "detailed", - "summary" - ]); - const statsOptions = z - .strictObject({ - all: z.boolean(), - preset: z.boolean().or(statsPresets), - assets: z.boolean(), - chunks: z.boolean(), - modules: z.boolean(), - entrypoints: z.boolean().or(z.literal("auto")), - chunkGroups: z.boolean(), - warnings: z.boolean(), - warningsCount: z.boolean(), - errors: z.boolean(), - errorsCount: z.boolean(), - colors: z.boolean(), - hash: z.boolean(), - version: z.boolean(), - reasons: z.boolean(), - publicPath: z.boolean(), - outputPath: z.boolean(), - chunkModules: z.boolean(), - chunkRelations: z.boolean(), - ids: z.boolean(), - timings: z.boolean(), - builtAt: z.boolean(), - moduleAssets: z.boolean(), - nestedModules: z.boolean(), - source: z.boolean(), - logging: z - .enum(["none", "error", "warn", "info", "log", "verbose"]) - .or(z.boolean()), - loggingDebug: z.boolean().or(filterTypes), - loggingTrace: z.boolean(), - runtimeModules: z.boolean(), - children: z.boolean(), - usedExports: z.boolean(), - providedExports: z.boolean(), - optimizationBailout: z.boolean(), - groupModulesByType: z.boolean(), - groupModulesByCacheStatus: z.boolean(), - groupModulesByLayer: z.boolean(), - groupModulesByAttributes: z.boolean(), - groupModulesByPath: z.boolean(), - groupModulesByExtension: z.boolean(), - modulesSpace: intOrInfinity, - chunkModulesSpace: intOrInfinity, - nestedModulesSpace: intOrInfinity, - relatedAssets: z.boolean(), - groupAssetsByEmitStatus: z.boolean(), - groupAssetsByInfo: z.boolean(), - groupAssetsByPath: z.boolean(), - groupAssetsByExtension: z.boolean(), - groupAssetsByChunk: z.boolean(), - assetsSpace: intOrInfinity, - orphanModules: z.boolean(), - excludeModules: z - .array(z.string().or(z.instanceof(RegExp)).or(anyFunction)) - .or(z.string()) - .or(z.instanceof(RegExp)) - .or(anyFunction) - .or(z.boolean()), - excludeAssets: z - .array(z.string().or(z.instanceof(RegExp)).or(anyFunction)) - .or(z.string()) - .or(z.instanceof(RegExp)) - .or(anyFunction), - modulesSort: z.string(), - chunkModulesSort: z.string(), - nestedModulesSort: z.string(), - chunksSort: z.string(), - assetsSort: z.string(), - performance: z.boolean(), - env: z.boolean(), - chunkGroupAuxiliary: z.boolean(), - chunkGroupChildren: z.boolean(), - chunkGroupMaxAssets: numberOrInfinity, - dependentModules: z.boolean(), - chunkOrigins: z.boolean(), - runtime: z.boolean(), - depth: z.boolean(), - reasonsSpace: intOrInfinity, - groupReasonsByOrigin: z.boolean(), - errorDetails: z.boolean(), - errorStack: z.boolean(), - moduleTrace: z.boolean(), - cachedModules: z.boolean(), - cachedAssets: z.boolean(), - cached: z.boolean(), - errorsSpace: intOrInfinity, - warningsSpace: intOrInfinity - }) - .partial() satisfies z.ZodType; - - const statsValue = z - .boolean() - .or(statsPresets) - .or(statsOptions) satisfies z.ZodType; - //#endregion - - //#region Plugins - const plugin = z.union([ - z.custom< - | t.RspackPluginInstance - | t.RspackPluginFunction - | t.WebpackPluginInstance - | t.WebpackPluginFunction - >(), - falsy - ]) satisfies z.ZodType; - - const plugins = plugin.array() satisfies z.ZodType; - //#endregion - - //#region Optimization - const optimizationRuntimeChunk = z - .enum(["single", "multiple"]) - .or(z.boolean()) - .or( - z - .strictObject({ - name: z.string().or(anyFunction) - }) - .partial() - ) satisfies z.ZodType; - - const optimizationSplitChunksNameFunction = - anyFunction satisfies z.ZodType; - - const optimizationSplitChunksName = z - .string() - .or(z.literal(false)) - .or(optimizationSplitChunksNameFunction); - const optimizationSplitChunksChunks = z - .enum(["initial", "async", "all"]) - .or(z.instanceof(RegExp)) - .or(anyFunction); - const optimizationSplitChunksSizes = numberOrInfinity.or( - z.record(z.string(), numberOrInfinity) - ); - const optimizationSplitChunksDefaultSizeTypes = z.array(z.string()); - - const sharedOptimizationSplitChunksCacheGroup = { - chunks: optimizationSplitChunksChunks, - defaultSizeTypes: optimizationSplitChunksDefaultSizeTypes, - minChunks: z.number().min(1).or(z.literal(Number.POSITIVE_INFINITY)), - usedExports: z.boolean(), - name: optimizationSplitChunksName, - filename: filename, - minSize: optimizationSplitChunksSizes, - minSizeReduction: optimizationSplitChunksSizes, - maxSize: optimizationSplitChunksSizes, - maxAsyncSize: optimizationSplitChunksSizes, - maxInitialSize: optimizationSplitChunksSizes, - maxAsyncRequests: numberOrInfinity, - maxInitialRequests: numberOrInfinity, - automaticNameDelimiter: z.string() - }; - - const optimizationSplitChunksCacheGroup = z - .strictObject({ - test: z.string().or(z.instanceof(RegExp)).or(anyFunction), - priority: numberOrInfinity, - enforce: z.boolean(), - reuseExistingChunk: z.boolean(), - type: z.string().or(z.instanceof(RegExp)), - idHint: z.string(), - layer: z.string().or(z.instanceof(RegExp)).or(anyFunction), - ...sharedOptimizationSplitChunksCacheGroup - }) - .partial() satisfies z.ZodType; - - const optimizationSplitChunksOptions = z - .strictObject({ - cacheGroups: z.record( - z.string(), - z.literal(false).or(optimizationSplitChunksCacheGroup) - ), - fallbackCacheGroup: z - .strictObject({ - chunks: optimizationSplitChunksChunks, - minSize: numberOrInfinity, - maxSize: numberOrInfinity, - maxAsyncSize: numberOrInfinity, - maxInitialSize: numberOrInfinity, - automaticNameDelimiter: z.string() - }) - .partial(), - hidePathInfo: z.boolean(), - ...sharedOptimizationSplitChunksCacheGroup - }) - .partial() satisfies z.ZodType; - - const optimization = z - .strictObject({ - moduleIds: z.enum(["named", "natural", "deterministic"]), - chunkIds: z.enum([ - "natural", - "named", - "deterministic", - "size", - "total-size" - ]), - minimize: z.boolean(), - minimizer: z.literal("...").or(plugin).array(), - mergeDuplicateChunks: z.boolean(), - splitChunks: z.literal(false).or(optimizationSplitChunksOptions), - runtimeChunk: optimizationRuntimeChunk, - removeAvailableModules: z.boolean(), - removeEmptyChunks: z.boolean(), - realContentHash: z.boolean(), - sideEffects: z.enum(["flag"]).or(z.boolean()), - providedExports: z.boolean(), - concatenateModules: z.boolean(), - innerGraph: z.boolean(), - usedExports: z.enum(["global"]).or(z.boolean()), - mangleExports: z.enum(["size", "deterministic"]).or(z.boolean()), - nodeEnv: z.union([z.string(), z.literal(false)]), - emitOnErrors: z.boolean(), - avoidEntryIife: z.boolean() - }) - .partial() satisfies z.ZodType; - //#endregion - - //#region Experiments - const rspackFutureOptions = z - .strictObject({ - bundlerInfo: z - .strictObject({ - version: z.string(), - bundler: z.string(), - force: z.boolean().or(z.array(z.enum(["version", "uniqueId"]))) - }) - .partial() - }) - .partial() satisfies z.ZodType; - - const experimentCacheOptions = z - .object({ - type: z.enum(["memory"]) - }) - .or( - z.object({ - type: z.enum(["persistent"]), - buildDependencies: z.string().array().optional(), - version: z.string().optional(), - snapshot: z - .object({ - immutablePaths: z - .string() - .or(z.instanceof(RegExp)) - .array() - .optional(), - unmanagedPaths: z - .string() - .or(z.instanceof(RegExp)) - .array() - .optional(), - managedPaths: z.string().or(z.instanceof(RegExp)).array().optional() - }) - .optional(), - storage: z - .object({ - type: z.enum(["filesystem"]), - directory: z.string().optional() - }) - .optional() - }) - ); - - const lazyCompilationOptions = z - .object({ - imports: z.boolean(), - entries: z.boolean(), - test: z.instanceof(RegExp).or(anyFunction), - client: z.string(), - serverUrl: z.string(), - prefix: z.string() - }) - .partial() satisfies z.ZodType; - - const incremental = z - .strictObject({ - silent: z.boolean(), - make: z.boolean(), - inferAsyncModules: z.boolean(), - providedExports: z.boolean(), - dependenciesDiagnostics: z.boolean(), - sideEffects: z.boolean(), - buildChunkGraph: z.boolean(), - moduleIds: z.boolean(), - chunkIds: z.boolean(), - modulesHashes: z.boolean(), - modulesCodegen: z.boolean(), - modulesRuntimeRequirements: z.boolean(), - chunksRuntimeRequirements: z.boolean(), - chunksHashes: z.boolean(), - chunksRender: z.boolean(), - emitAssets: z.boolean() - }) - .partial() satisfies z.ZodType; - - // Define buildHttp options schema - const buildHttpOptions = z.object({ - allowedUris: z.array(z.union([z.string(), z.instanceof(RegExp)])), - lockfileLocation: z.string().optional(), - cacheLocation: z.union([z.string(), z.literal(false)]).optional(), - upgrade: z.boolean().optional(), - // proxy: z.string().optional(), - // frozen: z.boolean().optional(), - httpClient: anyFunction.optional() - }) satisfies z.ZodType; - - const useInputFileSystem = z.union([ - z.literal(false), - z.array(z.instanceof(RegExp)) - ]) satisfies z.ZodType; - - const experiments = z - .strictObject({ - cache: z.boolean().or(experimentCacheOptions), - lazyCompilation: z.boolean().or(lazyCompilationOptions), - asyncWebAssembly: z.boolean(), - outputModule: z.boolean(), - topLevelAwait: z.boolean(), - css: z.boolean(), - layers: z.boolean(), - incremental: z - .boolean() - .or(z.literal("safe")) - .or(z.literal("advance")) - .or(z.literal("advance-silent")) - .or(incremental), - parallelCodeSplitting: z.boolean(), - futureDefaults: z.boolean(), - rspackFuture: rspackFutureOptions, - buildHttp: buildHttpOptions, - parallelLoader: z.boolean(), - useInputFileSystem: useInputFileSystem, - inlineConst: z.boolean(), - inlineEnum: z.boolean(), - typeReexportsPresence: z.boolean(), - lazyBarrel: z.boolean(), - nativeWatcher: z.boolean() - }) - .partial() satisfies z.ZodType; - //#endregion - - //#region Watch - const watch = z.boolean() satisfies z.ZodType; - //#endregion - - //#region WatchOptions - const watchOptions = z - .strictObject({ - aggregateTimeout: numberOrInfinity, - followSymlinks: z.boolean(), - ignored: z.string().array().or(z.instanceof(RegExp)).or(z.string()), - poll: numberOrInfinity.or(z.boolean()), - stdin: z.boolean() - }) - .partial() satisfies z.ZodType; - //#endregion - - //#region DevServer - const devServer = z.custom(); - //#endregion - - //#region IgnoreWarnings - const ignoreWarnings = z - .instanceof(RegExp) - .or(anyFunction) - .or( - z.object({ - file: z.instanceof(RegExp).optional(), - message: z.instanceof(RegExp).optional(), - module: z.instanceof(RegExp).optional() - }) - ) - .array() satisfies z.ZodType; - //#endregion - - //#region Profile - const profile = z.boolean() satisfies z.ZodType; - //#endregion - - //#region Amd - const amd = z - .literal(false) - .or(z.record(z.string(), z.any())) satisfies z.ZodType; - //#endregion - - //#region Bail - const bail = z.boolean() satisfies z.ZodType; - //#endregion - - //#region Performance - const performance = z - .strictObject({ - assetFilter: anyFunction, - hints: z.enum(["error", "warning"]).or(z.literal(false)), - maxAssetSize: numberOrInfinity, - maxEntrypointSize: numberOrInfinity - }) - .partial() - .or(z.literal(false)) satisfies z.ZodType; - //#endregion - - const rspackOptions = z - .strictObject({ - name: name, - dependencies: dependencies, - extends: z.union([z.string(), z.array(z.string())]), - entry: entry, - output: output, - target: target, - mode: mode, - experiments: experiments, - externals: externals, - externalsType: getExternalsTypeSchema(), - externalsPresets: externalsPresets, - infrastructureLogging: infrastructureLogging, - cache: cacheOptions, - context: context, - devtool: devTool, - node: node, - loader: loader, - ignoreWarnings: ignoreWarnings, - watchOptions: watchOptions, - watch: watch, - stats: statsValue, - snapshot: snapshotOptions, - optimization: optimization, - resolve: resolveOptions, - resolveLoader: resolveOptions, - plugins: plugins, - devServer: devServer, - module: moduleOptions, - profile: profile, - amd: amd, - bail: bail, - performance: performance, - lazyCompilation: z.boolean().or(lazyCompilationOptions).optional() - }) - .partial() - .check(externalUmdChecker) satisfies z.ZodType; - - return rspackOptions; -}); diff --git a/packages/rspack/src/schema/loaders.ts b/packages/rspack/src/schema/loaders.ts deleted file mode 100644 index 736a43f58934..000000000000 --- a/packages/rspack/src/schema/loaders.ts +++ /dev/null @@ -1,444 +0,0 @@ -import type { - AmdConfig, - BaseModuleConfig, - CommonJsConfig, - Config, - ConstModulesConfig, - EnvConfig, - Es6Config, - GlobalPassOption, - JscConfig, - JscTarget, - JsFormatOptions, - JsMinifyOptions, - ModuleConfig, - NodeNextConfig, - OptimizerConfig, - ReactConfig, - SystemjsConfig, - TerserEcmaVersion, - TerserMangleOptions, - TransformConfig, - UmdConfig -} from "@swc/types"; -import type { Assumptions } from "@swc/types/assumptions"; -import * as z from "zod"; -import type { CollectTypeScriptInfoOptions } from "../builtin-loader/swc/collectTypeScriptInfo"; -import type { PluginImportOptions } from "../builtin-loader/swc/pluginImport"; -import type { - SwcLoaderOptions, - TerserCompressOptions -} from "../builtin-loader/swc/types"; -import { memoize } from "../util/memoize"; -import { numberOrInfinity } from "./utils"; - -export const getZodSwcLoaderOptionsSchema = memoize(() => { - const ZodSwcEnvConfig = z - .strictObject({ - mode: z.enum(["usage", "entry"]), - debug: z.boolean(), - dynamicImport: z.boolean(), - loose: z.boolean(), - bugfixes: z.boolean(), - skip: z.string().array(), - include: z.string().array(), - exclude: z.string().array(), - coreJs: z.string(), - targets: z.any(), - path: z.string(), - shippedProposals: z.boolean(), - forceAllTransforms: z.boolean() - }) - .partial() satisfies z.ZodType; - - const ZodSwcAssumptions = z - .strictObject({ - arrayLikeIsIterable: z.boolean(), - constantReexports: z.boolean(), - constantSuper: z.boolean(), - enumerableModuleMeta: z.boolean(), - ignoreFunctionLength: z.boolean(), - ignoreFunctionName: z.boolean(), - ignoreToPrimitiveHint: z.boolean(), - iterableIsArray: z.boolean(), - mutableTemplateObject: z.boolean(), - noClassCalls: z.boolean(), - noDocumentAll: z.boolean(), - noIncompleteNsImportDetection: z.boolean(), - noNewArrows: z.boolean(), - objectRestNoSymbols: z.boolean(), - privateFieldsAsProperties: z.boolean(), - pureGetters: z.boolean(), - setClassMethods: z.boolean(), - setComputedProperties: z.boolean(), - setPublicClassFields: z.boolean(), - setSpreadProperties: z.boolean(), - skipForOfIteratorClosing: z.boolean(), - superIsCallableConstructor: z.boolean(), - tsEnumIsReadonly: z.boolean() - }) - .partial() satisfies z.ZodType; - - const ZodSwcParserConfig = z.strictObject({ - syntax: z.enum(["typescript", "ecmascript"]), - // typescript only - tsx: z.boolean().optional(), - decorators: z.boolean().optional(), - dynamicImport: z.boolean().optional(), - // ecmascript only - jsx: z.boolean().optional(), - numericSeparator: z.boolean().optional(), - classPrivateProperty: z.boolean().optional(), - privateMethod: z.boolean().optional(), - classProperty: z.boolean().optional(), - functionBind: z.boolean().optional(), - // decorators: z.boolean().optional(), - decoratorsBeforeExport: z.boolean().optional(), - exportDefaultFrom: z.boolean().optional(), - exportNamespaceFrom: z.boolean().optional(), - // dynamicImport: z.boolean().optional(), - nullishCoalescing: z.boolean().optional(), - optionalChaining: z.boolean().optional(), - importMeta: z.boolean().optional(), - topLevelAwait: z.boolean().optional(), - importAssertions: z.boolean().optional(), - importAttributes: z.boolean().optional(), - allowSuperOutsideMethod: z.boolean().optional(), - allowReturnOutsideFunction: z.boolean().optional(), - autoAccessors: z.boolean().optional(), - explicitResourceManagement: z.boolean().optional() - }); - - const ZodSwcJscTarget = z.enum([ - "es3", - "es5", - "es2015", - "es2016", - "es2017", - "es2018", - "es2019", - "es2020", - "es2021", - "es2022", - "es2023", - "es2024", - "esnext" - ]) satisfies z.ZodType; - - const ZodSwcTerserEcmaVersion = z.union([ - z.literal(5), - z.literal(2015), - z.literal(2016), - z.string(), - z.int() - ]) satisfies z.ZodType; - - const ZodSwcJsFormatOptions = z - .strictObject({ - asciiOnly: z.boolean(), - beautify: z.boolean(), - braces: z.boolean(), - comments: z.literal("some").or(z.literal("all")).or(z.literal(false)), - ecma: ZodSwcTerserEcmaVersion, - indentLevel: z.int(), - indentStart: z.int(), - inlineScript: z.boolean(), - keepNumbers: z.int(), - keepQuotedProps: z.boolean(), - maxLineLen: numberOrInfinity, - preamble: z.string(), - quoteKeys: z.boolean(), - quoteStyle: z.boolean(), - preserveAnnotations: z.boolean(), - safari10: z.boolean(), - semicolons: z.boolean(), - shebang: z.boolean(), - webkit: z.boolean(), - wrapIife: z.boolean(), - wrapFuncArgs: z.boolean() - }) - .partial() satisfies z.ZodType; - - const ZodSwcTerserCompressOptions = z - .strictObject({ - arguments: z.boolean(), - arrows: z.boolean(), - booleans: z.boolean(), - booleans_as_integers: z.boolean(), - collapse_vars: z.boolean(), - comparisons: z.boolean(), - computed_props: z.boolean(), - conditionals: z.boolean(), - dead_code: z.boolean(), - defaults: z.boolean(), - directives: z.boolean(), - drop_console: z.boolean(), - drop_debugger: z.boolean(), - ecma: ZodSwcTerserEcmaVersion, - evaluate: z.boolean(), - expression: z.boolean(), - global_defs: z.any(), - hoist_funs: z.boolean(), - hoist_props: z.boolean(), - hoist_vars: z.boolean(), - ie8: z.boolean(), - if_return: z.boolean(), - inline: z.literal(0).or(z.literal(1)).or(z.literal(2)).or(z.literal(3)), - join_vars: z.boolean(), - keep_classnames: z.boolean(), - keep_fargs: z.boolean(), - keep_fnames: z.boolean(), - keep_infinity: z.boolean(), - loops: z.boolean(), - negate_iife: z.boolean(), - passes: numberOrInfinity, - properties: z.boolean(), - pure_getters: z.any(), - pure_funcs: z.string().array(), - reduce_funcs: z.boolean(), - reduce_vars: z.boolean(), - sequences: z.any(), - side_effects: z.boolean(), - switches: z.boolean(), - top_retain: z.any(), - toplevel: z.any(), - typeofs: z.boolean(), - unsafe: z.boolean(), - unsafe_passes: z.boolean(), - unsafe_arrows: z.boolean(), - unsafe_comps: z.boolean(), - unsafe_function: z.boolean(), - unsafe_math: z.boolean(), - unsafe_symbols: z.boolean(), - unsafe_methods: z.boolean(), - unsafe_proto: z.boolean(), - unsafe_regexp: z.boolean(), - unsafe_undefined: z.boolean(), - unused: z.boolean(), - const_to_let: z.boolean(), - module: z.boolean() - }) - .partial() satisfies z.ZodType; - - const ZodSwcTerserMangleOptions = z - .strictObject({ - props: z.record(z.string(), z.any()), - topLevel: z.boolean(), - toplevel: z.boolean(), - keepClassNames: z.boolean(), - keep_classnames: z.boolean(), - keepFnNames: z.boolean(), - keep_fnames: z.boolean(), - keepPrivateProps: z.boolean(), - keep_private_props: z.boolean(), - ie8: z.boolean(), - safari10: z.boolean(), - reserved: z.string().array() - }) - .partial() satisfies z.ZodType; - - const ZodSwcReactConfig = z - .strictObject({ - pragma: z.string(), - pragmaFrag: z.string(), - throwIfNamespace: z.boolean(), - development: z.boolean(), - useBuiltins: z.boolean(), - refresh: z.boolean().or( - z - .strictObject({ - refreshReg: z.string(), - refreshSig: z.string(), - emitFullSignatures: z.boolean() - }) - .partial() - ), - runtime: z.enum(["automatic", "classic", "preserve"]), - importSource: z.string() - }) - .partial() satisfies z.ZodType; - - const ZodSwcConstModulesConfig = z.strictObject({ - globals: z.record(z.string(), z.record(z.string(), z.string())).optional() - }) satisfies z.ZodType; - - const ZodSwcGlobalPassOption = z - .strictObject({ - vars: z.record(z.string(), z.string()), - envs: z.union([z.string().array(), z.record(z.string(), z.string())]), - typeofs: z.record(z.string(), z.string()) - }) - .partial() satisfies z.ZodType; - - const ZodSwcOptimizerConfig = z - .strictObject({ - simplify: z.boolean(), - globals: ZodSwcGlobalPassOption, - jsonify: z.strictObject({ - minCost: numberOrInfinity - }) - }) - .partial() satisfies z.ZodType; - - const ZodSwcTransformConfig = z - .strictObject({ - react: ZodSwcReactConfig, - constModules: ZodSwcConstModulesConfig, - optimizer: ZodSwcOptimizerConfig, - legacyDecorator: z.boolean(), - decoratorMetadata: z.boolean(), - decoratorVersion: z.enum(["2021-12", "2022-03"]), - treatConstEnumAsEnum: z.boolean(), - tsEnumIsMutable: z.boolean(), - useDefineForClassFields: z.boolean(), - verbatimModuleSyntax: z.boolean() - }) - .partial() satisfies z.ZodType; - - const ZodSwcJsMinifyOptions = z - .strictObject({ - compress: z.union([ZodSwcTerserCompressOptions, z.boolean()]), - format: ZodSwcJsFormatOptions, - mangle: z.union([ZodSwcTerserMangleOptions, z.boolean()]), - ecma: ZodSwcTerserEcmaVersion, - keep_classnames: z.boolean(), - keep_fnames: z.boolean(), - module: z.union([z.boolean(), z.literal("unknown")]), - safari10: z.boolean(), - toplevel: z.boolean(), - sourceMap: z.boolean(), - outputPath: z.string(), - inlineSourcesContent: z.boolean() - }) - .partial() satisfies z.ZodType; - - const ZodSwcJscConfig = z - .strictObject({ - assumptions: ZodSwcAssumptions, - loose: z.boolean(), - parser: ZodSwcParserConfig, - transform: ZodSwcTransformConfig, - externalHelpers: z.boolean(), - target: ZodSwcJscTarget, - keepClassNames: z.boolean(), - experimental: z - .strictObject({ - optimizeHygiene: z.boolean(), - keepImportAttributes: z.boolean(), - emitAssertForImportAttributes: z.boolean(), - cacheRoot: z.string(), - plugins: z.array( - z.tuple([z.string(), z.record(z.string(), z.any())]) - ), - runPluginFirst: z.boolean(), - disableBuiltinTransformsForInternalTesting: z.boolean(), - emitIsolatedDts: z.boolean(), - disableAllLints: z.boolean(), - keepImportAssertions: z.boolean() - }) - .partial(), - baseUrl: z.string(), - paths: z.record(z.string(), z.string().array()), - minify: ZodSwcJsMinifyOptions, - preserveAllComments: z.boolean(), - output: z.strictObject({ - charset: z.enum(["utf8", "ascii"]).optional() - }) - }) - .partial() satisfies z.ZodType; - - const ZodSwcBaseModuleConfig = z - .strictObject({ - strict: z.boolean(), - strictMode: z.boolean(), - lazy: z.union([z.boolean(), z.string().array()]), - noInterop: z.boolean(), - importInterop: z.enum(["swc", "babel", "node", "none"]), - outFileExtension: z.enum(["js", "mjs", "cjs"]), - exportInteropAnnotation: z.boolean(), - ignoreDynamic: z.boolean(), - allowTopLevelThis: z.boolean(), - preserveImportMeta: z.boolean() - }) - .partial() satisfies z.ZodType; - - const ZodSwcEs6Config = ZodSwcBaseModuleConfig.extend({ - type: z.literal("es6") - }) satisfies z.ZodType; - - const ZodSwcNodeNextConfig = ZodSwcBaseModuleConfig.extend({ - type: z.literal("nodenext") - }) satisfies z.ZodType; - - const ZodSwcCommonJsConfig = ZodSwcBaseModuleConfig.extend({ - type: z.literal("commonjs") - }) satisfies z.ZodType; - - const ZodSwcUmdConfig = ZodSwcBaseModuleConfig.extend({ - type: z.literal("umd"), - globals: z.record(z.string(), z.string()).optional() - }) satisfies z.ZodType; - - const ZodSwcAmdConfig = ZodSwcBaseModuleConfig.extend({ - type: z.literal("amd"), - moduleId: z.string().optional() - }) satisfies z.ZodType; - - const ZodSwcSystemjsConfig = z.strictObject({ - type: z.literal("systemjs"), - allowTopLevelThis: z.boolean().optional() - }) satisfies z.ZodType; - - const ZodSwcModuleConfig = z.union([ - ZodSwcEs6Config, - ZodSwcCommonJsConfig, - ZodSwcUmdConfig, - ZodSwcAmdConfig, - ZodSwcNodeNextConfig, - ZodSwcSystemjsConfig - ]) satisfies z.ZodType; - - const ZodSwcConfig = z - .strictObject({ - $schema: z.string(), - test: z.string().or(z.string().array()), - exclude: z.string().or(z.string().array()), - env: ZodSwcEnvConfig, - jsc: ZodSwcJscConfig, - module: ZodSwcModuleConfig, - minify: z.boolean(), - sourceMaps: z.boolean().or(z.literal("inline")), - inlineSourcesContent: z.boolean() - }) - .partial() satisfies z.ZodType; - - const ZodSwcCollectTypeScriptInfo = z.strictObject({ - typeExports: z.boolean().optional(), - exportedEnum: z.boolean().or(z.literal("const-only")).optional() - }) satisfies z.ZodType; - - const ZodSwcPluginImportConfig = z - .strictObject({ - libraryName: z.string(), - libraryDirectory: z.string().optional(), - customName: z.string().optional(), - customStyleName: z.string().optional(), - style: z.string().or(z.boolean()).optional(), - styleLibraryDirectory: z.string().optional(), - camelToDashComponentName: z.boolean().optional(), - transformToDefaultImport: z.boolean().optional(), - ignoreEsComponent: z.string().array().optional(), - ignoreStyleComponent: z.string().array().optional() - }) - .array() satisfies z.ZodType; - - return ZodSwcConfig.extend({ - isModule: z.boolean().or(z.literal("unknown")), - rspackExperiments: z - .strictObject({ - import: ZodSwcPluginImportConfig, - collectTypeScriptInfo: ZodSwcCollectTypeScriptInfo - }) - .partial() - }).partial() satisfies z.ZodType; -}); diff --git a/packages/rspack/src/schema/plugins.ts b/packages/rspack/src/schema/plugins.ts deleted file mode 100644 index d5cc70cae281..000000000000 --- a/packages/rspack/src/schema/plugins.ts +++ /dev/null @@ -1,180 +0,0 @@ -import type { JsBuildMeta } from "@rspack/binding"; -import * as z from "zod"; -import type { - HtmlRspackPluginOptions, - TemplateParamFunction, - TemplateRenderFunction -} from "../builtin-plugin/html-plugin"; -import type { IgnorePluginOptions } from "../builtin-plugin/IgnorePlugin"; -import type { RsdoctorPluginOptions } from "../builtin-plugin/RsdoctorPlugin"; -import type { SubresourceIntegrityPluginOptions } from "../builtin-plugin/SubresourceIntegrityPlugin"; -import type { DllPluginOptions } from "../lib/DllPlugin"; -import type { - DllReferencePluginOptions, - DllReferencePluginOptionsContent, - DllReferencePluginOptionsManifest, - DllReferencePluginOptionsSourceType -} from "../lib/DllReferencePlugin"; -import { memoize } from "../util/memoize"; -import { anyFunction, numberOrInfinity } from "./utils"; - -export const getIgnorePluginOptionsSchema = memoize( - () => - z.union([ - z.object({ - contextRegExp: z.instanceof(RegExp).optional(), - resourceRegExp: z.instanceof(RegExp) - }), - z.object({ - checkResource: anyFunction - }) - ]) satisfies z.ZodType -); - -export const getRsdoctorPluginSchema = memoize( - () => - z.strictObject({ - moduleGraphFeatures: z - .union([z.boolean(), z.array(z.enum(["graph", "ids", "sources"]))]) - .optional(), - chunkGraphFeatures: z - .union([z.boolean(), z.array(z.enum(["graph", "assets"]))]) - .optional(), - sourceMapFeatures: z - .object({ - module: z.boolean().optional(), - cheap: z.boolean().optional() - }) - .optional() - }) satisfies z.ZodType -); - -export const getSRIPluginOptionsSchema = memoize(() => { - const hashFunctionSchema = z.enum(["sha256", "sha384", "sha512"]); - - return z.object({ - hashFuncNames: z - .tuple([hashFunctionSchema]) - .rest(hashFunctionSchema) - .optional(), - htmlPlugin: z.string().or(z.literal(false)).optional(), - enabled: z.literal("auto").or(z.boolean()).optional() - }) satisfies z.ZodType; -}); - -export const getDllPluginOptionsSchema = memoize( - () => - z.object({ - context: z.string().optional(), - entryOnly: z.boolean().optional(), - format: z.boolean().optional(), - name: z.string().optional(), - path: z.string(), - type: z.string().optional() - }) satisfies z.ZodType -); - -export const getDllReferencePluginOptionsSchema = memoize(() => { - const dllReferencePluginOptionsContentItem = z - .object({ - buildMeta: z.custom(), - exports: z.array(z.string()).or(z.literal(true)), - id: z.string().or(numberOrInfinity) - }) - .partial(); - - const dllReferencePluginOptionsContent = z.record( - z.string(), - dllReferencePluginOptionsContentItem - ) satisfies z.ZodType; - - const dllReferencePluginOptionsSourceType = z.enum([ - "var", - "assign", - "this", - "window", - "global", - "commonjs", - "commonjs2", - "commonjs-module", - "amd", - "amd-require", - "umd", - "umd2", - "jsonp", - "system" - ]) satisfies z.ZodType; - - const dllReferencePluginOptionsManifest = z.object({ - content: dllReferencePluginOptionsContent, - name: z.string().optional(), - type: dllReferencePluginOptionsSourceType.optional() - }) satisfies z.ZodType; - - const dllReferencePluginOptions = z.union([ - z.object({ - context: z.string().optional(), - extensions: z.array(z.string()).optional(), - manifest: z.string().or(dllReferencePluginOptionsManifest), - name: z.string().optional(), - scope: z.string().optional(), - sourceType: dllReferencePluginOptionsSourceType.optional(), - type: z.enum(["require", "object"]).optional() - }), - z.object({ - content: dllReferencePluginOptionsContent, - context: z.string().optional(), - extensions: z.array(z.string()).optional(), - name: z.string(), - scope: z.string().optional(), - sourceType: dllReferencePluginOptionsSourceType.optional(), - type: z.enum(["require", "object"]).optional() - }) - ]) satisfies z.ZodType; - - return dllReferencePluginOptions; -}); - -export const getHtmlPluginOptionsSchema = memoize(() => { - const templateRenderFunction = - anyFunction satisfies z.ZodType; - const templateParamFunction = - anyFunction satisfies z.ZodType; - - return z - .object({ - filename: z.string().or(anyFunction), - template: z.string().refine(val => !val.includes("!"), { - error: "HtmlRspackPlugin does not support template path with loader yet" - }), - templateContent: z.string().or(templateRenderFunction), - templateParameters: z - .record(z.string(), z.string()) - .or(z.boolean()) - .or(templateParamFunction), - inject: z.enum(["head", "body"]).or(z.boolean()), - publicPath: z.string(), - base: z.string().or( - z - .strictObject({ - href: z.string(), - target: z.enum(["_self", "_blank", "_parent", "_top"]) - }) - .partial() - ), - scriptLoading: z.enum(["blocking", "defer", "module", "systemjs-module"]), - chunks: z.string().array(), - excludeChunks: z.string().array(), - chunksSortMode: z.enum(["auto", "manual"]), - sri: z.enum(["sha256", "sha384", "sha512"]), - minify: z.boolean(), - title: z.string(), - favicon: z.string(), - meta: z.record( - z.string(), - z.string().or(z.record(z.string(), z.string())) - ), - hash: z.boolean() - }) - .partial() satisfies z.ZodType; -}); diff --git a/packages/rspack/src/schema/utils.ts b/packages/rspack/src/schema/utils.ts deleted file mode 100644 index 6e3412c5ca15..000000000000 --- a/packages/rspack/src/schema/utils.ts +++ /dev/null @@ -1,20 +0,0 @@ -import * as z from "zod"; - -// Zod v4 doesn't support Infinity, so we need to use a custom type -// See: https://github.com/colinhacks/zod/issues/4721 -export const numberOrInfinity = z - .number() - .or(z.literal(Number.POSITIVE_INFINITY)); - -export const intOrInfinity = z.int().or(z.literal(Number.POSITIVE_INFINITY)); - -export const anyFunction = z.custom<(...args: unknown[]) => any>( - data => typeof data === "function", - // Make the similar error message as zod v3 - // https://github.com/colinhacks/zod/blob/64bfb7001cf6f2575bf38b5e6130bc73b4b0e371/packages/zod/src/v3/types.ts#L3821-L3828 - { - error: input => ({ - message: `Expected function, received ${z.core.util.getParsedType(input)}` - }) - } -); diff --git a/packages/rspack/src/schema/validate.ts b/packages/rspack/src/schema/validate.ts deleted file mode 100644 index e4384fbae55b..000000000000 --- a/packages/rspack/src/schema/validate.ts +++ /dev/null @@ -1,105 +0,0 @@ -import type { z } from "zod"; -import { fromZodError } from "zod-validation-error"; - -export class ValidationError extends Error { - constructor(message: string) { - super(message); - this.name = "ValidationError"; - } -} - -export function validate( - opts: any, - createSchema: () => T, - options: { - output?: boolean; - strategy?: "strict" | "loose-unrecognized-keys" | "loose-silent" | "loose"; - } = {} -): string | null { - const strategy = - options.strategy ?? process.env.RSPACK_CONFIG_VALIDATE ?? "strict"; - - // Skip schema validation if the strategy is `loose-silent` - if (strategy === "loose-silent") { - return null; - } - - const schema = - typeof createSchema === "function" ? createSchema() : createSchema; - const res = schema.safeParse(opts); - - if (!res.success) { - const output = options.output ?? true; - - let friendlyErr: ValidationError; - const originalIssues = res.error.issues; - - // Issues with code `unrecognized_keys` are ignored. Other issues are thrown. - // This does not work when `zodError.issues` is empty so we need to check the length of `zodError.issues`. - // See: https://github.com/causaly/zod-validation-error/blob/62684ba47cba9cbd84e2a75dfd5fd06dcd0e1ad5/lib/fromZodError.ts#L53 - if (strategy === "loose-unrecognized-keys" && res.error.issues.length > 0) { - // This is based on the invariant that `fromZodError` always reads `zodError.errors` first and - // `zodError.errors` always returns `zodError.issues`: - // See: https://github.com/causaly/zod-validation-error/blob/62684ba47cba9cbd84e2a75dfd5fd06dcd0e1ad5/lib/fromZodError.ts#L55 - // Also see: https://github.com/colinhacks/zod/blob/8552233c77426f77d3586cc877f7aec1aa0aa45b/src/ZodError.ts#L200 - const unrecognizedKeys = originalIssues.filter( - issue => issue.code === "unrecognized_keys" - ); - if (unrecognizedKeys.length > 0) { - friendlyErr = toValidationError({ - ...res.error, - issues: unrecognizedKeys - }); - if (output) { - console.error(friendlyErr.message); - } - } - const issuesWithoutUnrecognizedKeys = originalIssues.filter( - issue => issue.code !== "unrecognized_keys" - ); - if (issuesWithoutUnrecognizedKeys.length > 0) { - throw toValidationError({ - ...res.error, - issues: issuesWithoutUnrecognizedKeys - }); - } - return output || !friendlyErr! ? null : friendlyErr.message; - } - - if (strategy === "loose-unrecognized-keys" || strategy === "loose") { - friendlyErr = toValidationError(res.error); - if (output) { - console.error(friendlyErr.message); - } - return output ? null : friendlyErr.message; - } - - // strict - friendlyErr = toValidationError(res.error); - throw friendlyErr; - } - return null; -} - -function toValidationError(error: z.ZodError): ValidationError { - const separator = "\n- "; - const validationErr = fromZodError(error, { - prefix: - "Invalid configuration object. Rspack has been initialized using a configuration object that does not match the API schema.", - prefixSeparator: separator, - issueSeparator: separator - }); - return new ValidationError(validationErr.message); -} - -export function isValidate( - opts: any, - createSchema: () => T -) { - try { - validate(opts, createSchema); - return true; - } catch { - return false; - } -} diff --git a/packages/rspack/src/util/index.ts b/packages/rspack/src/util/index.ts index 6abfffff0569..091d56fd3459 100644 --- a/packages/rspack/src/util/index.ts +++ b/packages/rspack/src/util/index.ts @@ -59,13 +59,6 @@ export function stringifyLoaderObject(o: LoaderObject): string { return o.path + o.query + o.fragment; } -export function asArray(item: T[]): T[]; -export function asArray(item: readonly T[]): readonly T[]; -export function asArray(item: T): T[]; -export function asArray(item: T | T[]): T[] { - return Array.isArray(item) ? item : [item]; -} - export const unsupported = (name: string, issue?: string) => { let s = `${name} is not supported by rspack.`; if (issue) { diff --git a/packages/rspack/src/util/validateConfig.ts b/packages/rspack/src/util/validateConfig.ts new file mode 100644 index 000000000000..0bc95d4d368d --- /dev/null +++ b/packages/rspack/src/util/validateConfig.ts @@ -0,0 +1,89 @@ +import { isAbsolute } from "node:path"; +import type { + Configuration, + ExternalItem, + ExternalItemUmdValue +} from "../config"; + +const ERROR_PREFIX = "Invalid Rspack configuration:"; + +const validateContext = ({ context }: Configuration) => { + if (context && !isAbsolute(context)) { + throw new Error( + `${ERROR_PREFIX} "context" must be an absolute path, get "${context}".` + ); + } +}; + +const validateSplitChunks = ({ optimization }: Configuration) => { + if (optimization?.splitChunks) { + const { minChunks } = optimization.splitChunks; + if (minChunks !== undefined && minChunks < 1) { + throw new Error( + `${ERROR_PREFIX} "optimization.splitChunks.minChunks" must be greater than or equal to 1, get \`${minChunks}\`.` + ); + } + } +}; + +const validateExternalUmd = ({ + output, + externals, + externalsType +}: Configuration) => { + let isLibraryUmd = false; + const library = output?.library; + + if (typeof library === "object" && "type" in library) { + isLibraryUmd = library.type === "umd"; + } else { + isLibraryUmd = output?.libraryTarget === "umd"; + } + + if ( + !isLibraryUmd || + (externalsType !== undefined && externalsType !== "umd") + ) { + return; + } + + const checkExternalItem = (externalItem: ExternalItem | undefined) => { + if (typeof externalItem === "object" && externalItem !== null) { + for (const value of Object.values(externalItem)) { + checkExternalItemValue(value); + } + } + }; + + const checkExternalItemValue = (value: ExternalItemUmdValue | undefined) => { + if (!value || typeof value !== "object") { + return; + } + + const requiredKeys = ["root", "commonjs", "commonjs2", "amd"] as const; + if (requiredKeys.some(key => value[key] === undefined)) { + throw new Error( + `${ERROR_PREFIX} External object must have "root", "commonjs", "commonjs2", "amd" properties when "libraryType" or "externalsType" is "umd", get: ${JSON.stringify( + value, + null, + 2 + )}.` + ); + } + }; + + if (!Array.isArray(externals)) { + checkExternalItem(externals); + } else { + externals.forEach(external => checkExternalItem(external)); + } +}; + +/** + * Performs configuration validation that cannot be covered by TypeScript types. + */ +export function validateRspackConfig(config: Configuration) { + validateContext(config); + validateSplitChunks(config); + validateExternalUmd(config); +} diff --git a/packages/rspack/tsconfig.browser.json b/packages/rspack/tsconfig.browser.json index 5b5176b5f760..c2891006577f 100644 --- a/packages/rspack/tsconfig.browser.json +++ b/packages/rspack/tsconfig.browser.json @@ -3,13 +3,14 @@ "compilerOptions": { "outDir": "../rspack-browser/dist", "rootDir": "src", + "lib": ["es2022", "dom"], "resolveJsonModule": true, "emitDeclarationOnly": true, "sourceMap": false, "declarationMap": false }, "include": ["src", "src/**/*.json"], - "exclude": ["src/config/schema.check.js", "src/container/default.runtime.js"], + "exclude": ["src/container/default.runtime.js"], "ts-node": { "transpileOnly": true } diff --git a/packages/rspack/tsconfig.json b/packages/rspack/tsconfig.json index 0d464c4b8b2a..12626bc91629 100644 --- a/packages/rspack/tsconfig.json +++ b/packages/rspack/tsconfig.json @@ -3,6 +3,7 @@ "compilerOptions": { "outDir": "dist", "rootDir": "src", + "lib": ["es2022", "dom"], "emitDeclarationOnly": true, "paths": { "watchpack": ["./compiled/watchpack"], diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a3906680693c..7434309517b6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -326,6 +326,9 @@ importers: '@swc/types': specifier: 0.1.25 version: 0.1.25 + '@types/node': + specifier: ^20.19.21 + version: 20.19.21 '@types/watchpack': specifier: ^2.4.4 version: 2.4.4 @@ -359,12 +362,6 @@ importers: webpack-sources: specifier: 3.3.3 version: 3.3.3(patch_hash=b2a26650f08a2359d0a3cd81fa6fa272aa7441a28dd7e601792da5ed5d2b4aee) - zod: - specifier: ^4.1.12 - version: 4.1.12 - zod-validation-error: - specifier: ^4.0.2 - version: 4.0.2(zod@4.1.12) packages/rspack-browser: dependencies: @@ -3505,12 +3502,6 @@ packages: '@types/node-forge@1.3.14': resolution: {integrity: sha512-mhVF2BnD4BO+jtOp7z1CdzaK4mbuK0LLQYAvdOLqHTavxFNq4zA1EmYkpnFjP8HOUzedfQkRnp0E2ulSAYSzAw==} - '@types/node@20.19.18': - resolution: {integrity: sha512-KeYVbfnbsBCyKG8e3gmUqAfyZNcoj/qpEbHRkQkfZdKOBrU7QQ+BsTdfqLSWX9/m1ytYreMhpKvp+EZi3UFYAg==} - - '@types/node@20.19.20': - resolution: {integrity: sha512-2Q7WS25j4pS1cS8yw3d6buNCVJukOTeQ39bAnwR6sOJbaxvyCGebzTMypDFN82CxBLnl+lSWVdCCWbRY6y9yZQ==} - '@types/node@20.19.21': resolution: {integrity: sha512-CsGG2P3I5y48RPMfprQGfy4JPRZ6csfC3ltBZSRItG3ngggmNY/qs2uZKp4p9VbrpqNNSMzUZNFZKzgOGnd/VA==} @@ -8626,12 +8617,6 @@ packages: resolution: {integrity: sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==} engines: {node: '>=18'} - zod-validation-error@4.0.2: - resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==} - engines: {node: '>=18.0.0'} - peerDependencies: - zod: ^3.25.0 || ^4.0.0 - zod@4.1.12: resolution: {integrity: sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==} @@ -9802,7 +9787,7 @@ snapshots: '@jest/transform': 29.7.0 '@jest/types': 29.6.3 '@jridgewell/trace-mapping': 0.3.31 - '@types/node': 20.19.20 + '@types/node': 20.19.21 chalk: 4.1.2 collect-v8-coverage: 1.0.2 exit: 0.1.2 @@ -11224,13 +11209,13 @@ snapshots: '@types/fs-extra@11.0.4': dependencies: '@types/jsonfile': 6.1.4 - '@types/node': 20.19.18 + '@types/node': 20.19.21 '@types/geojson@7946.0.16': {} '@types/graceful-fs@4.1.9': dependencies: - '@types/node': 20.19.18 + '@types/node': 20.19.21 '@types/hast@3.0.4': dependencies: @@ -11267,7 +11252,7 @@ snapshots: '@types/jsdom@21.1.7': dependencies: - '@types/node': 20.19.18 + '@types/node': 20.19.21 '@types/tough-cookie': 4.0.5 parse5: 7.3.0 @@ -11291,14 +11276,6 @@ snapshots: dependencies: '@types/node': 20.19.21 - '@types/node@20.19.18': - dependencies: - undici-types: 6.21.0 - - '@types/node@20.19.20': - dependencies: - undici-types: 6.21.0 - '@types/node@20.19.21': dependencies: undici-types: 6.21.0 @@ -11352,11 +11329,11 @@ snapshots: '@types/watchpack@2.4.4': dependencies: '@types/graceful-fs': 4.1.9 - '@types/node': 20.19.18 + '@types/node': 20.19.21 '@types/webpack-bundle-analyzer@4.7.0': dependencies: - '@types/node': 20.19.18 + '@types/node': 20.19.21 tapable: 2.2.3 webpack: 5.99.9 transitivePeerDependencies: @@ -14106,7 +14083,7 @@ snapshots: '@jest/environment': 29.7.0 '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 - '@types/node': 20.19.20 + '@types/node': 20.19.21 jest-mock: 29.7.0 jest-util: 29.7.0 @@ -17321,10 +17298,6 @@ snapshots: yoctocolors-cjs@2.1.3: {} - zod-validation-error@4.0.2(zod@4.1.12): - dependencies: - zod: 4.1.12 - zod@4.1.12: {} zwitch@2.0.4: {} diff --git a/tests/rspack-test/Cache.test.js b/tests/rspack-test/Cache.test.js index a04edadf8331..8e891bd0f57d 100644 --- a/tests/rspack-test/Cache.test.js +++ b/tests/rspack-test/Cache.test.js @@ -1,5 +1,3 @@ -process.env.RSPACK_CONFIG_VALIDATE = "loose-silent"; - const path = require("path"); const { describeByWalk, createCacheCase } = require("@rspack/test-tools"); const tempDir = path.resolve(__dirname, `./js/temp`); diff --git a/tests/rspack-test/Incremental-async-node.test.js b/tests/rspack-test/Incremental-async-node.test.js index b4933760af41..080103a6584f 100644 --- a/tests/rspack-test/Incremental-async-node.test.js +++ b/tests/rspack-test/Incremental-async-node.test.js @@ -1,5 +1,3 @@ -process.env.RSPACK_CONFIG_VALIDATE = "loose-silent"; - const path = require("path"); const { describeByWalk, diff --git a/tests/rspack-test/Incremental-node.test.js b/tests/rspack-test/Incremental-node.test.js index 275bed3e9602..3c65ab300e2a 100644 --- a/tests/rspack-test/Incremental-node.test.js +++ b/tests/rspack-test/Incremental-node.test.js @@ -1,5 +1,3 @@ -process.env.RSPACK_CONFIG_VALIDATE = "loose-silent"; - const path = require("path"); const { describeByWalk, diff --git a/tests/rspack-test/Incremental-watch.test.js b/tests/rspack-test/Incremental-watch.test.js index 004623f0ad12..b238239fe8ad 100644 --- a/tests/rspack-test/Incremental-watch.test.js +++ b/tests/rspack-test/Incremental-watch.test.js @@ -1,5 +1,4 @@ process.env.RSPACK_INCREMENTAL_WATCH_TEST = true; -process.env.RSPACK_CONFIG_VALIDATE = "loose-silent"; const path = require("path"); const { diff --git a/tests/rspack-test/Incremental-web.test.js b/tests/rspack-test/Incremental-web.test.js index 44dbe8a217af..98c14322db50 100644 --- a/tests/rspack-test/Incremental-web.test.js +++ b/tests/rspack-test/Incremental-web.test.js @@ -1,5 +1,3 @@ -process.env.RSPACK_CONFIG_VALIDATE = "loose-silent"; - const path = require("path"); const { describeByWalk, diff --git a/tests/rspack-test/Incremental-webworker.test.js b/tests/rspack-test/Incremental-webworker.test.js index f236af89834c..06d5d80cc5f1 100644 --- a/tests/rspack-test/Incremental-webworker.test.js +++ b/tests/rspack-test/Incremental-webworker.test.js @@ -1,5 +1,3 @@ -process.env.RSPACK_CONFIG_VALIDATE = "loose-silent"; - const path = require("path"); const { describeByWalk, diff --git a/tests/rspack-test/Validation.test.js b/tests/rspack-test/Validation.test.js deleted file mode 100644 index aa468be80302..000000000000 --- a/tests/rspack-test/Validation.test.js +++ /dev/null @@ -1,298 +0,0 @@ -describe("Validation", () => { - const createTestCase = (name, config, fn, strategy, fn2) => { - it(`should fail validation for ${name}`, () => { - let prevStrategy = process.env.RSPACK_CONFIG_VALIDATE; - process.env.RSPACK_CONFIG_VALIDATE = strategy; - let errors = []; - console.error = (...args) => { - errors.push(...args); - }; - try { - const { rspack } = require("@rspack/core"); - rspack(config); - } catch (err) { - if (err.name !== "ValidationError") throw err; - - if (strategy === "loose") { - throw new Error("Validation should not be failed in loose mode"); - } - - expect(err.message).toMatch(/^Invalid configuration object/); - fn(err.message); - - return; - } finally { - if (strategy === "loose" || strategy === "loose-unrecognized-keys") { - if (typeof fn2 !== "function") { - throw new Error("Should provide a function for error testing"); - } - fn2(errors); - } - process.env.RSPACK_CONFIG_VALIDATE = prevStrategy; - } - - // Only in strict mode(default mode), we expect the validation always to fail - // loose-unrecognized-keys and loose mode will ignore the additional properties and log a warning - // loose-unrecognized-keys will fail the validation if the errors returned are not only unrecognized keys - if (strategy === "strict" || !strategy) { - throw new Error("Validation didn't fail"); - } - }); - }; - - describe("loose-unrecognized-keys", () => { - createTestCase( - "additional properties in loose-unrecognized-keys should be ignored", - { - _additionalProperty: "test" - }, - message => { - throw new Error("should not have error"); - }, - "loose-unrecognized-keys", - log => { - expect(log).toMatchInlineSnapshot(` - Array [ - Invalid configuration object. Rspack has been initialized using a configuration object that does not match the API schema. - - Unrecognized key(s) "_additionalProperty" in object, - ] - `); - } - ); - - createTestCase( - "additional properties recursive in loose-unrecognized-keys should be ignored", - { - optimization: { - _additionalProperty: "test" - } - }, - message => { - throw new Error("should not have error"); - }, - "loose-unrecognized-keys", - log => { - expect(log).toMatchInlineSnapshot(` - Array [ - Invalid configuration object. Rspack has been initialized using a configuration object that does not match the API schema. - - Unrecognized key(s) "_additionalProperty" in object at "optimization", - ] - `); - } - ); - - createTestCase( - "loose-unrecognized-keys should fail if the errors returned are other issues than unrecognized keys", - { - context: "./" - }, - message => { - expect(message).toMatchInlineSnapshot(` - Invalid configuration object. Rspack has been initialized using a configuration object that does not match the API schema. - - The provided value "./" must be an absolute path at "context" - `); - }, - "loose-unrecognized-keys", - log => { - expect(log).toMatchInlineSnapshot(`Array []`); - } - ); - - createTestCase( - "loose-unrecognized-keys should print warning and error at the same time if both kinds of errors are returned", - { - context: "./", - _additionalProperty: "test" - }, - message => { - expect(message).toMatchInlineSnapshot(` - Invalid configuration object. Rspack has been initialized using a configuration object that does not match the API schema. - - The provided value "./" must be an absolute path at "context" - `); - }, - "loose-unrecognized-keys", - log => { - expect(log).toMatchInlineSnapshot(` - Array [ - Invalid configuration object. Rspack has been initialized using a configuration object that does not match the API schema. - - Unrecognized key(s) "_additionalProperty" in object, - ] - `); - } - ); - }); - - describe("loose", () => { - createTestCase( - "should not be failed for any errors", - { - context: "./", - _additionalProperty: "test", - optimization: { - _additionalProperty: "test" - } - }, - message => { - throw new Error("should not have error"); - }, - "loose", - log => { - expect(log).toMatchInlineSnapshot(` - Array [ - Invalid configuration object. Rspack has been initialized using a configuration object that does not match the API schema. - - The provided value "./" must be an absolute path at "context" - - Unrecognized key(s) "_additionalProperty" in object at "optimization" - - Unrecognized key(s) "_additionalProperty" in object, - ] - `); - } - ); - - createTestCase( - "function type", - { - ignoreWarnings: [new Map()], - output: { - devtoolModuleFilenameTemplate: new Set() - } - }, - message => { - throw new Error("should not have error"); - }, - "loose", - log => { - expect(log).toMatchInlineSnapshot(` - Array [ - Invalid configuration object. Rspack has been initialized using a configuration object that does not match the API schema. - - Expected string, received set at "output.devtoolModuleFilenameTemplate" or Expected function, received object at "output.devtoolModuleFilenameTemplate", - ] - `); - } - ); - }); - - describe("strict", () => { - createTestCase( - "not absolute context", - { - context: "./" - }, - message => { - expect(message).toMatchInlineSnapshot(` - Invalid configuration object. Rspack has been initialized using a configuration object that does not match the API schema. - - The provided value "./" must be an absolute path at "context" - `); - }, - "strict", - log => { - throw new Error("should not have log"); - } - ); - - createTestCase( - "unrecognized keys", - { - context: "./", - _additionalProperty: "test", - optimization: { - _additionalProperty: "test" - } - }, - message => { - expect(message).toMatchInlineSnapshot(` - Invalid configuration object. Rspack has been initialized using a configuration object that does not match the API schema. - - The provided value "./" must be an absolute path at "context" - - Unrecognized key(s) "_additionalProperty" in object at "optimization" - - Unrecognized key(s) "_additionalProperty" in object - `); - }, - "strict", - log => { - throw new Error("should not have log"); - } - ); - - createTestCase( - "function type", - { - ignoreWarnings: [new Map()], - output: { - devtoolModuleFilenameTemplate: new Set(), - filename: [] - } - }, - message => { - expect(message).toMatchInlineSnapshot(` - Invalid configuration object. Rspack has been initialized using a configuration object that does not match the API schema. - - Expected string, received array at "output.filename" or Expected function, received object at "output.filename" - - Expected string, received set at "output.devtoolModuleFilenameTemplate" or Expected function, received object at "output.devtoolModuleFilenameTemplate" - `); - }, - "strict", - log => { - throw new Error("should not have log"); - } - ); - }); - - describe("default (strict)", () => { - createTestCase( - "not absolute context", - { - context: "./" - }, - message => { - expect(message).toMatchInlineSnapshot(` - Invalid configuration object. Rspack has been initialized using a configuration object that does not match the API schema. - - The provided value "./" must be an absolute path at "context" - `); - }, - log => { - throw new Error("should not have log"); - } - ); - - createTestCase( - "unrecognized keys", - { - context: "./", - _additionalProperty: "test", - optimization: { - _additionalProperty: "test" - } - }, - message => { - expect(message).toMatchInlineSnapshot(` - Invalid configuration object. Rspack has been initialized using a configuration object that does not match the API schema. - - The provided value "./" must be an absolute path at "context" - - Unrecognized key(s) "_additionalProperty" in object at "optimization" - - Unrecognized key(s) "_additionalProperty" in object - `); - }, - log => { - throw new Error("should not have log"); - } - ); - - createTestCase( - "function type", - { - ignoreWarnings: [new Map()], - output: { - devtoolModuleFilenameTemplate: new Set(), - filename: [] - } - }, - message => { - expect(message).toMatchInlineSnapshot(` - Invalid configuration object. Rspack has been initialized using a configuration object that does not match the API schema. - - Expected string, received array at "output.filename" or Expected function, received object at "output.filename" - - Expected string, received set at "output.devtoolModuleFilenameTemplate" or Expected function, received object at "output.devtoolModuleFilenameTemplate" - `); - }, - log => { - throw new Error("should not have log"); - } - ); - }); -}); diff --git a/tests/rspack-test/compilerCases/splitchunks-minchunks.js b/tests/rspack-test/compilerCases/splitchunks-minchunks.js index 2175ac87243e..0b7a3ce93475 100644 --- a/tests/rspack-test/compilerCases/splitchunks-minchunks.js +++ b/tests/rspack-test/compilerCases/splitchunks-minchunks.js @@ -26,7 +26,7 @@ module.exports = { expect(Array.isArray(errors)).toBeTruthy(); expect(errors.length).toBe(1); expect(errors[0].toString()).toContain( - 'Number must be greater than or equal to 1 at "optimization.splitChunks.minChunks"' + 'Invalid Rspack configuration: "optimization.splitChunks.minChunks" must be greater than or equal to 1, get `0`.' ); context.clearError(name); } diff --git a/tests/rspack-test/configCases/builtin-swc-loader/validate/errors.js b/tests/rspack-test/configCases/builtin-swc-loader/validate/errors.js index f413f44372a7..36b6a0bb3a7d 100644 --- a/tests/rspack-test/configCases/builtin-swc-loader/validate/errors.js +++ b/tests/rspack-test/configCases/builtin-swc-loader/validate/errors.js @@ -1,5 +1,3 @@ module.exports = [ - [ - /Invalid options for 'builtin:swc-loader'/ - ], + [/unknown field `syntax`/], ]; diff --git a/tests/rspack-test/configCases/builtin-swc-loader/validate/rspack.config.js b/tests/rspack-test/configCases/builtin-swc-loader/validate/rspack.config.js index bb77e21d4f81..6d73db0e7375 100644 --- a/tests/rspack-test/configCases/builtin-swc-loader/validate/rspack.config.js +++ b/tests/rspack-test/configCases/builtin-swc-loader/validate/rspack.config.js @@ -11,7 +11,9 @@ module.exports = { { loader: "builtin:swc-loader", options: { - myFn: () => {} + jsc: { + syntax: "unknown" + } } } ], diff --git a/tests/rspack-test/configCases/errors/rspack-issue-4504/errors.js b/tests/rspack-test/configCases/errors/rspack-issue-4504/errors.js deleted file mode 100644 index c8241e058753..000000000000 --- a/tests/rspack-test/configCases/errors/rspack-issue-4504/errors.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = [ - [/Expected value to be one of "md4", "xxhash64" or "sha256" at "output.hashFunction"/] -]; diff --git a/tests/rspack-test/configCases/errors/rspack-issue-4504/index.js b/tests/rspack-test/configCases/errors/rspack-issue-4504/index.js deleted file mode 100644 index 06c48b1a2315..000000000000 --- a/tests/rspack-test/configCases/errors/rspack-issue-4504/index.js +++ /dev/null @@ -1,5 +0,0 @@ -function add(a, b) { - return a + b; -} - -add(1, 2); diff --git a/tests/rspack-test/configCases/errors/rspack-issue-4504/rspack.config.js b/tests/rspack-test/configCases/errors/rspack-issue-4504/rspack.config.js deleted file mode 100644 index f3af038fe4b2..000000000000 --- a/tests/rspack-test/configCases/errors/rspack-issue-4504/rspack.config.js +++ /dev/null @@ -1,6 +0,0 @@ -/** @type {import('@rspack/core').Configuration} */ -module.exports = { - output: { - hashFunction: "abc" - } -}; diff --git a/tests/rspack-test/configCases/externals/umd-validation-failed-no-externals-type/errors.js b/tests/rspack-test/configCases/externals/umd-validation-failed-no-externals-type/errors.js index 9d32d63c9561..9166762bff5c 100644 --- a/tests/rspack-test/configCases/externals/umd-validation-failed-no-externals-type/errors.js +++ b/tests/rspack-test/configCases/externals/umd-validation-failed-no-externals-type/errors.js @@ -1 +1,3 @@ -module.exports = [/External object must have "root", "commonjs", "commonjs2", "amd" properties when "libraryType" or "externalsType" is "umd" at "externals.lodash"/]; \ No newline at end of file +module.exports = [ + /Invalid Rspack configuration: External object must have "root", "commonjs", "commonjs2", "amd" properties when "libraryType" or "externalsType" is "umd", get:/ +]; diff --git a/tests/rspack-test/configCases/externals/umd-validation-failed/errors.js b/tests/rspack-test/configCases/externals/umd-validation-failed/errors.js index 9d32d63c9561..9166762bff5c 100644 --- a/tests/rspack-test/configCases/externals/umd-validation-failed/errors.js +++ b/tests/rspack-test/configCases/externals/umd-validation-failed/errors.js @@ -1 +1,3 @@ -module.exports = [/External object must have "root", "commonjs", "commonjs2", "amd" properties when "libraryType" or "externalsType" is "umd" at "externals.lodash"/]; \ No newline at end of file +module.exports = [ + /Invalid Rspack configuration: External object must have "root", "commonjs", "commonjs2", "amd" properties when "libraryType" or "externalsType" is "umd", get:/ +]; diff --git a/website/docs/en/guide/migration/webpack.mdx b/website/docs/en/guide/migration/webpack.mdx index f69fd95158ef..ad30b19dfc2b 100644 --- a/website/docs/en/guide/migration/webpack.mdx +++ b/website/docs/en/guide/migration/webpack.mdx @@ -51,17 +51,6 @@ Rspack commands can specify the configuration file with `-c` or `--config`, simi However, unlike webpack, if a configuration file is not explicitly specified, Rspack defaults to using `rspack.config.js`. ::: -Rspack does not currently support all webpack configurations, and some configurations might affect the build output. -To ensure the correctness of the build output, Rspack enables strict validation of the configurations by default. -However, Rspack also provides a loose mode for easy progressive migration. You can enable it by setting the `RSPACK_CONFIG_VALIDATE` environment variable: - -```bash -# Enabling loose validation mode will print out erroneous configurations but will not throw an error. -RSPACK_CONFIG_VALIDATE=loose rspack build -# Enable loose validation mode, without printing errors or throwing an error. -RSPACK_CONFIG_VALIDATE=loose-silent rspack build -``` - Rspack is actively working on implementing webpack's upcoming features, so some configuration defaults differ from webpack 5, as shown below: | Configuration | webpack Default | Rspack Default | diff --git a/website/docs/zh/guide/migration/webpack.mdx b/website/docs/zh/guide/migration/webpack.mdx index e4db998cf568..ff472ba9ac03 100644 --- a/website/docs/zh/guide/migration/webpack.mdx +++ b/website/docs/zh/guide/migration/webpack.mdx @@ -49,16 +49,6 @@ Rspack 的配置是基于 webpack 的设计实现的,以此你能够非常轻 Rspack 命令与 webpack 命令相同,均可通过 `-c` 或 `--config` 指定配置文件。但与 webpack 不同的是,如果你未显式指定配置文件,Rspack 默认使用 `rspack.config.js`。 ::: -Rspack 目前并不支持所有 webpack 配置,有些配置会影响构建产物,为保证构建产物的正确性,Rspack 默认开启了对配置的严格校验。 -不过,Rspack 也提供了宽松模式,方便进行渐进式迁移。你可以通过设置 `RSPACK_CONFIG_VALIDATE` 环境变量来开启宽松模式: - -```bash -# 开启宽松校验模式,会打印错误的配置但不会抛出错误 -RSPACK_CONFIG_VALIDATE=loose rspack build -# 开启宽松校验模式,不打印错误也不抛出错误 -RSPACK_CONFIG_VALIDATE=loose-silent rspack build -``` - Rspack 正在积极推动 webpack 的下一个版本的功能,因此在部分配置项上与 webpack 5 的默认值不同,如下: | 配置 | webpack 默认值 | Rspack 默认值 |