diff --git a/packages/rspack/src/builtin-loader/swc/types.ts b/packages/rspack/src/builtin-loader/swc/types.ts index 3a0800f4f5c2..cee4c694866c 100644 --- a/packages/rspack/src/builtin-loader/swc/types.ts +++ b/packages/rspack/src/builtin-loader/swc/types.ts @@ -26,6 +26,7 @@ import type { } from "@swc/types"; import type { Assumptions } from "@swc/types/assumptions"; import { z } from "zod"; +import { memoize } from "../../util/memoize"; import { type PluginImportOptions, ZodSwcPluginImportConfig @@ -48,129 +49,6 @@ export type SwcLoaderOptions = Config & { }; }; -const ZodSwcEnvConfig = z.strictObject({ - mode: z.enum(["usage", "entry"]).optional(), - debug: z.boolean().optional(), - dynamicImport: z.boolean().optional(), - loose: z.boolean().optional(), - bugfixes: z.boolean().optional(), - skip: z.string().array().optional(), - include: z.string().array().optional(), - exclude: z.string().array().optional(), - coreJs: z.string().optional(), - targets: z.any().optional(), - path: z.string().optional(), - shippedProposals: z.boolean().optional(), - forceAllTransforms: z.boolean().optional() -}) satisfies z.ZodType; - -const ZodSwcAssumptions = z.strictObject({ - arrayLikeIsIterable: z.boolean().optional(), - constantReexports: z.boolean().optional(), - constantSuper: z.boolean().optional(), - enumerableModuleMeta: z.boolean().optional(), - ignoreFunctionLength: z.boolean().optional(), - ignoreFunctionName: z.boolean().optional(), - ignoreToPrimitiveHint: z.boolean().optional(), - iterableIsArray: z.boolean().optional(), - mutableTemplateObject: z.boolean().optional(), - noClassCalls: z.boolean().optional(), - noDocumentAll: z.boolean().optional(), - noIncompleteNsImportDetection: z.boolean().optional(), - noNewArrows: z.boolean().optional(), - objectRestNoSymbols: z.boolean().optional(), - privateFieldsAsProperties: z.boolean().optional(), - pureGetters: z.boolean().optional(), - setClassMethods: z.boolean().optional(), - setComputedProperties: z.boolean().optional(), - setPublicClassFields: z.boolean().optional(), - setSpreadProperties: z.boolean().optional(), - skipForOfIteratorClosing: z.boolean().optional(), - superIsCallableConstructor: z.boolean().optional(), - tsEnumIsReadonly: z.boolean().optional() -}) 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.number() -]) satisfies z.ZodType; - -const ZodSwcJsFormatOptions = z.strictObject({ - asciiOnly: z.boolean().optional(), - beautify: z.boolean().optional(), - braces: z.boolean().optional(), - comments: z - .literal("some") - .or(z.literal("all")) - .or(z.literal(false)) - .optional(), - ecma: ZodSwcTerserEcmaVersion.optional(), - indentLevel: z.number().optional(), - indentStart: z.number().optional(), - inlineScript: z.boolean().optional(), - keepNumbers: z.number().optional(), - keepQuotedProps: z.boolean().optional(), - maxLineLen: z.number().optional(), - preamble: z.string().optional(), - quoteKeys: z.boolean().optional(), - quoteStyle: z.boolean().optional(), - preserveAnnotations: z.boolean().optional(), - safari10: z.boolean().optional(), - semicolons: z.boolean().optional(), - shebang: z.boolean().optional(), - webkit: z.boolean().optional(), - wrapIife: z.boolean().optional(), - wrapFuncArgs: z.boolean().optional() -}) satisfies z.ZodType; export interface TerserCompressOptions { arguments?: boolean; arrows?: boolean; @@ -230,255 +108,381 @@ export interface TerserCompressOptions { module?: boolean; } -const ZodSwcTerserCompressOptions = z.strictObject({ - arguments: z.boolean().optional(), - arrows: z.boolean().optional(), - booleans: z.boolean().optional(), - booleans_as_integers: z.boolean().optional(), - collapse_vars: z.boolean().optional(), - comparisons: z.boolean().optional(), - computed_props: z.boolean().optional(), - conditionals: z.boolean().optional(), - dead_code: z.boolean().optional(), - defaults: z.boolean().optional(), - directives: z.boolean().optional(), - drop_console: z.boolean().optional(), - drop_debugger: z.boolean().optional(), - ecma: ZodSwcTerserEcmaVersion.optional(), - evaluate: z.boolean().optional(), - expression: z.boolean().optional(), - global_defs: z.any().optional(), - hoist_funs: z.boolean().optional(), - hoist_props: z.boolean().optional(), - hoist_vars: z.boolean().optional(), - ie8: z.boolean().optional(), - if_return: z.boolean().optional(), - inline: z - .literal(0) - .or(z.literal(1)) - .or(z.literal(2)) - .or(z.literal(3)) - .optional(), - join_vars: z.boolean().optional(), - keep_classnames: z.boolean().optional(), - keep_fargs: z.boolean().optional(), - keep_fnames: z.boolean().optional(), - keep_infinity: z.boolean().optional(), - loops: z.boolean().optional(), - negate_iife: z.boolean().optional(), - passes: z.number().optional(), - properties: z.boolean().optional(), - pure_getters: z.any().optional(), - pure_funcs: z.string().array().optional(), - reduce_funcs: z.boolean().optional(), - reduce_vars: z.boolean().optional(), - sequences: z.any().optional(), - side_effects: z.boolean().optional(), - switches: z.boolean().optional(), - top_retain: z.any().optional(), - toplevel: z.any().optional(), - typeofs: z.boolean().optional(), - unsafe: z.boolean().optional(), - unsafe_passes: z.boolean().optional(), - unsafe_arrows: z.boolean().optional(), - unsafe_comps: z.boolean().optional(), - unsafe_function: z.boolean().optional(), - unsafe_math: z.boolean().optional(), - unsafe_symbols: z.boolean().optional(), - unsafe_methods: z.boolean().optional(), - unsafe_proto: z.boolean().optional(), - unsafe_regexp: z.boolean().optional(), - unsafe_undefined: z.boolean().optional(), - unused: z.boolean().optional(), - const_to_let: z.boolean().optional(), - module: z.boolean().optional() -}) satisfies z.ZodType; +export const getZodSwcLoaderOptionsSchema = memoize(() => { + const ZodSwcEnvConfig = z.strictObject({ + mode: z.enum(["usage", "entry"]).optional(), + debug: z.boolean().optional(), + dynamicImport: z.boolean().optional(), + loose: z.boolean().optional(), + bugfixes: z.boolean().optional(), + skip: z.string().array().optional(), + include: z.string().array().optional(), + exclude: z.string().array().optional(), + coreJs: z.string().optional(), + targets: z.any().optional(), + path: z.string().optional(), + shippedProposals: z.boolean().optional(), + forceAllTransforms: z.boolean().optional() + }) satisfies z.ZodType; -const ZodSwcTerserMangleOptions = z.strictObject({ - props: z.record(z.string(), z.any()).optional(), - topLevel: z.boolean().optional(), - toplevel: z.boolean().optional(), - keepClassNames: z.boolean().optional(), - keep_classnames: z.boolean().optional(), - keepFnNames: z.boolean().optional(), - keep_fnames: z.boolean().optional(), - keepPrivateProps: z.boolean().optional(), - keep_private_props: z.boolean().optional(), - ie8: z.boolean().optional(), - safari10: z.boolean().optional(), - reserved: z.string().array().optional() -}) satisfies z.ZodType; + const ZodSwcAssumptions = z.strictObject({ + arrayLikeIsIterable: z.boolean().optional(), + constantReexports: z.boolean().optional(), + constantSuper: z.boolean().optional(), + enumerableModuleMeta: z.boolean().optional(), + ignoreFunctionLength: z.boolean().optional(), + ignoreFunctionName: z.boolean().optional(), + ignoreToPrimitiveHint: z.boolean().optional(), + iterableIsArray: z.boolean().optional(), + mutableTemplateObject: z.boolean().optional(), + noClassCalls: z.boolean().optional(), + noDocumentAll: z.boolean().optional(), + noIncompleteNsImportDetection: z.boolean().optional(), + noNewArrows: z.boolean().optional(), + objectRestNoSymbols: z.boolean().optional(), + privateFieldsAsProperties: z.boolean().optional(), + pureGetters: z.boolean().optional(), + setClassMethods: z.boolean().optional(), + setComputedProperties: z.boolean().optional(), + setPublicClassFields: z.boolean().optional(), + setSpreadProperties: z.boolean().optional(), + skipForOfIteratorClosing: z.boolean().optional(), + superIsCallableConstructor: z.boolean().optional(), + tsEnumIsReadonly: z.boolean().optional() + }) satisfies z.ZodType; -const ZodSwcReactConfig = z.strictObject({ - pragma: z.string().optional(), - pragmaFrag: z.string().optional(), - throwIfNamespace: z.boolean().optional(), - development: z.boolean().optional(), - useBuiltins: z.boolean().optional(), - refresh: z - .boolean() - .or( - z.strictObject({ - refreshReg: z.string().optional(), - refreshSig: z.string().optional(), - emitFullSignatures: z.boolean().optional() - }) - ) - .optional(), - runtime: z.enum(["automatic", "classic"]).optional(), - importSource: z.string().optional() -}) 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.number() + ]) satisfies z.ZodType; -const ZodSwcConstModulesConfig = z.strictObject({ - globals: z.record(z.string(), z.record(z.string(), z.string())).optional() -}) satisfies z.ZodType; + const ZodSwcJsFormatOptions = z.strictObject({ + asciiOnly: z.boolean().optional(), + beautify: z.boolean().optional(), + braces: z.boolean().optional(), + comments: z + .literal("some") + .or(z.literal("all")) + .or(z.literal(false)) + .optional(), + ecma: ZodSwcTerserEcmaVersion.optional(), + indentLevel: z.number().optional(), + indentStart: z.number().optional(), + inlineScript: z.boolean().optional(), + keepNumbers: z.number().optional(), + keepQuotedProps: z.boolean().optional(), + maxLineLen: z.number().optional(), + preamble: z.string().optional(), + quoteKeys: z.boolean().optional(), + quoteStyle: z.boolean().optional(), + preserveAnnotations: z.boolean().optional(), + safari10: z.boolean().optional(), + semicolons: z.boolean().optional(), + shebang: z.boolean().optional(), + webkit: z.boolean().optional(), + wrapIife: z.boolean().optional(), + wrapFuncArgs: z.boolean().optional() + }) satisfies z.ZodType; -const ZodSwcGlobalPassOption = z.strictObject({ - vars: z.record(z.string(), z.string()).optional(), - envs: z - .union([z.string().array(), z.record(z.string(), z.string())]) - .optional(), - typeofs: z.record(z.string(), z.string()).optional() -}) satisfies z.ZodType; + const ZodSwcTerserCompressOptions = z.strictObject({ + arguments: z.boolean().optional(), + arrows: z.boolean().optional(), + booleans: z.boolean().optional(), + booleans_as_integers: z.boolean().optional(), + collapse_vars: z.boolean().optional(), + comparisons: z.boolean().optional(), + computed_props: z.boolean().optional(), + conditionals: z.boolean().optional(), + dead_code: z.boolean().optional(), + defaults: z.boolean().optional(), + directives: z.boolean().optional(), + drop_console: z.boolean().optional(), + drop_debugger: z.boolean().optional(), + ecma: ZodSwcTerserEcmaVersion.optional(), + evaluate: z.boolean().optional(), + expression: z.boolean().optional(), + global_defs: z.any().optional(), + hoist_funs: z.boolean().optional(), + hoist_props: z.boolean().optional(), + hoist_vars: z.boolean().optional(), + ie8: z.boolean().optional(), + if_return: z.boolean().optional(), + inline: z + .literal(0) + .or(z.literal(1)) + .or(z.literal(2)) + .or(z.literal(3)) + .optional(), + join_vars: z.boolean().optional(), + keep_classnames: z.boolean().optional(), + keep_fargs: z.boolean().optional(), + keep_fnames: z.boolean().optional(), + keep_infinity: z.boolean().optional(), + loops: z.boolean().optional(), + negate_iife: z.boolean().optional(), + passes: z.number().optional(), + properties: z.boolean().optional(), + pure_getters: z.any().optional(), + pure_funcs: z.string().array().optional(), + reduce_funcs: z.boolean().optional(), + reduce_vars: z.boolean().optional(), + sequences: z.any().optional(), + side_effects: z.boolean().optional(), + switches: z.boolean().optional(), + top_retain: z.any().optional(), + toplevel: z.any().optional(), + typeofs: z.boolean().optional(), + unsafe: z.boolean().optional(), + unsafe_passes: z.boolean().optional(), + unsafe_arrows: z.boolean().optional(), + unsafe_comps: z.boolean().optional(), + unsafe_function: z.boolean().optional(), + unsafe_math: z.boolean().optional(), + unsafe_symbols: z.boolean().optional(), + unsafe_methods: z.boolean().optional(), + unsafe_proto: z.boolean().optional(), + unsafe_regexp: z.boolean().optional(), + unsafe_undefined: z.boolean().optional(), + unused: z.boolean().optional(), + const_to_let: z.boolean().optional(), + module: z.boolean().optional() + }) satisfies z.ZodType; -const ZodSwcOptimizerConfig = z.strictObject({ - simplify: z.boolean().optional(), - globals: ZodSwcGlobalPassOption.optional(), - jsonify: z - .strictObject({ - minCost: z.number() - }) - .optional() -}) satisfies z.ZodType; + const ZodSwcTerserMangleOptions = z.strictObject({ + props: z.record(z.string(), z.any()).optional(), + topLevel: z.boolean().optional(), + toplevel: z.boolean().optional(), + keepClassNames: z.boolean().optional(), + keep_classnames: z.boolean().optional(), + keepFnNames: z.boolean().optional(), + keep_fnames: z.boolean().optional(), + keepPrivateProps: z.boolean().optional(), + keep_private_props: z.boolean().optional(), + ie8: z.boolean().optional(), + safari10: z.boolean().optional(), + reserved: z.string().array().optional() + }) satisfies z.ZodType; -const ZodSwcTransformConfig = z.strictObject({ - react: ZodSwcReactConfig.optional(), - constModules: ZodSwcConstModulesConfig.optional(), - optimizer: ZodSwcOptimizerConfig.optional(), - legacyDecorator: z.boolean().optional(), - decoratorMetadata: z.boolean().optional(), - decoratorVersion: z.enum(["2021-12", "2022-03"]).optional(), - treatConstEnumAsEnum: z.boolean().optional(), - useDefineForClassFields: z.boolean().optional(), - verbatimModuleSyntax: z.boolean().optional() -}) satisfies z.ZodType; + const ZodSwcReactConfig = z.strictObject({ + pragma: z.string().optional(), + pragmaFrag: z.string().optional(), + throwIfNamespace: z.boolean().optional(), + development: z.boolean().optional(), + useBuiltins: z.boolean().optional(), + refresh: z + .boolean() + .or( + z.strictObject({ + refreshReg: z.string().optional(), + refreshSig: z.string().optional(), + emitFullSignatures: z.boolean().optional() + }) + ) + .optional(), + runtime: z.enum(["automatic", "classic"]).optional(), + importSource: z.string().optional() + }) satisfies z.ZodType; -const ZodSwcJsMinifyOptions = z.strictObject({ - compress: z.union([ZodSwcTerserCompressOptions, z.boolean()]).optional(), - format: ZodSwcJsFormatOptions.optional(), - mangle: z.union([ZodSwcTerserMangleOptions, z.boolean()]).optional(), - ecma: ZodSwcTerserEcmaVersion.optional(), - keep_classnames: z.boolean().optional(), - keep_fnames: z.boolean().optional(), - module: z.union([z.boolean(), z.literal("unknown")]).optional(), - safari10: z.boolean().optional(), - toplevel: z.boolean().optional(), - sourceMap: z.boolean().optional(), - outputPath: z.string().optional(), - inlineSourcesContent: z.boolean().optional() -}) satisfies z.ZodType; + const ZodSwcConstModulesConfig = z.strictObject({ + globals: z.record(z.string(), z.record(z.string(), z.string())).optional() + }) satisfies z.ZodType; -const ZodSwcJscConfig = z.strictObject({ - assumptions: ZodSwcAssumptions.optional(), - loose: z.boolean().optional(), - parser: ZodSwcParserConfig.optional(), - transform: ZodSwcTransformConfig.optional(), - externalHelpers: z.boolean().optional(), - target: ZodSwcJscTarget.optional(), - keepClassNames: z.boolean().optional(), - experimental: z - .strictObject({ - optimizeHygiene: z.boolean().optional(), - keepImportAttributes: z.boolean().optional(), - emitAssertForImportAttributes: z.boolean().optional(), - cacheRoot: z.string().optional(), - plugins: z - .array(z.tuple([z.string(), z.record(z.string(), z.any())])) - .optional(), - runPluginFirst: z.boolean().optional(), - disableBuiltinTransformsForInternalTesting: z.boolean().optional(), - emitIsolatedDts: z.boolean().optional(), - disableAllLints: z.boolean().optional(), - keepImportAssertions: z.boolean().optional() - }) - .optional(), - baseUrl: z.string().optional(), - paths: z.record(z.string(), z.string().array()).optional(), - minify: ZodSwcJsMinifyOptions.optional(), - preserveAllComments: z.boolean().optional(), - output: z - .strictObject({ - charset: z.enum(["utf8", "ascii"]).optional() - }) - .optional() -}) satisfies z.ZodType; + const ZodSwcGlobalPassOption = z.strictObject({ + vars: z.record(z.string(), z.string()).optional(), + envs: z + .union([z.string().array(), z.record(z.string(), z.string())]) + .optional(), + typeofs: z.record(z.string(), z.string()).optional() + }) satisfies z.ZodType; -const ZodSwcBaseModuleConfig = z.strictObject({ - strict: z.boolean().optional(), - strictMode: z.boolean().optional(), - lazy: z.union([z.boolean(), z.string().array()]).optional(), - noInterop: z.boolean().optional(), - importInterop: z.enum(["swc", "babel", "node", "none"]).optional(), - outFileExtension: z.enum(["js", "mjs", "cjs"]).optional(), - exportInteropAnnotation: z.boolean().optional(), - ignoreDynamic: z.boolean().optional(), - allowTopLevelThis: z.boolean().optional(), - preserveImportMeta: z.boolean().optional() -}) satisfies z.ZodType; + const ZodSwcOptimizerConfig = z.strictObject({ + simplify: z.boolean().optional(), + globals: ZodSwcGlobalPassOption.optional(), + jsonify: z + .strictObject({ + minCost: z.number() + }) + .optional() + }) satisfies z.ZodType; + + const ZodSwcTransformConfig = z.strictObject({ + react: ZodSwcReactConfig.optional(), + constModules: ZodSwcConstModulesConfig.optional(), + optimizer: ZodSwcOptimizerConfig.optional(), + legacyDecorator: z.boolean().optional(), + decoratorMetadata: z.boolean().optional(), + decoratorVersion: z.enum(["2021-12", "2022-03"]).optional(), + treatConstEnumAsEnum: z.boolean().optional(), + useDefineForClassFields: z.boolean().optional(), + verbatimModuleSyntax: z.boolean().optional() + }) satisfies z.ZodType; + + const ZodSwcJsMinifyOptions = z.strictObject({ + compress: z.union([ZodSwcTerserCompressOptions, z.boolean()]).optional(), + format: ZodSwcJsFormatOptions.optional(), + mangle: z.union([ZodSwcTerserMangleOptions, z.boolean()]).optional(), + ecma: ZodSwcTerserEcmaVersion.optional(), + keep_classnames: z.boolean().optional(), + keep_fnames: z.boolean().optional(), + module: z.union([z.boolean(), z.literal("unknown")]).optional(), + safari10: z.boolean().optional(), + toplevel: z.boolean().optional(), + sourceMap: z.boolean().optional(), + outputPath: z.string().optional(), + inlineSourcesContent: z.boolean().optional() + }) satisfies z.ZodType; -const ZodSwcEs6Config = ZodSwcBaseModuleConfig.extend({ - type: z.literal("es6") -}) satisfies z.ZodType; + const ZodSwcJscConfig = z.strictObject({ + assumptions: ZodSwcAssumptions.optional(), + loose: z.boolean().optional(), + parser: ZodSwcParserConfig.optional(), + transform: ZodSwcTransformConfig.optional(), + externalHelpers: z.boolean().optional(), + target: ZodSwcJscTarget.optional(), + keepClassNames: z.boolean().optional(), + experimental: z + .strictObject({ + optimizeHygiene: z.boolean().optional(), + keepImportAttributes: z.boolean().optional(), + emitAssertForImportAttributes: z.boolean().optional(), + cacheRoot: z.string().optional(), + plugins: z + .array(z.tuple([z.string(), z.record(z.string(), z.any())])) + .optional(), + runPluginFirst: z.boolean().optional(), + disableBuiltinTransformsForInternalTesting: z.boolean().optional(), + emitIsolatedDts: z.boolean().optional(), + disableAllLints: z.boolean().optional(), + keepImportAssertions: z.boolean().optional() + }) + .optional(), + baseUrl: z.string().optional(), + paths: z.record(z.string(), z.string().array()).optional(), + minify: ZodSwcJsMinifyOptions.optional(), + preserveAllComments: z.boolean().optional(), + output: z + .strictObject({ + charset: z.enum(["utf8", "ascii"]).optional() + }) + .optional() + }) satisfies z.ZodType; -const ZodSwcNodeNextConfig = ZodSwcBaseModuleConfig.extend({ - type: z.literal("nodenext") -}) satisfies z.ZodType; + const ZodSwcBaseModuleConfig = z.strictObject({ + strict: z.boolean().optional(), + strictMode: z.boolean().optional(), + lazy: z.union([z.boolean(), z.string().array()]).optional(), + noInterop: z.boolean().optional(), + importInterop: z.enum(["swc", "babel", "node", "none"]).optional(), + outFileExtension: z.enum(["js", "mjs", "cjs"]).optional(), + exportInteropAnnotation: z.boolean().optional(), + ignoreDynamic: z.boolean().optional(), + allowTopLevelThis: z.boolean().optional(), + preserveImportMeta: z.boolean().optional() + }) satisfies z.ZodType; -const ZodSwcCommonJsConfig = ZodSwcBaseModuleConfig.extend({ - type: z.literal("commonjs") -}) satisfies z.ZodType; + const ZodSwcEs6Config = ZodSwcBaseModuleConfig.extend({ + type: z.literal("es6") + }) satisfies z.ZodType; -const ZodSwcUmdConfig = ZodSwcBaseModuleConfig.extend({ - type: z.literal("umd"), - globals: z.record(z.string(), z.string()).optional() -}) satisfies z.ZodType; + const ZodSwcNodeNextConfig = ZodSwcBaseModuleConfig.extend({ + type: z.literal("nodenext") + }) satisfies z.ZodType; -const ZodSwcAmdConfig = ZodSwcBaseModuleConfig.extend({ - type: z.literal("amd"), - moduleId: z.string().optional() -}) satisfies z.ZodType; + const ZodSwcCommonJsConfig = ZodSwcBaseModuleConfig.extend({ + type: z.literal("commonjs") + }) satisfies z.ZodType; -const ZodSwcSystemjsConfig = z.strictObject({ - type: z.literal("systemjs"), - allowTopLevelThis: z.boolean().optional() -}) satisfies z.ZodType; + const ZodSwcUmdConfig = ZodSwcBaseModuleConfig.extend({ + type: z.literal("umd"), + globals: z.record(z.string(), z.string()).optional() + }) satisfies z.ZodType; -const ZodSwcModuleConfig = z.union([ - ZodSwcEs6Config, - ZodSwcCommonJsConfig, - ZodSwcUmdConfig, - ZodSwcAmdConfig, - ZodSwcNodeNextConfig, - ZodSwcSystemjsConfig -]) satisfies z.ZodType; + const ZodSwcAmdConfig = ZodSwcBaseModuleConfig.extend({ + type: z.literal("amd"), + moduleId: z.string().optional() + }) satisfies z.ZodType; -const ZodSwcConfig = z.strictObject({ - $schema: z.string().optional(), - test: z.string().or(z.string().array()).optional(), - exclude: z.string().or(z.string().array()).optional(), - env: ZodSwcEnvConfig.optional(), - jsc: ZodSwcJscConfig.optional(), - module: ZodSwcModuleConfig.optional(), - minify: z.boolean().optional(), - sourceMaps: z.boolean().or(z.literal("inline")).optional(), - inlineSourcesContent: z.boolean().optional() -}) satisfies z.ZodType; + const ZodSwcSystemjsConfig = z.strictObject({ + type: z.literal("systemjs"), + allowTopLevelThis: z.boolean().optional() + }) satisfies z.ZodType; -export const ZodSwcLoaderOptions = ZodSwcConfig.extend({ - isModule: z.boolean().or(z.literal("unknown")).optional(), - rspackExperiments: z - .strictObject({ - import: ZodSwcPluginImportConfig.optional() - }) - .optional() -}) satisfies z.ZodType; + const ZodSwcModuleConfig = z.union([ + ZodSwcEs6Config, + ZodSwcCommonJsConfig, + ZodSwcUmdConfig, + ZodSwcAmdConfig, + ZodSwcNodeNextConfig, + ZodSwcSystemjsConfig + ]) satisfies z.ZodType; + + const ZodSwcConfig = z.strictObject({ + $schema: z.string().optional(), + test: z.string().or(z.string().array()).optional(), + exclude: z.string().or(z.string().array()).optional(), + env: ZodSwcEnvConfig.optional(), + jsc: ZodSwcJscConfig.optional(), + module: ZodSwcModuleConfig.optional(), + minify: z.boolean().optional(), + sourceMaps: z.boolean().or(z.literal("inline")).optional(), + inlineSourcesContent: z.boolean().optional() + }) satisfies z.ZodType; + + return ZodSwcConfig.extend({ + isModule: z.boolean().or(z.literal("unknown")).optional(), + rspackExperiments: z + .strictObject({ + import: ZodSwcPluginImportConfig.optional() + }) + .optional() + }) satisfies z.ZodType; +}); diff --git a/packages/rspack/src/builtin-plugin/IgnorePlugin.ts b/packages/rspack/src/builtin-plugin/IgnorePlugin.ts index ecf42c900f1f..787fb1fd72e9 100644 --- a/packages/rspack/src/builtin-plugin/IgnorePlugin.ts +++ b/packages/rspack/src/builtin-plugin/IgnorePlugin.ts @@ -5,6 +5,7 @@ import { import { z } from "zod"; import { anyFunction } from "../config/utils"; +import { memoize } from "../util/memoize"; import { validate } from "../util/validate"; import { create } from "./base"; @@ -21,20 +22,23 @@ export type IgnorePluginOptions = checkResource: NonNullable; }; -const IgnorePluginOptions = z.union([ - z.object({ - contextRegExp: z.instanceof(RegExp).optional(), - resourceRegExp: z.instanceof(RegExp) - }), - z.object({ - checkResource: anyFunction - }) -]) satisfies z.ZodType; +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 IgnorePlugin = create( BuiltinPluginName.IgnorePlugin, (options: IgnorePluginOptions): RawIgnorePluginOptions => { - validate(options, IgnorePluginOptions); + validate(options, getIgnorePluginOptionsSchema()); return options; } diff --git a/packages/rspack/src/builtin-plugin/RsdoctorPlugin.ts b/packages/rspack/src/builtin-plugin/RsdoctorPlugin.ts index 355f0e63064c..8d712cccef24 100644 --- a/packages/rspack/src/builtin-plugin/RsdoctorPlugin.ts +++ b/packages/rspack/src/builtin-plugin/RsdoctorPlugin.ts @@ -29,6 +29,7 @@ import { z } from "zod"; import { type Compilation, checkCompilation } from "../Compilation"; import type { Compiler } from "../Compiler"; import type { CreatePartialRegisters } from "../taps/types"; +import { memoize } from "../util/memoize"; import { validate } from "../util/validate"; import { create } from "./base"; @@ -62,14 +63,18 @@ export type RsdoctorPluginOptions = { moduleGraphFeatures?: boolean | Array<"graph" | "ids" | "sources">; chunkGraphFeatures?: boolean | Array<"graph" | "assets">; }; -const rsdoctorPluginSchema = 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() -}) satisfies z.ZodType; + +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() + }) satisfies z.ZodType +); const RsdoctorPluginImpl = create( BuiltinPluginName.RsdoctorPlugin, @@ -80,7 +85,7 @@ const RsdoctorPluginImpl = create( chunkGraphFeatures: true } ): RawRsdoctorPluginOptions { - validate(c, rsdoctorPluginSchema); + 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 2bc6c980d941..1892f6aa712d 100644 --- a/packages/rspack/src/builtin-plugin/SubresourceIntegrityPlugin.ts +++ b/packages/rspack/src/builtin-plugin/SubresourceIntegrityPlugin.ts @@ -12,6 +12,7 @@ import { z } from "zod"; import type { Compilation } from "../Compilation"; import type { Compiler } from "../Compiler"; import type { CrossOriginLoading } from "../config/types"; +import { memoize } from "../util/memoize"; import { validate } from "../util/validate"; import { create } from "./base"; @@ -67,15 +68,18 @@ export type SubresourceIntegrityPluginOptions = { enabled?: "auto" | boolean; }; -const hashFunctionSchema = z.enum(["sha256", "sha384", "sha512"]); -const pluginOptionsSchema = 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; +const getPluginOptionsSchema = 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 type NativeSubresourceIntegrityPluginOptions = Omit< RawSubresourceIntegrityPluginOptions, @@ -322,7 +326,7 @@ export class SubresourceIntegrityPlugin extends NativeSubresourceIntegrityPlugin function validateSubresourceIntegrityPluginOptions( options: SubresourceIntegrityPluginOptions ) { - validate(options, pluginOptionsSchema); + validate(options, getPluginOptionsSchema()); } function isErrorWithCode(obj: T): boolean { diff --git a/packages/rspack/src/builtin-plugin/html-plugin/options.ts b/packages/rspack/src/builtin-plugin/html-plugin/options.ts index 17ee0c00c838..ca611edb3dea 100644 --- a/packages/rspack/src/builtin-plugin/html-plugin/options.ts +++ b/packages/rspack/src/builtin-plugin/html-plugin/options.ts @@ -1,6 +1,7 @@ import { z } from "zod"; import { Compilation } from "../../Compilation"; import { anyFunction } from "../../config/utils"; +import { memoize } from "../../util/memoize"; import { validate } from "../../util/validate"; const compilationOptionsMap: WeakMap = @@ -113,53 +114,56 @@ export type HtmlRspackPluginOptions = { [key: string]: any; }; -const pluginOptionsSchema = z.object({ - filename: z.string().or(anyFunction).optional(), - template: z - .string() - .refine( - val => !val.includes("!"), - () => ({ - message: - "HtmlRspackPlugin does not support template path with loader yet" - }) - ) - .optional(), - templateContent: z.string().or(templateRenderFunction).optional(), - templateParameters: z - .record(z.string(), z.string()) - .or(z.boolean()) - .or(templateParamFunction) - .optional(), - inject: z.enum(["head", "body"]).or(z.boolean()).optional(), - publicPath: z.string().optional(), - base: z - .string() - .or( - z.strictObject({ - href: z.string().optional(), - target: z.enum(["_self", "_blank", "_parent", "_top"]).optional() - }) - ) - .optional(), - scriptLoading: z - .enum(["blocking", "defer", "module", "systemjs-module"]) - .optional(), - chunks: z.string().array().optional(), - excludeChunks: z.string().array().optional(), - chunksSortMode: z.enum(["auto", "manual"]).optional(), - sri: z.enum(["sha256", "sha384", "sha512"]).optional(), - minify: z.boolean().optional(), - title: z.string().optional(), - favicon: z.string().optional(), - meta: z - .record(z.string(), z.string().or(z.record(z.string(), z.string()))) - .optional(), - hash: z.boolean().optional() -}) satisfies z.ZodType; +const getPluginOptionsSchema = memoize( + () => + z.object({ + filename: z.string().or(anyFunction).optional(), + template: z + .string() + .refine( + val => !val.includes("!"), + () => ({ + message: + "HtmlRspackPlugin does not support template path with loader yet" + }) + ) + .optional(), + templateContent: z.string().or(templateRenderFunction).optional(), + templateParameters: z + .record(z.string(), z.string()) + .or(z.boolean()) + .or(templateParamFunction) + .optional(), + inject: z.enum(["head", "body"]).or(z.boolean()).optional(), + publicPath: z.string().optional(), + base: z + .string() + .or( + z.strictObject({ + href: z.string().optional(), + target: z.enum(["_self", "_blank", "_parent", "_top"]).optional() + }) + ) + .optional(), + scriptLoading: z + .enum(["blocking", "defer", "module", "systemjs-module"]) + .optional(), + chunks: z.string().array().optional(), + excludeChunks: z.string().array().optional(), + chunksSortMode: z.enum(["auto", "manual"]).optional(), + sri: z.enum(["sha256", "sha384", "sha512"]).optional(), + minify: z.boolean().optional(), + title: z.string().optional(), + favicon: z.string().optional(), + meta: z + .record(z.string(), z.string().or(z.record(z.string(), z.string()))) + .optional(), + hash: z.boolean().optional() + }) satisfies z.ZodType +); export function validateHtmlPluginOptions(options: HtmlRspackPluginOptions) { - return validate(options, pluginOptionsSchema); + return validate(options, getPluginOptionsSchema()); } export const getPluginOptions = (compilation: Compilation, uid: number) => { diff --git a/packages/rspack/src/config/zod.ts b/packages/rspack/src/config/zod.ts index e9628942ec1f..6ff045edc305 100644 --- a/packages/rspack/src/config/zod.ts +++ b/packages/rspack/src/config/zod.ts @@ -1,6 +1,6 @@ import nodePath from "node:path"; import { ZodIssueCode, z } from "zod"; -import { ZodSwcLoaderOptions } from "../builtin-loader/swc/types"; +import { getZodSwcLoaderOptionsSchema } from "../builtin-loader/swc/types"; import { validate } from "../util/validate"; import type * as t from "./types"; import { ZodRspackCrossChecker, anyFunction } from "./utils"; @@ -458,15 +458,19 @@ const ruleSetLoaderWithOptions = type: z.strictObject({ ident: z.string().optional(), loader: z.literal("builtin:swc-loader"), - options: ZodSwcLoaderOptions, + options: getZodSwcLoaderOptionsSchema(), parallel: z.boolean().optional() }), issue: (res, _, input) => { try { - const message = validate(input.data.options, ZodSwcLoaderOptions, { - output: false, - strategy: "strict" - }); + const message = validate( + input.data.options, + getZodSwcLoaderOptionsSchema(), + { + output: false, + strategy: "strict" + } + ); if (message) { return [ { @@ -540,7 +544,7 @@ const extendedBaseRuleSetRule: z.ZodType = const extendedSwcRuleSetRule: z.ZodType = baseRuleSetRule .extend({ loader: z.literal("builtin:swc-loader"), - options: ZodSwcLoaderOptions + options: getZodSwcLoaderOptionsSchema() }) .extend({ oneOf: z.lazy(() => ruleSetRule.or(falsy).array()).optional(), @@ -556,10 +560,14 @@ const ruleSetRule = new ZodRspackCrossChecker({ type: extendedSwcRuleSetRule, issue: (res, _, input) => { try { - const message = validate(input.data.options, ZodSwcLoaderOptions, { - output: false, - strategy: "strict" - }); + const message = validate( + input.data.options, + getZodSwcLoaderOptionsSchema(), + { + output: false, + strategy: "strict" + } + ); if (message) { return [ { diff --git a/packages/rspack/src/lib/DllPlugin.ts b/packages/rspack/src/lib/DllPlugin.ts index f06dc3fdca2c..4cf917f763eb 100644 --- a/packages/rspack/src/lib/DllPlugin.ts +++ b/packages/rspack/src/lib/DllPlugin.ts @@ -13,6 +13,7 @@ import type { Compiler } from "../Compiler"; import { LibManifestPlugin } from "../builtin-plugin"; import { DllEntryPlugin } from "../builtin-plugin/DllEntryPlugin"; import { FlagAllModulesAsUsedPlugin } from "../builtin-plugin/FlagAllModulesAsUsedPlugin"; +import { memoize } from "../util/memoize"; import { validate } from "../util/validate"; export type DllPluginOptions = { @@ -48,20 +49,23 @@ export type DllPluginOptions = { type?: string; }; -const dllPluginOptions = 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; +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 class DllPlugin { private options: DllPluginOptions; constructor(options: DllPluginOptions) { - validate(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 24cf319a37dd..5be03a18be69 100644 --- a/packages/rspack/src/lib/DllReferencePlugin.ts +++ b/packages/rspack/src/lib/DllReferencePlugin.ts @@ -14,6 +14,7 @@ import type { CompilationParams } from "../Compilation"; import type { Compiler } from "../Compiler"; import { DllReferenceAgencyPlugin } from "../builtin-plugin"; import { makePathsRelative } from "../util/identifier"; +import { memoize } from "../util/memoize"; import { validate } from "../util/validate"; import WebpackError from "./WebpackError"; @@ -137,60 +138,64 @@ export interface DllReferencePluginOptionsContent { }; } -const dllReferencePluginOptionsContentItem = z.object({ - buildMeta: z.custom().optional(), - exports: z.array(z.string()).or(z.literal(true)).optional(), - id: z.string().or(z.number()).optional() -}); - -const dllReferencePluginOptionsContent = z.record( - z.string(), - dllReferencePluginOptionsContentItem -) satisfies z.ZodType; +const getDllReferencePluginOptionsSchema = memoize(() => { + const dllReferencePluginOptionsContentItem = z.object({ + buildMeta: z.custom().optional(), + exports: z.array(z.string()).or(z.literal(true)).optional(), + id: z.string().or(z.number()).optional() + }); -const dllReferencePluginOptionsSourceType = z.enum([ - "var", - "assign", - "this", - "window", - "global", - "commonjs", - "commonjs2", - "commonjs-module", - "amd", - "amd-require", - "umd", - "umd2", - "jsonp", - "system" -]) satisfies z.ZodType; + const dllReferencePluginOptionsContent = z.record( + z.string(), + dllReferencePluginOptionsContentItem + ) satisfies z.ZodType; -const dllReferencePluginOptionsManifest = z.object({ - content: dllReferencePluginOptionsContent, - name: z.string().optional(), - type: dllReferencePluginOptionsSourceType.optional() -}) 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 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({ + const dllReferencePluginOptionsManifest = 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; + 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 class DllReferencePlugin { private options: DllReferencePluginOptions; @@ -198,7 +203,7 @@ export class DllReferencePlugin { private errors: WeakMap; constructor(options: DllReferencePluginOptions) { - validate(options, dllReferencePluginOptions); + validate(options, getDllReferencePluginOptionsSchema()); this.options = options; this.errors = new WeakMap();