UNPKG

rspack-chain

Version:

<p> <a href="https://npmjs.com/package/rspack-chain?activeTab=readme"> <img src="https://img.shields.io/npm/v/rspack-chain?style=flat-square&colorA=564341&colorB=EDED91" alt="npm version" /> </a> <a href="https://npmcharts.com/compare/rspack-chai

906 lines (905 loc) 29.5 kB
import deepmerge from "deepmerge"; import { stringify as external_javascript_stringify_stringify } from "javascript-stringify"; function createMap(superClass) { return class extends superClass { extend(methods) { this.shorthands = methods; methods.forEach((method)=>{ this[method] = (value)=>this.set(method, value); }); return this; } clear() { this.store.clear(); return this; } delete(key) { this.store.delete(key); return this; } order() { const entries = [ ...this.store ].reduce((acc, [key, value])=>{ acc[key] = value; return acc; }, {}); const names = Object.keys(entries); const order = [ ...names ]; names.forEach((name)=>{ if (!entries[name]) return; const { __before, __after } = entries[name]; if (__before && order.includes(__before)) { order.splice(order.indexOf(name), 1); order.splice(order.indexOf(__before), 0, name); } else if (__after && order.includes(__after)) { order.splice(order.indexOf(name), 1); order.splice(order.indexOf(__after) + 1, 0, name); } }); return { entries, order }; } entries() { const { entries, order } = this.order(); if (order.length) return entries; } values() { const { entries, order } = this.order(); return order.map((name)=>entries[name]); } get(key) { return this.store.get(key); } getOrCompute(key, fn) { if (!this.has(key)) this.set(key, fn()); return this.get(key); } has(key) { return this.store.has(key); } set(key, value) { this.store.set(key, value); return this; } merge(obj, omit = []) { Object.keys(obj).forEach((key)=>{ if (omit.includes(key)) return; const value = obj[key]; if ((Array.isArray(value) || 'object' == typeof value) && null !== value && this.has(key)) this.set(key, deepmerge(this.get(key), value)); else this.set(key, value); }); return this; } clean(obj) { return Object.keys(obj).reduce((acc, key)=>{ const value = obj[key]; if (void 0 === value) return acc; if (Array.isArray(value) && !value.length) return acc; if ('[object Object]' === Object.prototype.toString.call(value) && !Object.keys(value).length) return acc; acc[key] = value; return acc; }, {}); } when(condition, whenTruthy = Function.prototype, whenFalsy = Function.prototype) { if (condition) whenTruthy(this); else whenFalsy(this); return this; } constructor(...args){ super(...args); this.store = new Map(); } }; } function createChainable(superClass) { return class extends superClass { batch(handler) { handler(this); return this; } end() { return this.parent; } constructor(parent){ super(); this.parent = parent; } }; } const ChainedMap = createMap(createChainable(Object)); class Callable_class extends Function { classCall() { throw new Error('not implemented'); } constructor(){ super(); return new Proxy(this, { apply: (target, thisArg, args)=>target.classCall(...args) }); } } function createValue(superClass) { return class extends superClass { set(...args) { this.useMap = true; this.value = void 0; return super.set(...args); } clear() { this.value = void 0; return super.clear(); } classCall(value) { this.clear(); this.useMap = false; this.value = value; return this.parent; } entries() { if (this.useMap) return super.entries(); return this.value; } values() { if (this.useMap) return super.values(); return this.value; } constructor(...args){ super(...args); this.value = void 0; this.useMap = true; } }; } const ChainedValueMap = createValue(createMap(createChainable(Callable_class))); function createSet(superClass) { return class extends superClass { add(value) { this.store.add(value); return this; } prepend(value) { this.store = new Set([ value, ...this.store ]); return this; } clear() { this.store.clear(); return this; } delete(value) { this.store.delete(value); return this; } values() { return [ ...this.store ]; } has(value) { return this.store.has(value); } merge(arr) { if (void 0 !== arr) this.store = new Set([ ...this.store, ...arr ]); return this; } when(condition, whenTruthy = Function.prototype, whenFalsy = Function.prototype) { if (condition) whenTruthy(this); else whenFalsy(this); return this; } constructor(...args){ super(...args); this.store = new Set(); } }; } const ChainedSet = createSet(createChainable(Object)); const Orderable = (Class)=>{ class _class extends Class { before(name) { if (this.__after) throw new Error(`Unable to set .before(${JSON.stringify(name)}) with existing value for .after()`); this.__before = name; return this; } after(name) { if (this.__before) throw new Error(`Unable to set .after(${JSON.stringify(name)}) with existing value for .before()`); this.__after = name; return this; } merge(obj, omit = []) { if (obj.before) this.before(obj.before); if (obj.after) this.after(obj.after); return super.merge(obj, [ ...omit, 'before', 'after' ]); } } return _class; }; const src_Plugin = Orderable(class extends ChainedMap { use(plugin, args = []) { return this.set('plugin', plugin).set('args', args); } tap(f) { if (!this.has('plugin')) throw new Error(`Cannot call .tap() on a plugin that has not yet been defined. Call ${this.type}('${this.name}').use(<Plugin>) first.`); this.set('args', f(this.get('args') || [])); return this; } set(key, value) { if ('args' === key && !Array.isArray(value)) throw new Error('args must be an array of arguments'); return super.set(key, value); } merge(obj, omit = []) { if ('plugin' in obj) this.set('plugin', obj.plugin); if ('args' in obj) this.set('args', obj.args); return super.merge(obj, [ ...omit, 'args', 'plugin' ]); } toConfig() { const init = this.get('init'); let plugin = this.get('plugin'); const args = this.get('args'); let pluginPath = null; if (void 0 === plugin) throw new Error(`Invalid ${this.type} configuration: ${this.type}('${this.name}').use(<Plugin>) was not called to specify the plugin`); if ('string' == typeof plugin) { pluginPath = plugin; plugin = require(pluginPath); } const constructorName = plugin.__expression ? `(${plugin.__expression})` : plugin.name; const config = init(plugin, args); Object.defineProperties(config, { __pluginName: { value: this.name }, __pluginType: { value: this.type }, __pluginArgs: { value: args }, __pluginConstructorName: { value: constructorName }, __pluginPath: { value: pluginPath } }); return config; } constructor(parent, name, type = 'plugin'){ super(parent); this.name = name; this.type = type; this.extend([ 'init' ]); this.init((Plugin, args = [])=>{ if ('function' == typeof Plugin) return new Plugin(...args); return Plugin; }); } }); const childMaps = [ 'alias', 'fallback', 'byDependency', 'extensionAlias' ]; const childSets = [ 'aliasFields', 'conditionNames', "descriptionFiles", 'extensions', 'mainFields', 'mainFiles', 'exportsFields', 'importsFields', 'restrictions', 'roots', 'modules' ]; class Resolve_class extends ChainedMap { plugin(name) { return this.plugins.getOrCompute(name, ()=>new src_Plugin(this, name, 'resolve.plugin')); } get(key) { if (childMaps.includes(key)) return this[key].entries(); if (childSets.includes(key)) return this[key].values(); return super.get(key); } toConfig() { const config = Object.assign(this.entries() || {}, { plugins: this.plugins.values().map((plugin)=>plugin.toConfig()) }); childMaps.forEach((key)=>{ config[key] = this[key].entries(); }); childSets.forEach((key)=>{ config[key] = this[key].values(); }); return this.clean(config); } merge(obj, omit = []) { if (!omit.includes('plugin') && 'plugin' in obj) Object.keys(obj.plugin).forEach((name)=>this.plugin(name).merge(obj.plugin[name])); const omissions = [ ...childMaps, ...childSets ]; omissions.forEach((key)=>{ if (!omit.includes(key) && key in obj) this[key].merge(obj[key]); }); return super.merge(obj, [ ...omit, ...omissions, 'plugin' ]); } constructor(parent){ super(parent); childMaps.forEach((key)=>{ this[key] = new ChainedMap(this); }); childSets.forEach((key)=>{ this[key] = new ChainedSet(this); }); this.plugins = new ChainedMap(this); this.extend([ 'cachePredicate', 'cacheWithContext', 'enforceExtension', 'symlinks', 'unsafeCache', 'preferRelative', 'preferAbsolute', 'tsConfig' ]); } } class ResolveLoader_class extends Resolve_class { toConfig() { return this.clean({ modules: this.modules.values(), moduleExtensions: this.moduleExtensions.values(), packageMains: this.packageMains.values(), ...super.toConfig() }); } merge(obj, omit = []) { const omissions = [ 'modules', 'moduleExtensions', 'packageMains' ]; omissions.forEach((key)=>{ if (!omit.includes(key) && key in obj) this[key].merge(obj[key]); }); return super.merge(obj, [ ...omit, ...omissions ]); } constructor(parent){ super(parent); this.modules = new ChainedSet(this); this.moduleExtensions = new ChainedSet(this); this.packageMains = new ChainedSet(this); } } class Output_class extends ChainedMap { constructor(parent){ super(parent); this.extend([ 'auxiliaryComment', 'charset', 'chunkFilename', 'chunkLoadTimeout', 'chunkLoadingGlobal', 'chunkLoading', 'chunkFormat', 'enabledChunkLoadingTypes', 'crossOriginLoading', 'devtoolFallbackModuleFilenameTemplate', 'devtoolModuleFilenameTemplate', 'devtoolNamespace', 'filename', 'assetModuleFilename', 'globalObject', 'uniqueName', 'hashDigest', 'hashDigestLength', 'hashFunction', 'hashSalt', 'hotUpdateChunkFilename', 'hotUpdateGlobal', 'hotUpdateMainFilename', 'library', 'libraryExport', 'libraryTarget', 'importFunctionName', 'path', 'pathinfo', 'publicPath', "scriptType", 'sourceMapFilename', 'sourcePrefix', 'strictModuleErrorHandling', 'strictModuleExceptionHandling', 'umdNamedDefine', 'workerChunkLoading', 'enabledLibraryTypes', 'environment', 'compareBeforeEmit', 'wasmLoading', 'webassemblyModuleFilename', 'enabledWasmLoadingTypes', 'iife', 'module', 'clean' ]); } } class DevServer_class extends ChainedMap { toConfig() { return this.clean({ allowedHosts: this.allowedHosts.values(), ...this.entries() || {} }); } merge(obj, omit = []) { if (!omit.includes('allowedHosts') && 'allowedHosts' in obj) this.allowedHosts.merge(obj.allowedHosts); return super.merge(obj, [ 'allowedHosts' ]); } constructor(parent){ super(parent); this.allowedHosts = new ChainedSet(this); this.extend([ 'after', 'before', 'bonjour', 'clientLogLevel', 'compress', 'contentBase', 'contentBasePublicPath', 'disableHostCheck', 'filename', 'headers', 'historyApiFallback', 'host', 'hot', 'hotOnly', 'http2', 'https', 'index', 'injectClient', 'injectHot', 'inline', 'lazy', 'liveReload', 'mimeTypes', 'noInfo', 'onListening', 'open', 'openPage', 'overlay', 'pfx', 'pfxPassphrase', 'port', 'proxy', 'progress', 'public', 'publicPath', 'quiet', 'serveIndex', 'setup', 'socket', 'sockHost', 'sockPath', 'sockPort', 'staticOptions', 'stats', 'stdin', 'transportMode', 'useLocalIp', 'watchContentBase', 'watchOptions', 'writeToDisk' ]); } } const Use = Orderable(class extends ChainedMap { tap(f) { this.options(f(this.get('options'))); return this; } merge(obj, omit = []) { if (!omit.includes('loader') && 'loader' in obj) this.loader(obj.loader); if (!omit.includes('options') && 'options' in obj) this.options(deepmerge(this.store.get('options') || {}, obj.options)); return super.merge(obj, [ ...omit, 'loader', 'options' ]); } toConfig() { const config = this.clean(this.entries() || {}); Object.defineProperties(config, { __useName: { value: this.name }, __ruleNames: { value: this.parent && this.parent.names }, __ruleTypes: { value: this.parent && this.parent.ruleTypes } }); return config; } constructor(parent, name){ super(parent); this.name = name; this.extend([ 'loader', 'options', 'parallel' ]); } }); function toArray(arr) { return Array.isArray(arr) ? arr : [ arr ]; } const Rule_Rule = Orderable(class extends ChainedMap { use(name) { return this.uses.getOrCompute(name, ()=>new Use(this, name)); } rule(name) { return this.rules.getOrCompute(name, ()=>new Rule_Rule(this, name, 'rule')); } oneOf(name) { return this.oneOfs.getOrCompute(name, ()=>new Rule_Rule(this, name, 'oneOf')); } pre() { return this.enforce('pre'); } post() { return this.enforce('post'); } toConfig() { const config = this.clean(Object.assign(this.entries() || {}, { include: this.include.values(), exclude: this.exclude.values(), rules: this.rules.values().map((rule)=>rule.toConfig()), oneOf: this.oneOfs.values().map((oneOf)=>oneOf.toConfig()), use: this.uses.values().map((use)=>use.toConfig()), resolve: this.resolve.toConfig() })); Object.defineProperties(config, { __ruleNames: { value: this.names }, __ruleTypes: { value: this.ruleTypes } }); return config; } merge(obj, omit = []) { if (!omit.includes('include') && 'include' in obj) this.include.merge(toArray(obj.include)); if (!omit.includes('exclude') && 'exclude' in obj) this.exclude.merge(toArray(obj.exclude)); if (!omit.includes('use') && 'use' in obj) Object.keys(obj.use).forEach((name)=>this.use(name).merge(obj.use[name])); if (!omit.includes('rules') && 'rules' in obj) Object.keys(obj.rules).forEach((name)=>this.rule(name).merge(obj.rules[name])); if (!omit.includes('oneOf') && 'oneOf' in obj) Object.keys(obj.oneOf).forEach((name)=>this.oneOf(name).merge(obj.oneOf[name])); if (!omit.includes('resolve') && 'resolve' in obj) this.resolve.merge(obj.resolve); if (!omit.includes('test') && 'test' in obj) this.test(obj.test instanceof RegExp || 'function' == typeof obj.test ? obj.test : new RegExp(obj.test)); return super.merge(obj, [ ...omit, 'include', 'exclude', 'use', 'rules', 'oneOf', 'resolve', 'test' ]); } constructor(parent, name, ruleType = 'rule'){ super(parent); this.ruleName = name; this.names = []; this.ruleType = ruleType; this.ruleTypes = []; let rule = this; while(rule instanceof Rule_Rule){ this.names.unshift(rule.ruleName); this.ruleTypes.unshift(rule.ruleType); rule = rule.parent; } this.uses = new ChainedMap(this); this.include = new ChainedSet(this); this.exclude = new ChainedSet(this); this.rules = new ChainedMap(this); this.oneOfs = new ChainedMap(this); this.resolve = new Resolve_class(this); this.resolve.extend([ 'fullySpecified' ]); this.extend([ 'dependency', 'enforce', 'issuer', 'issuerLayer', 'layer', 'mimetype', 'parser', 'generator', 'resource', 'resourceFragment', 'resourceQuery', 'sideEffects', 'with', 'test', 'type' ]); } }); const Rule = Rule_Rule; class Module_class extends ChainedMap { defaultRule(name) { return this.defaultRules.getOrCompute(name, ()=>new Rule(this, name, 'defaultRule')); } rule(name) { return this.rules.getOrCompute(name, ()=>new Rule(this, name, 'rule')); } toConfig() { return this.clean(Object.assign(this.entries() || {}, { defaultRules: this.defaultRules.values().map((r)=>r.toConfig()), generator: this.generator.entries(), parser: this.parser.entries(), rules: this.rules.values().map((r)=>r.toConfig()) })); } merge(obj, omit = []) { if (!omit.includes('rule') && 'rule' in obj) Object.keys(obj.rule).forEach((name)=>this.rule(name).merge(obj.rule[name])); if (!omit.includes('defaultRule') && 'defaultRule' in obj) Object.keys(obj.defaultRule).forEach((name)=>this.defaultRule(name).merge(obj.defaultRule[name])); return super.merge(obj, [ 'rule', 'defaultRule' ]); } constructor(parent){ super(parent); this.rules = new ChainedMap(this); this.defaultRules = new ChainedMap(this); this.generator = new ChainedMap(this); this.parser = new ChainedMap(this); this.extend([ 'noParse', 'unsafeCache', 'wrappedContextCritical', 'exprContextRegExp', 'wrappedContextRecursive', 'strictExportPresence', 'wrappedContextRegExp' ]); } } class Optimization_class extends ChainedMap { minimizer(name) { if (Array.isArray(name)) throw new Error("optimization.minimizer() no longer supports being passed an array. Either switch to the new syntax (https://github.com/neutrinojs/webpack-chain#config-optimization-minimizers-adding) or downgrade to webpack-chain 4. If using Vue this likely means a Vue plugin has not yet been updated to support Vue CLI 4+."); return this.minimizers.getOrCompute(name, ()=>new src_Plugin(this, name, 'optimization.minimizer')); } toConfig() { return this.clean(Object.assign(this.entries() || {}, { splitChunks: this.splitChunks.entries(), minimizer: this.minimizers.values().map((plugin)=>plugin.toConfig()) })); } merge(obj, omit = []) { if (!omit.includes('minimizer') && 'minimizer' in obj) Object.keys(obj.minimizer).forEach((name)=>this.minimizer(name).merge(obj.minimizer[name])); return super.merge(obj, [ ...omit, 'minimizer' ]); } constructor(parent){ super(parent); this.minimizers = new ChainedMap(this); this.splitChunks = new ChainedValueMap(this); this.extend([ 'minimize', 'runtimeChunk', 'emitOnErrors', 'moduleIds', 'chunkIds', 'nodeEnv', 'mangleWasmImports', 'removeAvailableModules', 'removeEmptyChunks', 'mergeDuplicateChunks', 'flagIncludedChunks', 'providedExports', 'usedExports', 'concatenateModules', 'sideEffects', 'portableRecords', 'mangleExports', 'innerGraph', 'realContentHash', 'avoidEntryIife' ]); } } class Performance_class extends ChainedValueMap { constructor(parent){ super(parent); this.extend([ 'assetFilter', 'hints', 'maxAssetSize', 'maxEntrypointSize' ]); } } const castArray = (value)=>Array.isArray(value) ? value : [ value ]; const toEntryObject = (entryPoints)=>{ const entry = Object.keys(entryPoints).reduce((acc, key)=>Object.assign(acc, { [key]: entryPoints[key].values() }), {}); const formattedEntry = {}; for (const [entryName, entryValue] of Object.entries(entry)){ const entryImport = []; let entryDescription = null; for (const item of castArray(entryValue)){ if ('string' == typeof item) { entryImport.push(item); continue; } if (item.import) entryImport.push(...castArray(item.import)); if (entryDescription) Object.assign(entryDescription, item); else entryDescription = item; } formattedEntry[entryName] = entryDescription ? { ...entryDescription, import: entryImport } : entryImport; } return formattedEntry; }; class src_class extends ChainedMap { static toString(config, { verbose = false, configPrefix = 'config' } = {}) { return external_javascript_stringify_stringify(config, (value, indent, stringify)=>{ if (value && value.__pluginName) { const prefix = `/* ${configPrefix}.${value.__pluginType}('${value.__pluginName}') */\n`; const constructorExpression = value.__pluginPath ? `(require(${stringify(value.__pluginPath)}))` : value.__pluginConstructorName; if (constructorExpression) { const args = stringify(value.__pluginArgs).slice(1, -1); return `${prefix}new ${constructorExpression}(${args})`; } return prefix + stringify(value.__pluginArgs && value.__pluginArgs.length ? { args: value.__pluginArgs } : {}); } if (value && value.__ruleNames) { const ruleTypes = value.__ruleTypes; const prefix = `/* ${configPrefix}.module${value.__ruleNames.map((r, index)=>`.${ruleTypes ? ruleTypes[index] : 'rule'}('${r}')`).join('')}${value.__useName ? `.use('${value.__useName}')` : ""} */\n`; return prefix + stringify(value); } if (value && value.__expression) return value.__expression; if ('function' == typeof value) { if (!verbose && value.toString().length > 100) return "function () { /* omitted long function */ }"; } return stringify(value); }, 2); } entry(name) { return this.entryPoints.getOrCompute(name, ()=>new ChainedSet(this)); } plugin(name) { return this.plugins.getOrCompute(name, ()=>new src_Plugin(this, name)); } toConfig() { const entryPoints = this.entryPoints.entries() || {}; const baseConfig = this.entries() || {}; return this.clean(Object.assign(baseConfig, { node: this.node.entries(), output: this.output.entries(), resolve: this.resolve.toConfig(), resolveLoader: this.resolveLoader.toConfig(), devServer: this.devServer.toConfig(), module: this.module.toConfig(), optimization: this.optimization.toConfig(), plugins: this.plugins.values().map((plugin)=>plugin.toConfig()), performance: this.performance.entries(), entry: toEntryObject(entryPoints) })); } toString(options) { return this.constructor.toString(this.toConfig(), options); } merge(obj = {}, omit = []) { const omissions = [ 'node', 'output', 'resolve', 'resolveLoader', 'devServer', 'optimization', 'performance', 'module' ]; if (!omit.includes('entry') && 'entry' in obj) Object.keys(obj.entry).forEach((name)=>this.entry(name).merge([].concat(obj.entry[name]))); if (!omit.includes('plugin') && 'plugin' in obj) Object.keys(obj.plugin).forEach((name)=>this.plugin(name).merge(obj.plugin[name])); omissions.forEach((key)=>{ if (!omit.includes(key) && key in obj) this[key].merge(obj[key]); }); return super.merge(obj, [ ...omit, ...omissions, 'entry', 'plugin' ]); } constructor(){ super(); this.entryPoints = new ChainedMap(this); this.output = new Output_class(this); this.module = new Module_class(this); this.resolve = new Resolve_class(this); this.resolveLoader = new ResolveLoader_class(this); this.optimization = new Optimization_class(this); this.plugins = new ChainedMap(this); this.devServer = new DevServer_class(this); this.performance = new Performance_class(this); this.node = new ChainedValueMap(this); this.extend([ 'context', 'mode', 'devtool', 'target', 'watch', 'watchOptions', 'externals', 'externalsType', 'externalsPresets', 'stats', 'experiments', 'amd', 'bail', 'cache', 'dependencies', 'ignoreWarnings', 'loader', 'parallelism', 'profile', 'recordsPath', 'recordsInputPath', 'recordsOutputPath', 'name', 'infrastructureLogging', 'snapshot', 'lazyCompilation' ]); } } export { src_class as default };