@rspack/cli 2.1.2 → 2.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/freshImport.js +111 -0
- package/dist/index.js +125 -156
- package/dist/rspack-merge.js +95 -0
- package/package.json +5 -4
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { Module } from "node:module";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { MessageChannel } from "node:worker_threads";
|
|
4
|
+
const instanceId = Math.random().toString(36).slice(2);
|
|
5
|
+
const relativeImportRE = /^\.{1,2}(?:\/|\\)/;
|
|
6
|
+
function escapeRegExp(value) {
|
|
7
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
8
|
+
}
|
|
9
|
+
function buildQueryName() {
|
|
10
|
+
return `fresh-import-${instanceId}`;
|
|
11
|
+
}
|
|
12
|
+
function buildQueryRE(queryName) {
|
|
13
|
+
return new RegExp(`(?:\\?|&)${escapeRegExp(queryName)}=(\\d+),([^&]+)(?:&|$)`);
|
|
14
|
+
}
|
|
15
|
+
function formatTrackingQuery(queryName, id, context) {
|
|
16
|
+
return `?${queryName}=${id},${context}`;
|
|
17
|
+
}
|
|
18
|
+
function trackResolved(specifier, context, result, queryName, queryRE, onDependency) {
|
|
19
|
+
const isRelativeImport = relativeImportRE.test(specifier);
|
|
20
|
+
if ("builtin" === result.format || !isRelativeImport) return result;
|
|
21
|
+
if (!context.parentURL || queryRE.test(result.url) || !result.url.startsWith("file:")) return result;
|
|
22
|
+
const m = queryRE.exec(context.parentURL);
|
|
23
|
+
if (m) {
|
|
24
|
+
const [, id, contextFile] = m;
|
|
25
|
+
onDependency(contextFile, result.url);
|
|
26
|
+
result.url = result.url.replace(/(\?)|$/, (_n, n1)=>`?${queryName}=${id},${contextFile}${"?" === n1 ? "&" : ""}`);
|
|
27
|
+
}
|
|
28
|
+
return result;
|
|
29
|
+
}
|
|
30
|
+
var loader_default = 'data:text/javascript,Math.random().toString(36).slice(2);%0Aconst relativeImportRE = /^\\.{1,2}(%3F:\\/|\\\\)/;%0Afunction escapeRegExp(value) {%0A%09return value.replace(/[.*+%3F^${}()|[\\]\\\\]/g, "\\\\$&");%0A}%0A/**%0A* Build the regex that matches the tracking query `%3F<name>=<id>,<context>`%0A* (or the `&<name>=...` form).%0A*/%0Afunction buildQueryRE(queryName) {%0A%09return new RegExp(`(%3F:\\\\%3F|&)${escapeRegExp(queryName)}=(\\\\d+),([^&]+)(%3F:&|$)`);%0A}%0A/**%0A* Shared body of the resolve hook for both the on-thread and off-thread%0A* importers. Given an already-resolved `result`, decides whether it is a tracked%0A* relative file dependency; if so, reports it via `onDependency` and tags the%0A* URL so the query propagates to its own dependencies.%0A*%0A* The sync/async difference between the two hooks lives entirely in the caller%0A* (which awaits `nextResolve` or not); this function performs no I/O. `result`%0A* is mutated in place and returned.%0A*/%0Afunction trackResolved(specifier, context, result, queryName, queryRE, onDependency) {%0A%09const isRelativeImport = relativeImportRE.test(specifier);%0A%09if (result.format === "builtin" || !isRelativeImport) return result;%0A%09if (!context.parentURL || queryRE.test(result.url) || !result.url.startsWith("file:")) return result;%0A%09const m = queryRE.exec(context.parentURL);%0A%09if (m) {%0A%09%09const [, id, contextFile] = m;%0A%09%09onDependency(contextFile, result.url);%0A%09%09result.url = result.url.replace(/(\\%3F)|$/, (_n, n1) => `%3F${queryName}=${id},${contextFile}${n1 === "%3F" %3F "&" : ""}`);%0A%09}%0A%09return result;%0A}%0A//%23endregion%0A//%23region src/off-thread/loader.ts%0Alet port;%0Alet queryName;%0Alet queryRE;%0Aconst initialize = async (data) => {%0A%09port = data.port;%0A%09queryName = data.queryName;%0A%09queryRE = buildQueryRE(queryName);%0A};%0Aconst resolve = async (specifier, context, nextResolve) => {%0A%09return trackResolved(specifier, context, await nextResolve(specifier, context), queryName, queryRE, (ctx, url) => {%0A%09%09port.postMessage({%0A%09%09%09context: ctx,%0A%09%09%09url%0A%09%09});%0A%09});%0A};%0A//%23endregion%0Aexport { initialize, resolve };%0A';
|
|
31
|
+
let nextId$1 = 0;
|
|
32
|
+
function createOffThreadImporter() {
|
|
33
|
+
const queryName = buildQueryName();
|
|
34
|
+
const { port1, port2 } = new MessageChannel();
|
|
35
|
+
Module.register(loader_default, {
|
|
36
|
+
data: {
|
|
37
|
+
port: port2,
|
|
38
|
+
queryName
|
|
39
|
+
},
|
|
40
|
+
transferList: [
|
|
41
|
+
port2
|
|
42
|
+
]
|
|
43
|
+
});
|
|
44
|
+
port1.unref();
|
|
45
|
+
return {
|
|
46
|
+
async collect (specifier) {
|
|
47
|
+
const id = nextId$1++;
|
|
48
|
+
const depsList = /* @__PURE__ */ new Set();
|
|
49
|
+
const onMessage = (e)=>{
|
|
50
|
+
if (e.context === specifier) depsList.add(e.url);
|
|
51
|
+
};
|
|
52
|
+
port1.on("message", onMessage);
|
|
53
|
+
port1.unref();
|
|
54
|
+
try {
|
|
55
|
+
const result = await import(specifier + formatTrackingQuery(queryName, id, specifier));
|
|
56
|
+
await new Promise((resolve)=>setImmediate(resolve));
|
|
57
|
+
return {
|
|
58
|
+
result,
|
|
59
|
+
dependencies: [
|
|
60
|
+
...depsList
|
|
61
|
+
].filter((url)=>url.startsWith("file:")).map((url)=>fileURLToPath(url))
|
|
62
|
+
};
|
|
63
|
+
} finally{
|
|
64
|
+
port1.off("message", onMessage);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
let nextId = 0;
|
|
70
|
+
function createOnThreadImporter() {
|
|
71
|
+
const registry = /* @__PURE__ */ new Map();
|
|
72
|
+
const queryName = buildQueryName();
|
|
73
|
+
const queryRE = buildQueryRE(queryName);
|
|
74
|
+
const resolve = (specifier, context, nextResolve)=>trackResolved(specifier, context, nextResolve(specifier, context), queryName, queryRE, (ctx, url)=>{
|
|
75
|
+
registry.get(ctx)?.add(url);
|
|
76
|
+
});
|
|
77
|
+
Module.registerHooks({
|
|
78
|
+
resolve
|
|
79
|
+
});
|
|
80
|
+
return {
|
|
81
|
+
async collect (specifier) {
|
|
82
|
+
const id = nextId++;
|
|
83
|
+
const depsList = /* @__PURE__ */ new Set();
|
|
84
|
+
registry.set(specifier, depsList);
|
|
85
|
+
try {
|
|
86
|
+
return {
|
|
87
|
+
result: await import(specifier + formatTrackingQuery(queryName, id, specifier)),
|
|
88
|
+
dependencies: [
|
|
89
|
+
...depsList
|
|
90
|
+
].filter((url)=>url.startsWith("file:")).map((url)=>fileURLToPath(url))
|
|
91
|
+
};
|
|
92
|
+
} finally{
|
|
93
|
+
registry.delete(specifier);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
function createImporter() {
|
|
99
|
+
if (Module.registerHooks) return createOnThreadImporter();
|
|
100
|
+
if (Module.register) return createOffThreadImporter();
|
|
101
|
+
}
|
|
102
|
+
let importer;
|
|
103
|
+
let initialized = false;
|
|
104
|
+
function freshImport(specifier) {
|
|
105
|
+
if (!initialized) {
|
|
106
|
+
importer = createImporter();
|
|
107
|
+
initialized = true;
|
|
108
|
+
}
|
|
109
|
+
return importer?.collect(specifier);
|
|
110
|
+
}
|
|
111
|
+
export { freshImport };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import node_path from "node:path";
|
|
1
|
+
import node_path, { isAbsolute, join } from "node:path";
|
|
2
2
|
import node_util from "node:util";
|
|
3
3
|
import { rspack } from "@rspack/core";
|
|
4
4
|
import node_fs from "node:fs";
|
|
@@ -854,98 +854,117 @@ class ServeCommand {
|
|
|
854
854
|
}));
|
|
855
855
|
}
|
|
856
856
|
}
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
}
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
857
|
+
const canReadExport = (module)=>null !== module && ('object' == typeof module || 'function' == typeof module);
|
|
858
|
+
const isConfigFunction = (configExport)=>'function' == typeof configExport;
|
|
859
|
+
const getConfigExport = (configModule, exportName, configPath)=>{
|
|
860
|
+
if (false === exportName) return {};
|
|
861
|
+
if ('default' === exportName) return canReadExport(configModule) && 'default' in configModule ? configModule.default : configModule;
|
|
862
|
+
if (canReadExport(configModule) && Object.hasOwn(configModule, exportName)) return configModule[exportName];
|
|
863
|
+
throw new Error(`Cannot find export ${exportName} in config file: ${configPath}`);
|
|
864
|
+
};
|
|
865
|
+
const loadWithJiti = async (configPath, exportName, fresh)=>{
|
|
866
|
+
let createJiti;
|
|
867
|
+
try {
|
|
868
|
+
({ createJiti } = await import("../compiled/jiti/index.js"));
|
|
869
|
+
} catch (error) {
|
|
870
|
+
throw new Error('The "jiti" package is required to load this config. Install it with your package manager.', {
|
|
871
|
+
cause: error
|
|
872
|
+
});
|
|
873
|
+
}
|
|
874
|
+
const jiti = createJiti(configPath, {
|
|
875
|
+
moduleCache: !fresh,
|
|
876
|
+
interopDefault: true,
|
|
877
|
+
nativeModules: [
|
|
878
|
+
"typescript"
|
|
879
|
+
]
|
|
870
880
|
});
|
|
871
|
-
return
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
}
|
|
877
|
-
function isPlainObject(value) {
|
|
878
|
-
if ('[object Object]' !== Object.prototype.toString.call(value)) return false;
|
|
879
|
-
const proto = Object.getPrototypeOf(value);
|
|
880
|
-
if (null === proto) return true;
|
|
881
|
-
let baseProto = proto;
|
|
882
|
-
while(null !== Object.getPrototypeOf(baseProto))baseProto = Object.getPrototypeOf(baseProto);
|
|
883
|
-
return proto === baseProto;
|
|
884
|
-
}
|
|
885
|
-
function isUndefined(value) {
|
|
886
|
-
return void 0 === value;
|
|
887
|
-
}
|
|
888
|
-
function isPromiseLike(value) {
|
|
889
|
-
return null !== value && ('object' == typeof value || 'function' == typeof value) && 'function' == typeof value.then;
|
|
890
|
-
}
|
|
891
|
-
const isArray = Array.isArray;
|
|
892
|
-
function joinArrays({ customizeArray, customizeObject, key } = {}) {
|
|
893
|
-
return function _joinArrays(a, b, k) {
|
|
894
|
-
const newKey = key ? `${key}.${k}` : k;
|
|
895
|
-
if ('function' == typeof a && 'function' == typeof b) return (...args)=>_joinArrays(a(...args), b(...args), k);
|
|
896
|
-
if (isArray(a) && isArray(b)) {
|
|
897
|
-
const customResult = customizeArray && customizeArray(a, b, newKey);
|
|
898
|
-
return customResult || [
|
|
899
|
-
...a,
|
|
900
|
-
...b
|
|
901
|
-
];
|
|
902
|
-
}
|
|
903
|
-
if (isRegex(b)) return b;
|
|
904
|
-
if (isPlainObject(a) && isPlainObject(b)) {
|
|
905
|
-
const customResult = customizeObject && customizeObject(a, b, newKey);
|
|
906
|
-
return customResult || merge_with([
|
|
907
|
-
a,
|
|
908
|
-
b
|
|
909
|
-
], joinArrays({
|
|
910
|
-
customizeArray,
|
|
911
|
-
customizeObject,
|
|
912
|
-
key: newKey
|
|
913
|
-
}));
|
|
914
|
-
}
|
|
915
|
-
if (isPlainObject(b)) return merge_with([
|
|
916
|
-
{},
|
|
917
|
-
b
|
|
918
|
-
], joinArrays({
|
|
919
|
-
customizeArray,
|
|
920
|
-
customizeObject,
|
|
921
|
-
key: newKey
|
|
922
|
-
}));
|
|
923
|
-
if (isArray(b)) return [
|
|
924
|
-
...b
|
|
925
|
-
];
|
|
926
|
-
return b;
|
|
881
|
+
if ('default' === exportName) return {
|
|
882
|
+
configExport: await jiti.import(configPath, {
|
|
883
|
+
default: true
|
|
884
|
+
}),
|
|
885
|
+
dependencies: []
|
|
927
886
|
};
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
887
|
+
const configModule = await jiti.import(configPath);
|
|
888
|
+
return {
|
|
889
|
+
configExport: getConfigExport(configModule, exportName, configPath),
|
|
890
|
+
dependencies: []
|
|
891
|
+
};
|
|
892
|
+
};
|
|
893
|
+
const JS_CONFIG_REGEXP = /\.(?:js|mjs|cjs)$/;
|
|
894
|
+
const tryFreshImport = async (configFileURL)=>{
|
|
895
|
+
try {
|
|
896
|
+
const { freshImport } = await import("./freshImport.js");
|
|
897
|
+
return await freshImport(configFileURL);
|
|
898
|
+
} catch {}
|
|
899
|
+
};
|
|
900
|
+
const loadWithNative = async (configPath, fresh)=>{
|
|
901
|
+
const configFileURL = pathToFileURL(configPath).href;
|
|
902
|
+
if (!fresh) {
|
|
903
|
+
const configModule = await import(configFileURL);
|
|
904
|
+
return {
|
|
905
|
+
configModule,
|
|
906
|
+
dependencies: []
|
|
907
|
+
};
|
|
908
|
+
}
|
|
909
|
+
const freshImportResult = await tryFreshImport(configFileURL);
|
|
910
|
+
if (freshImportResult) return {
|
|
911
|
+
configModule: freshImportResult.result,
|
|
912
|
+
dependencies: freshImportResult.dependencies.sort()
|
|
913
|
+
};
|
|
914
|
+
const configModule = await import(`${configFileURL}?t=${Date.now()}`);
|
|
915
|
+
return {
|
|
916
|
+
configModule,
|
|
917
|
+
dependencies: []
|
|
918
|
+
};
|
|
919
|
+
};
|
|
920
|
+
const resolveConfigPath = (root, customConfig, configFileNames = [])=>{
|
|
921
|
+
if (customConfig) {
|
|
922
|
+
const customConfigPath = isAbsolute(customConfig) ? customConfig : join(root, customConfig);
|
|
923
|
+
if (node_fs.existsSync(customConfigPath)) return customConfigPath;
|
|
924
|
+
throw new Error(`Cannot find config file: ${customConfigPath}`);
|
|
925
|
+
}
|
|
926
|
+
for (const file of configFileNames){
|
|
927
|
+
const configFile = join(root, file);
|
|
928
|
+
if (node_fs.existsSync(configFile)) return configFile;
|
|
929
|
+
}
|
|
930
|
+
return null;
|
|
931
|
+
};
|
|
932
|
+
async function loadConfig({ cwd = process.cwd(), path, configFileNames = [], loader = 'auto', exportName = 'default', configParams = [], fresh = false } = {}) {
|
|
933
|
+
const configPath = resolveConfigPath(cwd, path, configFileNames);
|
|
934
|
+
if (!configPath) return {
|
|
935
|
+
content: {},
|
|
936
|
+
filePath: configPath,
|
|
937
|
+
dependencies: []
|
|
938
|
+
};
|
|
939
|
+
let loadedConfig;
|
|
940
|
+
const useNative = Boolean('native' === loader || 'auto' === loader && (process.features.typescript || process.versions.bun || process.versions.deno));
|
|
941
|
+
if (useNative || JS_CONFIG_REGEXP.test(configPath)) {
|
|
942
|
+
let result;
|
|
943
|
+
try {
|
|
944
|
+
result = await loadWithNative(configPath, fresh);
|
|
945
|
+
} catch (err) {
|
|
946
|
+
if ('native' === loader) throw err;
|
|
945
947
|
}
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
948
|
+
if (result) loadedConfig = {
|
|
949
|
+
configExport: getConfigExport(result.configModule, exportName, configPath),
|
|
950
|
+
dependencies: result.dependencies
|
|
951
|
+
};
|
|
952
|
+
}
|
|
953
|
+
if (!loadedConfig) loadedConfig = await loadWithJiti(configPath, exportName, fresh);
|
|
954
|
+
const { configExport, dependencies } = loadedConfig;
|
|
955
|
+
if (isConfigFunction(configExport)) {
|
|
956
|
+
const result = await configExport(...configParams);
|
|
957
|
+
if (void 0 === result) throw new Error('The config function must return a config object.');
|
|
958
|
+
return {
|
|
959
|
+
content: result,
|
|
960
|
+
filePath: configPath,
|
|
961
|
+
dependencies
|
|
962
|
+
};
|
|
963
|
+
}
|
|
964
|
+
return {
|
|
965
|
+
content: configExport,
|
|
966
|
+
filePath: configPath,
|
|
967
|
+
dependencies
|
|
949
968
|
};
|
|
950
969
|
}
|
|
951
970
|
const DEFAULT_EXTENSIONS = [
|
|
@@ -960,71 +979,22 @@ const findConfig = (basePath)=>DEFAULT_EXTENSIONS.map((ext)=>basePath + ext).fin
|
|
|
960
979
|
const utils_findConfig = findConfig;
|
|
961
980
|
const loadConfig_require = createRequire(import.meta.url);
|
|
962
981
|
const loadConfig_DEFAULT_CONFIG_NAME = 'rspack.config';
|
|
963
|
-
const JS_CONFIG_EXTENSION_REGEXP = /\.(?:js|mjs|cjs)$/;
|
|
964
|
-
const CONFIG_LOADER_VALUES = [
|
|
965
|
-
'auto',
|
|
966
|
-
'jiti',
|
|
967
|
-
'native'
|
|
968
|
-
];
|
|
969
|
-
const PREBUNDLED_JITI_PATH = new URL('../compiled/jiti/index.js', import.meta.url).href;
|
|
970
|
-
const supportsNativeTypeScript = ()=>{
|
|
971
|
-
const features = process.features;
|
|
972
|
-
return Boolean(features.typescript || process.versions.bun || process.versions.deno);
|
|
973
|
-
};
|
|
974
|
-
const normalizeConfigLoader = (configLoader)=>{
|
|
975
|
-
const normalizedLoader = configLoader ?? 'auto';
|
|
976
|
-
if (CONFIG_LOADER_VALUES.includes(normalizedLoader)) return normalizedLoader;
|
|
977
|
-
throw new Error(`config loader "${normalizedLoader}" is not supported. Expected one of: ${CONFIG_LOADER_VALUES.join(', ')}.`);
|
|
978
|
-
};
|
|
979
|
-
const resolveDefaultExport = (result)=>result && 'object' == typeof result && 'default' in result ? result.default : result;
|
|
980
|
-
const loadConfigWithNativeLoader = async (configPath)=>{
|
|
981
|
-
const configFileURL = pathToFileURL(configPath).href;
|
|
982
|
-
const loadedModule = await import(`${configFileURL}?t=${Date.now()}`);
|
|
983
|
-
return resolveDefaultExport(loadedModule);
|
|
984
|
-
};
|
|
985
|
-
let jitiInstancePromise;
|
|
986
|
-
const getJiti = async ()=>{
|
|
987
|
-
if (!jitiInstancePromise) jitiInstancePromise = import(PREBUNDLED_JITI_PATH).then((module)=>{
|
|
988
|
-
const createJiti = 'createJiti' in module ? module.createJiti : module.default;
|
|
989
|
-
return createJiti(import.meta.filename, {
|
|
990
|
-
moduleCache: false,
|
|
991
|
-
interopDefault: true,
|
|
992
|
-
nativeModules: [
|
|
993
|
-
"typescript"
|
|
994
|
-
]
|
|
995
|
-
});
|
|
996
|
-
});
|
|
997
|
-
return jitiInstancePromise;
|
|
998
|
-
};
|
|
999
|
-
const loadConfigWithJiti = async (configPath)=>{
|
|
1000
|
-
const jiti = await getJiti();
|
|
1001
|
-
return jiti.import(configPath, {
|
|
1002
|
-
default: true
|
|
1003
|
-
});
|
|
1004
|
-
};
|
|
1005
982
|
const loadConfigByPath = async (configPath, options)=>{
|
|
1006
|
-
const
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
}
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
983
|
+
const configParams = [
|
|
984
|
+
options.env,
|
|
985
|
+
options
|
|
986
|
+
];
|
|
987
|
+
const { content } = await loadConfig({
|
|
988
|
+
path: configPath,
|
|
989
|
+
loader: options.configLoader,
|
|
990
|
+
configParams,
|
|
991
|
+
fresh: true
|
|
992
|
+
});
|
|
993
|
+
if (!isRspackConfig(content)) throw new Error(`[rspack-cli:loadConfig] The config at "${configPath}" must be an object or an array, got ${String(content)}`);
|
|
994
|
+
return content;
|
|
1014
995
|
};
|
|
1015
996
|
const isConfigObject = (value)=>Boolean(value) && 'object' == typeof value && !Array.isArray(value);
|
|
1016
997
|
const isRspackConfig = (value)=>Array.isArray(value) || isConfigObject(value);
|
|
1017
|
-
const resolveRspackConfigExport = async (configExport, options)=>{
|
|
1018
|
-
let loadedConfig = configExport;
|
|
1019
|
-
if ('function' == typeof loadedConfig) {
|
|
1020
|
-
let functionResult = loadedConfig(options.env, options);
|
|
1021
|
-
if ('function' == typeof functionResult.then) functionResult = await functionResult;
|
|
1022
|
-
if (void 0 === functionResult) throw new Error('[rspack-cli:loadConfig] The config function must return a config object.');
|
|
1023
|
-
loadedConfig = functionResult;
|
|
1024
|
-
}
|
|
1025
|
-
if (!isRspackConfig(loadedConfig)) throw new Error(`[rspack-cli:loadConfig] The config must be an object, an array, or a function that returns one, get ${String(loadedConfig)}`);
|
|
1026
|
-
return loadedConfig;
|
|
1027
|
-
};
|
|
1028
998
|
const checkIsMultiRspackOptions = (config)=>Array.isArray(config);
|
|
1029
999
|
async function loadExtendedConfig(config, configPath, cwd, options, visitedPaths) {
|
|
1030
1000
|
const currentVisitedPaths = visitedPaths ?? new Set();
|
|
@@ -1087,8 +1057,8 @@ async function loadExtendedConfig(config, configPath, cwd, options, visitedPaths
|
|
|
1087
1057
|
}
|
|
1088
1058
|
if (!node_fs.existsSync(resolvedPath)) throw new Error(`Extended configuration file "${resolvedPath}" not found.`);
|
|
1089
1059
|
const loadedConfig = await loadConfigByPath(resolvedPath, options);
|
|
1090
|
-
const
|
|
1091
|
-
const { config: extendedConfig, pathMap: extendedPathMap } = await loadExtendedConfig(
|
|
1060
|
+
const { merge } = await import("./rspack-merge.js");
|
|
1061
|
+
const { config: extendedConfig, pathMap: extendedPathMap } = await loadExtendedConfig(loadedConfig, resolvedPath, cwd, options, currentVisitedPaths);
|
|
1092
1062
|
const configPaths = [
|
|
1093
1063
|
...pathMap.get(resultConfig) || [],
|
|
1094
1064
|
...extendedPathMap.get(extendedConfig) || []
|
|
@@ -1149,7 +1119,7 @@ class RspackCLI {
|
|
|
1149
1119
|
this.colors = this.createColors();
|
|
1150
1120
|
this.program = program;
|
|
1151
1121
|
program.help();
|
|
1152
|
-
program.version("2.1.
|
|
1122
|
+
program.version("2.1.4");
|
|
1153
1123
|
}
|
|
1154
1124
|
wrapAction(fn) {
|
|
1155
1125
|
return (...args)=>{
|
|
@@ -1279,8 +1249,7 @@ class RspackCLI {
|
|
|
1279
1249
|
pathMap: new WeakMap()
|
|
1280
1250
|
};
|
|
1281
1251
|
const { loadedConfig, configPath } = config;
|
|
1282
|
-
const
|
|
1283
|
-
const { config: extendedConfig, pathMap } = await loadExtendedConfig(resolvedConfig, configPath, process.cwd(), options);
|
|
1252
|
+
const { config: extendedConfig, pathMap } = await loadExtendedConfig(loadedConfig, configPath, process.cwd(), options);
|
|
1284
1253
|
return {
|
|
1285
1254
|
config: this.filterConfig(options, extendedConfig),
|
|
1286
1255
|
pathMap
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
function mergeWith(objects, customizer) {
|
|
2
|
+
const [first, ...rest] = objects;
|
|
3
|
+
let ret = first;
|
|
4
|
+
rest.forEach((a)=>{
|
|
5
|
+
ret = mergeTo(ret, a, customizer);
|
|
6
|
+
});
|
|
7
|
+
return ret;
|
|
8
|
+
}
|
|
9
|
+
function mergeTo(a, b, customizer) {
|
|
10
|
+
const ret = {};
|
|
11
|
+
Object.keys(a).concat(Object.keys(b)).forEach((k)=>{
|
|
12
|
+
const v = customizer(a[k], b[k], k);
|
|
13
|
+
ret[k] = void 0 === v ? a[k] : v;
|
|
14
|
+
});
|
|
15
|
+
return ret;
|
|
16
|
+
}
|
|
17
|
+
const merge_with = mergeWith;
|
|
18
|
+
function isRegex(o) {
|
|
19
|
+
return o instanceof RegExp;
|
|
20
|
+
}
|
|
21
|
+
function isPlainObject(value) {
|
|
22
|
+
if ('[object Object]' !== Object.prototype.toString.call(value)) return false;
|
|
23
|
+
const proto = Object.getPrototypeOf(value);
|
|
24
|
+
if (null === proto) return true;
|
|
25
|
+
let baseProto = proto;
|
|
26
|
+
while(null !== Object.getPrototypeOf(baseProto))baseProto = Object.getPrototypeOf(baseProto);
|
|
27
|
+
return proto === baseProto;
|
|
28
|
+
}
|
|
29
|
+
function isUndefined(value) {
|
|
30
|
+
return void 0 === value;
|
|
31
|
+
}
|
|
32
|
+
function isPromiseLike(value) {
|
|
33
|
+
return null !== value && ('object' == typeof value || 'function' == typeof value) && 'function' == typeof value.then;
|
|
34
|
+
}
|
|
35
|
+
const isArray = Array.isArray;
|
|
36
|
+
function joinArrays({ customizeArray, customizeObject, key } = {}) {
|
|
37
|
+
return function _joinArrays(a, b, k) {
|
|
38
|
+
const newKey = key ? `${key}.${k}` : k;
|
|
39
|
+
if ('function' == typeof a && 'function' == typeof b) return (...args)=>_joinArrays(a(...args), b(...args), k);
|
|
40
|
+
if (isArray(a) && isArray(b)) {
|
|
41
|
+
const customResult = customizeArray && customizeArray(a, b, newKey);
|
|
42
|
+
return customResult || [
|
|
43
|
+
...a,
|
|
44
|
+
...b
|
|
45
|
+
];
|
|
46
|
+
}
|
|
47
|
+
if (isRegex(b)) return b;
|
|
48
|
+
if (isPlainObject(a) && isPlainObject(b)) {
|
|
49
|
+
const customResult = customizeObject && customizeObject(a, b, newKey);
|
|
50
|
+
return customResult || merge_with([
|
|
51
|
+
a,
|
|
52
|
+
b
|
|
53
|
+
], joinArrays({
|
|
54
|
+
customizeArray,
|
|
55
|
+
customizeObject,
|
|
56
|
+
key: newKey
|
|
57
|
+
}));
|
|
58
|
+
}
|
|
59
|
+
if (isPlainObject(b)) return merge_with([
|
|
60
|
+
{},
|
|
61
|
+
b
|
|
62
|
+
], joinArrays({
|
|
63
|
+
customizeArray,
|
|
64
|
+
customizeObject,
|
|
65
|
+
key: newKey
|
|
66
|
+
}));
|
|
67
|
+
if (isArray(b)) return [
|
|
68
|
+
...b
|
|
69
|
+
];
|
|
70
|
+
return b;
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
function merge(firstConfiguration, ...configurations) {
|
|
74
|
+
return mergeWithCustomize({})(firstConfiguration, ...configurations);
|
|
75
|
+
}
|
|
76
|
+
function mergeWithCustomize(options) {
|
|
77
|
+
return function(firstConfiguration, ...configurations) {
|
|
78
|
+
if (isUndefined(firstConfiguration) || configurations.some(isUndefined)) throw new TypeError('Merging undefined is not supported');
|
|
79
|
+
if (isPromiseLike(firstConfiguration)) throw new TypeError('Promises are not supported');
|
|
80
|
+
if (!firstConfiguration) return {};
|
|
81
|
+
if (0 === configurations.length) {
|
|
82
|
+
if (Array.isArray(firstConfiguration)) {
|
|
83
|
+
if (0 === firstConfiguration.length) return {};
|
|
84
|
+
if (firstConfiguration.some(isUndefined)) throw new TypeError('Merging undefined is not supported');
|
|
85
|
+
if (isPromiseLike(firstConfiguration[0])) throw new TypeError('Promises are not supported');
|
|
86
|
+
return merge_with(firstConfiguration, joinArrays(options));
|
|
87
|
+
}
|
|
88
|
+
return firstConfiguration;
|
|
89
|
+
}
|
|
90
|
+
return merge_with([
|
|
91
|
+
firstConfiguration
|
|
92
|
+
].concat(configurations), joinArrays(options));
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
export { merge };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rspack/cli",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.4",
|
|
4
4
|
"description": "CLI for rspack",
|
|
5
5
|
"homepage": "https://rspack.rs",
|
|
6
6
|
"bugs": "https://github.com/web-infra-dev/rspack/issues",
|
|
@@ -30,7 +30,8 @@
|
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@discoveryjs/json-ext": "^1.1.0",
|
|
32
32
|
"@microsoft/api-extractor": "^7.58.9",
|
|
33
|
-
"@
|
|
33
|
+
"@rstackjs/load-config": "^0.1.1",
|
|
34
|
+
"@rslib/core": "^0.23.2",
|
|
34
35
|
"@rspack/dev-server": "^2.1.0",
|
|
35
36
|
"cac": "^7.0.0",
|
|
36
37
|
"concat-stream": "^2.0.0",
|
|
@@ -41,8 +42,8 @@
|
|
|
41
42
|
"prebundle": "^1.6.5",
|
|
42
43
|
"rspack-merge": "1.0.1",
|
|
43
44
|
"typescript": "^6.0.3",
|
|
44
|
-
"@rspack/core": "2.1.
|
|
45
|
-
"@rspack/test-tools": "2.1.
|
|
45
|
+
"@rspack/core": "2.1.4",
|
|
46
|
+
"@rspack/test-tools": "2.1.4"
|
|
46
47
|
},
|
|
47
48
|
"peerDependencies": {
|
|
48
49
|
"@rspack/core": "^2.0.0-0",
|