@qse/edu-scripts 0.0.0-beta.4 → 0.0.0-beta.6
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/asset/template/edu-scripts.override.js.tpl +2 -2
- package/asset/template/tailwind.config.js.tpl +1 -1
- package/dist/cli.mjs +60 -73
- package/dist/index.d.mts +5 -11
- package/package.json +2 -2
- package/src/cli.ts +1 -0
- package/src/commit-dist.ts +1 -4
- package/src/config/paths.ts +1 -2
- package/src/config/plugins/mock-server/index.ts +2 -5
- package/src/config/{webpackConfig.js → webpackConfig.ts} +47 -23
- package/src/config/{webpackDevServerConfig.js → webpackDevServerConfig.ts} +17 -13
- package/src/deploy.ts +1 -1
- package/src/utils/{FileSizeReporter.js → FileSizeReporter.ts} +52 -38
- package/src/utils/{changeDeployVersion.js → changeDeployVersion.ts} +39 -37
- package/src/utils/defineConfig.ts +5 -12
- package/src/utils/getOverride.ts +2 -1
- package/src/utils/resolveModule.ts +3 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
import { defineConfig } from '@qse/edu-scripts'
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
export default defineConfig({
|
|
4
4
|
startup: ({ logger, chalk }) => {
|
|
5
5
|
logger.info('本地免登录开发地址:', chalk.cyan(`http://127.0.0.1:${process.env.PORT}/index.html`))
|
|
6
6
|
},
|
package/dist/cli.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
|
+
import "@swc-node/register/esm-register";
|
|
3
4
|
import fs from "fs-extra";
|
|
4
5
|
import path from "path";
|
|
5
6
|
import { globby, globbySync } from "globby";
|
|
@@ -58,9 +59,8 @@ const paths = {
|
|
|
58
59
|
jsconfig: resolveApp("jsconfig.json"),
|
|
59
60
|
package: resolveApp("package.json"),
|
|
60
61
|
tailwind: resolveApp("tailwind.config.js"),
|
|
61
|
-
indexJS: resolveApp("src", "index.js"),
|
|
62
62
|
pages: resolveApp("src", "pages"),
|
|
63
|
-
override: resolveApp("edu-scripts.override.js"),
|
|
63
|
+
override: getExistPath(resolveApp("edu-scripts.override.js"), resolveApp("edu-scripts.override.ts")),
|
|
64
64
|
indexHTML: globbySync("./public/*.html", { absolute: true }),
|
|
65
65
|
src: resolveApp("src"),
|
|
66
66
|
public: resolveApp("public"),
|
|
@@ -166,7 +166,13 @@ const PostcssSafeAreaPlugin = () => {
|
|
|
166
166
|
};
|
|
167
167
|
|
|
168
168
|
//#endregion
|
|
169
|
-
//#region src/
|
|
169
|
+
//#region src/utils/resolveModule.ts
|
|
170
|
+
function resolveModule(mod) {
|
|
171
|
+
return mod.default ? mod.default : mod;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
//#endregion
|
|
175
|
+
//#region src/config/webpackConfig.ts
|
|
170
176
|
const require$2 = createRequire(import.meta.url);
|
|
171
177
|
const appPkg$1 = fs.readJsonSync(paths.package);
|
|
172
178
|
const jsMainPath = appConfig.grayscale ? `${appPkg$1.name}/beta/${appPkg$1.name}` : `${appPkg$1.name}/${appPkg$1.name}`;
|
|
@@ -191,10 +197,6 @@ const qseCDN = (() => {
|
|
|
191
197
|
isUseQsbSchemeRender: include("qsb-scheme-render.min.js")
|
|
192
198
|
};
|
|
193
199
|
})();
|
|
194
|
-
/**
|
|
195
|
-
* @param {*} args
|
|
196
|
-
* @param {import('../utils/defineConfig.js').Configuration} override
|
|
197
|
-
*/
|
|
198
200
|
function getWebpackConfig(args, override) {
|
|
199
201
|
const isDev = process.env.NODE_ENV === "development";
|
|
200
202
|
const isProd = process.env.NODE_ENV === "production";
|
|
@@ -225,7 +227,7 @@ function getWebpackConfig(args, override) {
|
|
|
225
227
|
isProd && PostcssSafeAreaPlugin(),
|
|
226
228
|
isProd && [require$2.resolve("postcss-momentum-scrolling"), ["scroll", "auto"]],
|
|
227
229
|
require$2.resolve("postcss-normalize"),
|
|
228
|
-
...override.extraPostCSSPlugins
|
|
230
|
+
...override.extraPostCSSPlugins || []
|
|
229
231
|
].filter(Boolean)
|
|
230
232
|
},
|
|
231
233
|
sourceMap: isDev
|
|
@@ -237,7 +239,7 @@ function getWebpackConfig(args, override) {
|
|
|
237
239
|
options: {
|
|
238
240
|
lessOptions: {
|
|
239
241
|
javascriptEnabled: true,
|
|
240
|
-
modifyVars: fs.existsSync(paths.theme) ? require$2(paths.theme) : void 0
|
|
242
|
+
modifyVars: fs.existsSync(paths.theme) ? resolveModule(require$2(paths.theme)) : void 0
|
|
241
243
|
},
|
|
242
244
|
sourceMap: true
|
|
243
245
|
}
|
|
@@ -304,7 +306,11 @@ function getWebpackConfig(args, override) {
|
|
|
304
306
|
".tsx",
|
|
305
307
|
".json",
|
|
306
308
|
".wasm"
|
|
307
|
-
]
|
|
309
|
+
],
|
|
310
|
+
tsConfig: {
|
|
311
|
+
configFile: paths.tsconfig,
|
|
312
|
+
references: "auto"
|
|
313
|
+
}
|
|
308
314
|
},
|
|
309
315
|
stats: false,
|
|
310
316
|
devtool: isDev ? "cheap-module-source-map" : false,
|
|
@@ -322,8 +328,9 @@ function getWebpackConfig(args, override) {
|
|
|
322
328
|
env: { targets: process.env.BROWSERSLIST },
|
|
323
329
|
rspackExperiments: { import: [{
|
|
324
330
|
libraryName: "lodash",
|
|
325
|
-
|
|
326
|
-
|
|
331
|
+
libraryDirectory: "",
|
|
332
|
+
camelToDashComponentName: false
|
|
333
|
+
}, ...override.import || []] },
|
|
327
334
|
isModule: "unknown",
|
|
328
335
|
jsc: {
|
|
329
336
|
parser: {
|
|
@@ -526,7 +533,6 @@ function getWebpackConfig(args, override) {
|
|
|
526
533
|
//#endregion
|
|
527
534
|
//#region src/config/plugins/mock-server/index.ts
|
|
528
535
|
const require$1 = createRequire(import.meta.url);
|
|
529
|
-
const { register } = require$1("@swc-node/register/register");
|
|
530
536
|
let mockCache = {};
|
|
531
537
|
let isSetup = false;
|
|
532
538
|
const setupMock = debounce(function setupMock() {
|
|
@@ -537,8 +543,7 @@ const setupMock = debounce(function setupMock() {
|
|
|
537
543
|
for (const file of files) {
|
|
538
544
|
delete require$1.cache[require$1.resolve(file)];
|
|
539
545
|
try {
|
|
540
|
-
|
|
541
|
-
mock = mock.default || mock;
|
|
546
|
+
const mock = resolveModule(require$1(file));
|
|
542
547
|
for (const key in mock) {
|
|
543
548
|
const [method, path] = key.split(" ");
|
|
544
549
|
mockCache[key] = {
|
|
@@ -622,7 +627,6 @@ const mockMiddlewave = function mockMiddlewave(req, res, next) {
|
|
|
622
627
|
};
|
|
623
628
|
function setupMockServer(middelwaves, _devServer) {
|
|
624
629
|
if (!fs.existsSync(paths.mock)) return;
|
|
625
|
-
register();
|
|
626
630
|
middelwaves.unshift({
|
|
627
631
|
name: "edu-scripts-mock-middelwave",
|
|
628
632
|
middleware: mockMiddlewave
|
|
@@ -633,7 +637,7 @@ function setupMockServer(middelwaves, _devServer) {
|
|
|
633
637
|
}
|
|
634
638
|
|
|
635
639
|
//#endregion
|
|
636
|
-
//#region src/config/webpackDevServerConfig.
|
|
640
|
+
//#region src/config/webpackDevServerConfig.ts
|
|
637
641
|
function createProxy(context, target, origin) {
|
|
638
642
|
const url = new URL(origin || target);
|
|
639
643
|
return {
|
|
@@ -647,13 +651,8 @@ function createProxy(context, target, origin) {
|
|
|
647
651
|
}
|
|
648
652
|
};
|
|
649
653
|
}
|
|
650
|
-
/**
|
|
651
|
-
* @param {*} args
|
|
652
|
-
* @param {import('../utils/defineConfig.js').Configuration} override
|
|
653
|
-
*/
|
|
654
654
|
function getWebpackDevServerConfig(args, override) {
|
|
655
655
|
const host = process.env.HOST || "0.0.0.0";
|
|
656
|
-
/** @type {import('@rspack/dev-server').Configuration} */
|
|
657
656
|
const devServer = {
|
|
658
657
|
allowedHosts: "all",
|
|
659
658
|
historyApiFallback: true,
|
|
@@ -680,10 +679,10 @@ function getWebpackDevServerConfig(args, override) {
|
|
|
680
679
|
compress: true
|
|
681
680
|
};
|
|
682
681
|
if (override.proxy) {
|
|
683
|
-
if (Array.isArray(override.proxy)) devServer.proxy = [...override.proxy, ...devServer.proxy];
|
|
682
|
+
if (Array.isArray(override.proxy)) devServer.proxy = [...override.proxy, ...devServer.proxy || []];
|
|
684
683
|
else if (typeof override.proxy === "object") devServer.proxy = [...Object.entries(override.proxy).map(([context, target]) => {
|
|
685
684
|
return createProxy(context, target);
|
|
686
|
-
}), ...devServer.proxy];
|
|
685
|
+
}), ...devServer.proxy || []];
|
|
687
686
|
else throw new Error("proxy 必须是数组或对象");
|
|
688
687
|
const proxyMap = /* @__PURE__ */ new Map();
|
|
689
688
|
devServer.proxy = devServer.proxy.filter((item) => {
|
|
@@ -713,7 +712,7 @@ function getOverride() {
|
|
|
713
712
|
if (override) return override;
|
|
714
713
|
override = Object.assign({}, defaultOverride);
|
|
715
714
|
if (fs.existsSync(paths.override)) {
|
|
716
|
-
const userOverride = require(paths.override);
|
|
715
|
+
const userOverride = resolveModule(require(paths.override));
|
|
717
716
|
if (typeof userOverride !== "object") throw new Error("格式错误,请使用 npx edu g override 生成文件");
|
|
718
717
|
Object.assign(override, userOverride);
|
|
719
718
|
}
|
|
@@ -770,7 +769,7 @@ async function start(args) {
|
|
|
770
769
|
}
|
|
771
770
|
|
|
772
771
|
//#endregion
|
|
773
|
-
//#region src/utils/FileSizeReporter.
|
|
772
|
+
//#region src/utils/FileSizeReporter.ts
|
|
774
773
|
/**
|
|
775
774
|
* Copyright (c) 2015-present, Facebook, Inc.
|
|
776
775
|
*
|
|
@@ -781,15 +780,15 @@ function canReadAsset(asset) {
|
|
|
781
780
|
return /\.(js|css)$/.test(asset) && !/service-worker\.js/.test(asset) && !/precache-manifest\.[0-9a-f]+\.js/.test(asset);
|
|
782
781
|
}
|
|
783
782
|
function printFileSizesAfterBuild(webpackStats, previousSizeMap, buildFolder, maxBundleGzipSize, maxChunkGzipSize) {
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
783
|
+
const root = previousSizeMap.root;
|
|
784
|
+
const sizes = previousSizeMap.sizes;
|
|
785
|
+
const assets = (webpackStats.stats || [webpackStats]).map((stats) => stats.toJson({
|
|
787
786
|
all: false,
|
|
788
787
|
assets: true
|
|
789
788
|
}).assets.filter((asset) => canReadAsset(asset.name)).map((asset) => {
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
789
|
+
const size = gzipSizeSync(fs.readFileSync(path.join(root, asset.name)));
|
|
790
|
+
const previousSize = sizes[removeFileNameHash(root, asset.name)];
|
|
791
|
+
const difference = getDifferenceLabel(size, previousSize);
|
|
793
792
|
return {
|
|
794
793
|
folder: path.join(path.basename(buildFolder), path.dirname(asset.name)),
|
|
795
794
|
name: path.basename(asset.name),
|
|
@@ -800,20 +799,20 @@ function printFileSizesAfterBuild(webpackStats, previousSizeMap, buildFolder, ma
|
|
|
800
799
|
if (assets.length === 0) return;
|
|
801
800
|
console.log("\ngzip 后文件大小:\n");
|
|
802
801
|
assets.sort((a, b) => b.size - a.size);
|
|
803
|
-
|
|
802
|
+
const mainAssetIdx = assets.findIndex((asset) => /_\d+\.\d+\.\d+/.test(asset.name));
|
|
804
803
|
assets.unshift(assets.splice(mainAssetIdx, 1)[0]);
|
|
805
|
-
|
|
806
|
-
|
|
804
|
+
const longestSizeLabelLength = Math.max.apply(null, assets.map((a) => stripAnsi(a.sizeLabel).length));
|
|
805
|
+
let suggestBundleSplitting = false;
|
|
807
806
|
assets.forEach((asset) => {
|
|
808
|
-
|
|
809
|
-
|
|
807
|
+
let sizeLabel = asset.sizeLabel;
|
|
808
|
+
const sizeLength = stripAnsi(sizeLabel).length;
|
|
810
809
|
if (sizeLength < longestSizeLabelLength) {
|
|
811
|
-
|
|
810
|
+
const rightPadding = " ".repeat(longestSizeLabelLength - sizeLength);
|
|
812
811
|
sizeLabel += rightPadding;
|
|
813
812
|
}
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
813
|
+
const isMainBundle = /_\d+\.\d+\.\d+\./.test(asset.name);
|
|
814
|
+
const maxRecommendedSize = isMainBundle ? maxBundleGzipSize : maxChunkGzipSize;
|
|
815
|
+
const isLarge = maxRecommendedSize && asset.size > maxRecommendedSize;
|
|
817
816
|
if (isLarge && path.extname(asset.name) === ".js") suggestBundleSplitting = true;
|
|
818
817
|
console.log(" " + (isLarge ? chalk.yellow(sizeLabel) : sizeLabel) + " " + chalk.dim(asset.folder + path.sep) + chalk.cyan(asset.name));
|
|
819
818
|
if (isMainBundle) console.log("");
|
|
@@ -830,9 +829,9 @@ function removeFileNameHash(buildFolder, fileName) {
|
|
|
830
829
|
return fileName.replace(buildFolder, "").replace(/\\/g, "/").replace(/\/\d+\.\d+\.\d+\//, "/").replace(/\/?(.*)(\.[0-9a-f]+)(\.chunk)?(\.js|\.css)/, (match, p1, p2, p3, p4) => p1 + p4);
|
|
831
830
|
}
|
|
832
831
|
function getDifferenceLabel(currentSize, previousSize) {
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
832
|
+
const FIFTY_KILOBYTES = 1024 * 50;
|
|
833
|
+
const difference = currentSize - previousSize;
|
|
834
|
+
const fileSize = !Number.isNaN(difference) ? filesize(difference) : 0;
|
|
836
835
|
if (difference >= FIFTY_KILOBYTES) return chalk.red("+" + fileSize);
|
|
837
836
|
else if (difference < FIFTY_KILOBYTES && difference > 0) return chalk.yellow("+" + fileSize);
|
|
838
837
|
else if (difference < 0) return chalk.green(fileSize);
|
|
@@ -841,10 +840,10 @@ function getDifferenceLabel(currentSize, previousSize) {
|
|
|
841
840
|
function measureFileSizesBeforeBuild(buildFolder) {
|
|
842
841
|
return new Promise((resolve) => {
|
|
843
842
|
recursive(buildFolder, (err, fileNames) => {
|
|
844
|
-
|
|
843
|
+
let sizes;
|
|
845
844
|
if (!err && fileNames) sizes = fileNames.filter(canReadAsset).reduce((memo, fileName) => {
|
|
846
|
-
|
|
847
|
-
|
|
845
|
+
const contents = fs.readFileSync(fileName);
|
|
846
|
+
const key = removeFileNameHash(buildFolder, fileName);
|
|
848
847
|
memo[key] = gzipSizeSync(contents);
|
|
849
848
|
return memo;
|
|
850
849
|
}, {});
|
|
@@ -899,7 +898,7 @@ async function build(args) {
|
|
|
899
898
|
}
|
|
900
899
|
|
|
901
900
|
//#endregion
|
|
902
|
-
//#region src/utils/changeDeployVersion.
|
|
901
|
+
//#region src/utils/changeDeployVersion.ts
|
|
903
902
|
const TARGET_IDENTIFIER_NAME = "project_apiArr";
|
|
904
903
|
const MODULE_IDENTIFIER_NAME = "module";
|
|
905
904
|
function changeDeployVersion(code, pkg) {
|
|
@@ -911,9 +910,6 @@ function changeDeployVersion(code, pkg) {
|
|
|
911
910
|
throw new Error(`代码解析错误: ${error.message}`, { cause: error });
|
|
912
911
|
}
|
|
913
912
|
const keyName = grayscale ? "grayscale" : "main";
|
|
914
|
-
/**
|
|
915
|
-
* @return {babel.NodePath<t.VariableDeclarator> | undefined}
|
|
916
|
-
*/
|
|
917
913
|
function findTargetDeclarator(ast) {
|
|
918
914
|
let res;
|
|
919
915
|
traverse(ast, { VariableDeclarator(path) {
|
|
@@ -921,44 +917,33 @@ function changeDeployVersion(code, pkg) {
|
|
|
921
917
|
} });
|
|
922
918
|
return res;
|
|
923
919
|
}
|
|
924
|
-
/**
|
|
925
|
-
* @param {babel.NodePath<t.VariableDeclarator>} path
|
|
926
|
-
* @return {babel.NodePath<t.ObjectExpression> | undefined}
|
|
927
|
-
*/
|
|
928
920
|
function findModuleObject(path) {
|
|
929
921
|
let res;
|
|
930
922
|
path.traverse({ ObjectExpression(path) {
|
|
931
|
-
if (path.node.properties.some((node) => types.isIdentifier(node.key, { name: MODULE_IDENTIFIER_NAME }) && types.isLiteral(node.value, { value: name }))) res = path;
|
|
923
|
+
if (path.node.properties.some((node) => types.isObjectProperty(node) && types.isIdentifier(node.key, { name: MODULE_IDENTIFIER_NAME }) && types.isLiteral(node.value, { value: name }))) res = path;
|
|
932
924
|
} });
|
|
933
925
|
return res;
|
|
934
926
|
}
|
|
935
|
-
/**
|
|
936
|
-
* @param {babel.NodePath<t.ObjectExpression>} path
|
|
937
|
-
*/
|
|
938
927
|
function modifyModuleVersion(path) {
|
|
939
928
|
let hasModify = false;
|
|
940
929
|
path.traverse({ Property(path) {
|
|
941
|
-
if (path.node.key
|
|
942
|
-
path.node.value.value = version;
|
|
930
|
+
if (types.isObjectProperty(path.node) && types.isIdentifier(path.node.key, { name: keyName })) {
|
|
931
|
+
if (types.isStringLiteral(path.node.value)) path.node.value.value = version;
|
|
943
932
|
hasModify = true;
|
|
944
933
|
}
|
|
945
934
|
} });
|
|
946
935
|
if (!hasModify) path.node.properties.push(types.objectProperty(types.identifier(keyName), types.stringLiteral(version)));
|
|
947
936
|
}
|
|
948
|
-
/**
|
|
949
|
-
* @param {babel.NodePath<t.ObjectExpression>} path
|
|
950
|
-
*/
|
|
951
937
|
function deleteModuleComments(path) {
|
|
952
938
|
path.traverse({ ObjectExpression(path) {
|
|
953
939
|
delete path.node.leadingComments;
|
|
954
940
|
} });
|
|
955
941
|
}
|
|
956
|
-
/**
|
|
957
|
-
* @param {babel.NodePath<t.VariableDeclarator>} path
|
|
958
|
-
*/
|
|
959
942
|
function addModuleToTarget(path) {
|
|
960
|
-
|
|
961
|
-
|
|
943
|
+
if (types.isArrayExpression(path.node.init)) {
|
|
944
|
+
const elements = path.node.init.elements;
|
|
945
|
+
elements.splice(elements.length - 2, 0, types.objectExpression([types.objectProperty(types.identifier(MODULE_IDENTIFIER_NAME), types.stringLiteral(name)), types.objectProperty(types.identifier(keyName), types.stringLiteral(version))]));
|
|
946
|
+
}
|
|
962
947
|
}
|
|
963
948
|
const targetPath = findTargetDeclarator(ast);
|
|
964
949
|
if (!targetPath) throw new Error(`ver.js 不合规范,未找到参数 ${TARGET_IDENTIFIER_NAME}`);
|
|
@@ -966,10 +951,12 @@ function changeDeployVersion(code, pkg) {
|
|
|
966
951
|
if (moduleObjPath) modifyModuleVersion(moduleObjPath);
|
|
967
952
|
else addModuleToTarget(targetPath);
|
|
968
953
|
deleteModuleComments(targetPath);
|
|
969
|
-
|
|
954
|
+
const result = transformFromAstSync(ast, void 0, {
|
|
970
955
|
filename: "ver.js",
|
|
971
956
|
minified: true
|
|
972
|
-
})
|
|
957
|
+
});
|
|
958
|
+
if (!result || !result.code) throw new Error("代码转换失败");
|
|
959
|
+
return result.code;
|
|
973
960
|
}
|
|
974
961
|
|
|
975
962
|
//#endregion
|
|
@@ -1045,7 +1032,7 @@ async function normalDeploy(args) {
|
|
|
1045
1032
|
try {
|
|
1046
1033
|
await sftp.fastGet(remoteLogFile, tmpLogFile);
|
|
1047
1034
|
content = await fs.readFile(tmpLogFile, "utf-8");
|
|
1048
|
-
} catch
|
|
1035
|
+
} catch {}
|
|
1049
1036
|
content = updateLogContent(content, info);
|
|
1050
1037
|
await fs.writeFile(tmpLogFile, content);
|
|
1051
1038
|
await sftp.fastPut(tmpLogFile, remoteLogFile);
|
|
@@ -1313,7 +1300,7 @@ function copyDistToRepo(info) {
|
|
|
1313
1300
|
exec(`svn co ${info.distBranchDirURL} ${tmpdir}`);
|
|
1314
1301
|
try {
|
|
1315
1302
|
exec(`svn rm * --force -q`, { cwd: tmpdir });
|
|
1316
|
-
} catch
|
|
1303
|
+
} catch {}
|
|
1317
1304
|
fs.copySync(paths.dist, tmpdir);
|
|
1318
1305
|
exec(`svn add * --force --auto-props --parents --depth infinity -q`, { cwd: tmpdir });
|
|
1319
1306
|
exec(`svn ci -m "${`[edu-scripts] commit ${info.branch} dist #${info.revision} @${info.author}`}"`, { cwd: tmpdir });
|
package/dist/index.d.mts
CHANGED
|
@@ -1,22 +1,18 @@
|
|
|
1
1
|
import { Chalk } from "chalk";
|
|
2
|
-
import { Compiler, Configuration } from "@rspack/core";
|
|
2
|
+
import { Compiler, Configuration, SwcLoaderOptions } from "@rspack/core";
|
|
3
3
|
import { Configuration as Configuration$1 } from "@rspack/dev-server";
|
|
4
4
|
import { RequestHandler } from "express";
|
|
5
5
|
|
|
6
6
|
//#region src/utils/defineConfig.d.ts
|
|
7
7
|
type ProxyConfigArray = NonNullable<Configuration$1['proxy']>;
|
|
8
|
-
type BabelImportPlugin = {
|
|
9
|
-
libraryName: string;
|
|
10
|
-
libraryDirectory?: string;
|
|
11
|
-
customName?: string;
|
|
12
|
-
style?: boolean | 'css' | string;
|
|
13
|
-
};
|
|
14
8
|
type Configuration$2 = {
|
|
15
9
|
webpack?: (config: Configuration) => Configuration | undefined;
|
|
16
10
|
devServer?: (config: Configuration$1) => Configuration$1 | undefined;
|
|
17
11
|
/**
|
|
18
12
|
* webpack alias 配置,会与内置 alias 合并
|
|
19
13
|
*
|
|
14
|
+
* 会自动读取 tsconfig 里 baseUrl + paths 的配置
|
|
15
|
+
*
|
|
20
16
|
* @default
|
|
21
17
|
* { '@': './src' }
|
|
22
18
|
*/
|
|
@@ -71,12 +67,10 @@ type Configuration$2 = {
|
|
|
71
67
|
/**
|
|
72
68
|
* 与 babel-plugin-import 类似,但是内部是 rspack 重构,libraryDirectory 默认值是 lib
|
|
73
69
|
*
|
|
74
|
-
* 如果 libraryDirectory 传 ’‘ 则必须使用 customName 来写
|
|
75
|
-
*
|
|
76
70
|
* @see https://rspack.rs/zh/guide/features/builtin-swc-loader#rspackexperimentsimport
|
|
77
|
-
* @default [{libraryName: 'lodash',
|
|
71
|
+
* @default [{libraryName: 'lodash',libraryDirectory: '',camelToDashComponentName: false}]
|
|
78
72
|
*/
|
|
79
|
-
import?:
|
|
73
|
+
import?: NonNullable<SwcLoaderOptions['rspackExperiments']>['import'];
|
|
80
74
|
};
|
|
81
75
|
declare function defineConfig(config: Configuration$2): Configuration$2;
|
|
82
76
|
//#endregion
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qse/edu-scripts",
|
|
3
|
-
"version": "0.0.0-beta.
|
|
3
|
+
"version": "0.0.0-beta.6",
|
|
4
4
|
"author": "Kinoko",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"docs:deploy": "ssh-sftp",
|
|
16
16
|
"build": "tsdown",
|
|
17
17
|
"deploy": "node scripts/deploy.js",
|
|
18
|
-
"release": "npm run test && npm run build && npm publish && rimraf
|
|
18
|
+
"release": "npm run test && npm run build && npm publish && rimraf dist",
|
|
19
19
|
"prettier": "prettier -c -w \"src/**/*.{js,jsx,tsx,ts,less,md,json}\"",
|
|
20
20
|
"lint": "eslint --fix src",
|
|
21
21
|
"postversion": "npm run release",
|
package/src/cli.ts
CHANGED
package/src/commit-dist.ts
CHANGED
|
@@ -61,10 +61,7 @@ function copyDistToRepo(info: WorkingCopyInfo) {
|
|
|
61
61
|
|
|
62
62
|
try {
|
|
63
63
|
exec(`svn rm * --force -q`, { cwd: tmpdir })
|
|
64
|
-
} catch
|
|
65
|
-
// 如果目录为空,svn rm 会报错,忽略即可
|
|
66
|
-
}
|
|
67
|
-
|
|
64
|
+
} catch {}
|
|
68
65
|
fs.copySync(paths.dist, tmpdir)
|
|
69
66
|
|
|
70
67
|
exec(`svn add * --force --auto-props --parents --depth infinity -q`, { cwd: tmpdir })
|
package/src/config/paths.ts
CHANGED
|
@@ -40,9 +40,8 @@ const paths = {
|
|
|
40
40
|
jsconfig: resolveApp('jsconfig.json'),
|
|
41
41
|
package: resolveApp('package.json'),
|
|
42
42
|
tailwind: resolveApp('tailwind.config.js'),
|
|
43
|
-
indexJS: resolveApp('src', 'index.js'),
|
|
44
43
|
pages: resolveApp('src', 'pages'),
|
|
45
|
-
override: resolveApp('edu-scripts.override.js'),
|
|
44
|
+
override: getExistPath(resolveApp('edu-scripts.override.js'), resolveApp('edu-scripts.override.ts')),
|
|
46
45
|
indexHTML: globbySync('./public/*.html', { absolute: true }),
|
|
47
46
|
src: resolveApp('src'),
|
|
48
47
|
public: resolveApp('public'),
|
|
@@ -9,8 +9,8 @@ import cookieParser from 'cookie-parser'
|
|
|
9
9
|
import multer from 'multer'
|
|
10
10
|
import { pathToRegexp, type Key } from 'path-to-regexp'
|
|
11
11
|
import { createRequire } from 'node:module'
|
|
12
|
+
import { resolveModule } from '@/utils/resolveModule'
|
|
12
13
|
const require = createRequire(import.meta.url)
|
|
13
|
-
const { register } = require('@swc-node/register/register')
|
|
14
14
|
|
|
15
15
|
let mockCache: Record<string, { handler: any; method: string; path: string }> = {}
|
|
16
16
|
let isSetup = false
|
|
@@ -31,8 +31,7 @@ const setupMock = debounce(function setupMock() {
|
|
|
31
31
|
for (const file of files) {
|
|
32
32
|
delete require.cache[require.resolve(file)]
|
|
33
33
|
try {
|
|
34
|
-
|
|
35
|
-
mock = mock.default || mock
|
|
34
|
+
const mock = resolveModule(require(file))
|
|
36
35
|
|
|
37
36
|
for (const key in mock) {
|
|
38
37
|
const [method, path] = key.split(' ')
|
|
@@ -129,8 +128,6 @@ type Middlewares = Parameters<
|
|
|
129
128
|
function setupMockServer(middelwaves: Middlewares, _devServer: any) {
|
|
130
129
|
if (!fs.existsSync(paths.mock)) return
|
|
131
130
|
|
|
132
|
-
register()
|
|
133
|
-
|
|
134
131
|
middelwaves.unshift({
|
|
135
132
|
name: 'edu-scripts-mock-middelwave',
|
|
136
133
|
middleware: mockMiddlewave as any,
|
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
import { RsdoctorRspackPlugin } from '@rsdoctor/rspack-plugin'
|
|
2
2
|
import { rspack } from '@rspack/core'
|
|
3
|
+
import type { Configuration, Compiler, RuleSetRule, SwcLoaderOptions } from '@rspack/core'
|
|
3
4
|
import ReactRefreshPlugin from '@rspack/plugin-react-refresh'
|
|
4
5
|
import chalk from 'chalk'
|
|
5
6
|
import fs from 'fs-extra'
|
|
6
7
|
import HtmlWebpackPlugin from 'html-webpack-plugin'
|
|
7
8
|
import { createRequire } from 'node:module'
|
|
8
|
-
import appConfig from '../utils/appConfig
|
|
9
|
-
import
|
|
10
|
-
import
|
|
9
|
+
import appConfig from '../utils/appConfig'
|
|
10
|
+
import type { Configuration as CustomConfiguration } from '../utils/defineConfig'
|
|
11
|
+
import paths from './paths'
|
|
12
|
+
import PostcssSafeAreaPlugin from './plugins/postcss-safe-area'
|
|
13
|
+
import { resolveModule } from '@/utils/resolveModule'
|
|
14
|
+
|
|
11
15
|
const require = createRequire(import.meta.url)
|
|
12
|
-
const appPkg = fs.readJsonSync(paths.package)
|
|
16
|
+
const appPkg = fs.readJsonSync(paths.package) as { name: string; version: string }
|
|
13
17
|
|
|
14
18
|
const jsMainPath = appConfig.grayscale
|
|
15
19
|
? `${appPkg.name}/beta/${appPkg.name}`
|
|
@@ -25,10 +29,19 @@ const lessModuleRegex = /\.module\.less$/
|
|
|
25
29
|
|
|
26
30
|
const imageInlineSizeLimit = 10 * 1024
|
|
27
31
|
|
|
28
|
-
|
|
32
|
+
interface QseCDN {
|
|
33
|
+
isUseCommon: boolean
|
|
34
|
+
isUseAxios: boolean
|
|
35
|
+
isUseMoment: boolean
|
|
36
|
+
isUseAntd: boolean
|
|
37
|
+
isUseQsbAntd: boolean
|
|
38
|
+
isUseQsbSchemeRender: boolean
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const qseCDN: QseCDN = (() => {
|
|
29
42
|
const contents = paths.indexHTML.map((url) => fs.readFileSync(url, 'utf-8'))
|
|
30
43
|
|
|
31
|
-
function include(pattern) {
|
|
44
|
+
function include(pattern: string | RegExp): boolean {
|
|
32
45
|
const regexp = new RegExp(pattern)
|
|
33
46
|
return contents.some((content) => regexp.test(content))
|
|
34
47
|
}
|
|
@@ -43,16 +56,21 @@ const qseCDN = (() => {
|
|
|
43
56
|
}
|
|
44
57
|
})()
|
|
45
58
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
59
|
+
interface CSSLoaderOptions {
|
|
60
|
+
importLoaders: number
|
|
61
|
+
sourceMap: boolean
|
|
62
|
+
modules: {
|
|
63
|
+
mode: 'global' | 'local'
|
|
64
|
+
localIdentName: string
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export default function getWebpackConfig(args: any, override: CustomConfiguration): Configuration {
|
|
51
69
|
const isDev = process.env.NODE_ENV === 'development'
|
|
52
70
|
const isProd = process.env.NODE_ENV === 'production'
|
|
53
71
|
|
|
54
72
|
// common function to get style loaders
|
|
55
|
-
const getStyleLoaders = (cssOptions, preProcessor) => {
|
|
73
|
+
const getStyleLoaders = (cssOptions: CSSLoaderOptions, preProcessor?: string) => {
|
|
56
74
|
const loaders = [
|
|
57
75
|
{
|
|
58
76
|
loader: require.resolve('style-loader'),
|
|
@@ -89,7 +107,7 @@ export default function getWebpackConfig(args, override) {
|
|
|
89
107
|
isProd && PostcssSafeAreaPlugin(),
|
|
90
108
|
isProd && [require.resolve('postcss-momentum-scrolling'), ['scroll', 'auto']],
|
|
91
109
|
require.resolve('postcss-normalize'),
|
|
92
|
-
...override.extraPostCSSPlugins,
|
|
110
|
+
...(override.extraPostCSSPlugins || []),
|
|
93
111
|
].filter(Boolean),
|
|
94
112
|
},
|
|
95
113
|
sourceMap: isDev,
|
|
@@ -102,19 +120,20 @@ export default function getWebpackConfig(args, override) {
|
|
|
102
120
|
options: {
|
|
103
121
|
lessOptions: {
|
|
104
122
|
javascriptEnabled: true,
|
|
105
|
-
modifyVars: fs.existsSync(paths.theme)
|
|
123
|
+
modifyVars: fs.existsSync(paths.theme)
|
|
124
|
+
? resolveModule(require(paths.theme))
|
|
125
|
+
: undefined,
|
|
106
126
|
},
|
|
107
127
|
sourceMap: true,
|
|
108
128
|
},
|
|
109
|
-
})
|
|
129
|
+
} as any)
|
|
110
130
|
}
|
|
111
131
|
return loaders
|
|
112
132
|
}
|
|
113
133
|
|
|
114
|
-
|
|
115
|
-
const config = {
|
|
134
|
+
const config: Configuration = {
|
|
116
135
|
context: process.cwd(),
|
|
117
|
-
mode: process.env.NODE_ENV,
|
|
136
|
+
mode: process.env.NODE_ENV as 'development' | 'production' | 'none',
|
|
118
137
|
entry: './src/index',
|
|
119
138
|
target: 'browserslist',
|
|
120
139
|
output: {
|
|
@@ -184,6 +203,10 @@ export default function getWebpackConfig(args, override) {
|
|
|
184
203
|
...override.alias,
|
|
185
204
|
},
|
|
186
205
|
extensions: ['.web.js', '.web.mjs', '.js', '.mjs', '.jsx', '.ts', '.tsx', '.json', '.wasm'],
|
|
206
|
+
tsConfig: {
|
|
207
|
+
configFile: paths.tsconfig,
|
|
208
|
+
references: 'auto',
|
|
209
|
+
},
|
|
187
210
|
},
|
|
188
211
|
stats: false,
|
|
189
212
|
devtool: isDev ? 'cheap-module-source-map' : false,
|
|
@@ -207,9 +230,10 @@ export default function getWebpackConfig(args, override) {
|
|
|
207
230
|
import: [
|
|
208
231
|
{
|
|
209
232
|
libraryName: 'lodash',
|
|
210
|
-
|
|
233
|
+
libraryDirectory: '',
|
|
234
|
+
camelToDashComponentName: false,
|
|
211
235
|
},
|
|
212
|
-
...override.import,
|
|
236
|
+
...(override.import || []),
|
|
213
237
|
],
|
|
214
238
|
},
|
|
215
239
|
isModule: 'unknown',
|
|
@@ -229,7 +253,7 @@ export default function getWebpackConfig(args, override) {
|
|
|
229
253
|
},
|
|
230
254
|
},
|
|
231
255
|
},
|
|
232
|
-
},
|
|
256
|
+
} satisfies SwcLoaderOptions,
|
|
233
257
|
},
|
|
234
258
|
],
|
|
235
259
|
},
|
|
@@ -365,7 +389,7 @@ export default function getWebpackConfig(args, override) {
|
|
|
365
389
|
test: /\.(?!(?:js|mjs|jsx|ts|tsx|html|json)$)[^.]+$/,
|
|
366
390
|
type: 'asset/resource',
|
|
367
391
|
},
|
|
368
|
-
].filter(Boolean),
|
|
392
|
+
].filter(Boolean) as RuleSetRule[],
|
|
369
393
|
},
|
|
370
394
|
],
|
|
371
395
|
},
|
|
@@ -417,7 +441,7 @@ export default function getWebpackConfig(args, override) {
|
|
|
417
441
|
: []),
|
|
418
442
|
process.env.ANALYZE && isProd && new RsdoctorRspackPlugin(),
|
|
419
443
|
isDev &&
|
|
420
|
-
((compiler) => {
|
|
444
|
+
((compiler: Compiler) => {
|
|
421
445
|
let isFirst = true
|
|
422
446
|
compiler.hooks.afterDone.tap('edu-scripts-startup', (stats) => {
|
|
423
447
|
if (!isFirst) console.clear()
|
|
@@ -1,6 +1,15 @@
|
|
|
1
|
+
import type { Configuration } from '@rspack/dev-server'
|
|
2
|
+
import type { Configuration as CustomConfiguration } from '../utils/defineConfig'
|
|
1
3
|
import setupMockServer from './plugins/mock-server'
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
interface ProxyConfig {
|
|
6
|
+
context: string[]
|
|
7
|
+
target: string
|
|
8
|
+
changeOrigin: boolean
|
|
9
|
+
onProxyReq: (proxyReq: any) => void
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function createProxy(context: string, target: string, origin?: string): ProxyConfig {
|
|
4
13
|
const url = new URL(origin || target)
|
|
5
14
|
|
|
6
15
|
return {
|
|
@@ -15,15 +24,10 @@ function createProxy(context, target, origin) {
|
|
|
15
24
|
}
|
|
16
25
|
}
|
|
17
26
|
|
|
18
|
-
|
|
19
|
-
* @param {*} args
|
|
20
|
-
* @param {import('../utils/defineConfig.js').Configuration} override
|
|
21
|
-
*/
|
|
22
|
-
export default function getWebpackDevServerConfig(args, override) {
|
|
27
|
+
export default function getWebpackDevServerConfig(args: any, override: CustomConfiguration): Configuration {
|
|
23
28
|
const host = process.env.HOST || '0.0.0.0'
|
|
24
29
|
|
|
25
|
-
|
|
26
|
-
const devServer = {
|
|
30
|
+
const devServer: Configuration = {
|
|
27
31
|
allowedHosts: 'all',
|
|
28
32
|
historyApiFallback: true,
|
|
29
33
|
port: args.port,
|
|
@@ -56,19 +60,19 @@ export default function getWebpackDevServerConfig(args, override) {
|
|
|
56
60
|
|
|
57
61
|
if (override.proxy) {
|
|
58
62
|
if (Array.isArray(override.proxy)) {
|
|
59
|
-
devServer.proxy = [...override.proxy, ...devServer.proxy]
|
|
63
|
+
devServer.proxy = [...override.proxy, ...(devServer.proxy || [])]
|
|
60
64
|
} else if (typeof override.proxy === 'object') {
|
|
61
65
|
const proxies = Object.entries(override.proxy).map(([context, target]) => {
|
|
62
|
-
return createProxy(context, target)
|
|
66
|
+
return createProxy(context, target as string)
|
|
63
67
|
})
|
|
64
|
-
devServer.proxy = [...proxies, ...devServer.proxy]
|
|
68
|
+
devServer.proxy = [...proxies, ...(devServer.proxy || [])]
|
|
65
69
|
} else {
|
|
66
70
|
throw new Error('proxy 必须是数组或对象')
|
|
67
71
|
}
|
|
68
72
|
|
|
69
73
|
// 清理重复的代理配置
|
|
70
|
-
const proxyMap = new Map()
|
|
71
|
-
devServer.proxy = devServer.proxy.filter((item) => {
|
|
74
|
+
const proxyMap = new Map<string, boolean>()
|
|
75
|
+
devServer.proxy = (devServer.proxy as ProxyConfig[]).filter((item) => {
|
|
72
76
|
const key = JSON.stringify([...item.context].sort())
|
|
73
77
|
if (!proxyMap.has(key)) {
|
|
74
78
|
proxyMap.set(key, true)
|
package/src/deploy.ts
CHANGED
|
@@ -96,7 +96,7 @@ async function normalDeploy(args: DeployArgs) {
|
|
|
96
96
|
try {
|
|
97
97
|
await sftp.fastGet(remoteLogFile, tmpLogFile)
|
|
98
98
|
content = await fs.readFile(tmpLogFile, 'utf-8')
|
|
99
|
-
} catch
|
|
99
|
+
} catch {}
|
|
100
100
|
content = updateLogContent(content, info)
|
|
101
101
|
await fs.writeFile(tmpLogFile, content)
|
|
102
102
|
await sftp.fastPut(tmpLogFile, remoteLogFile)
|
|
@@ -9,11 +9,22 @@ import fs from 'fs-extra'
|
|
|
9
9
|
import path from 'path'
|
|
10
10
|
import chalk from 'chalk'
|
|
11
11
|
import filesize from 'filesize'
|
|
12
|
+
// @ts-ignore
|
|
12
13
|
import recursive from 'recursive-readdir'
|
|
13
14
|
import stripAnsi from 'strip-ansi'
|
|
14
15
|
import { gzipSizeSync } from 'gzip-size'
|
|
16
|
+
import type { Stats } from '@rspack/core'
|
|
15
17
|
|
|
16
|
-
|
|
18
|
+
interface SizeMap {
|
|
19
|
+
root: string
|
|
20
|
+
sizes: Record<string, number>
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
interface WebpackStats extends Stats {
|
|
24
|
+
stats?: Stats[]
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function canReadAsset(asset: string): boolean {
|
|
17
28
|
return (
|
|
18
29
|
/\.(js|css)$/.test(asset) &&
|
|
19
30
|
!/service-worker\.js/.test(asset) &&
|
|
@@ -23,24 +34,24 @@ function canReadAsset(asset) {
|
|
|
23
34
|
|
|
24
35
|
// Prints a detailed summary of build files.
|
|
25
36
|
function printFileSizesAfterBuild(
|
|
26
|
-
webpackStats,
|
|
27
|
-
previousSizeMap,
|
|
28
|
-
buildFolder,
|
|
29
|
-
maxBundleGzipSize,
|
|
30
|
-
maxChunkGzipSize
|
|
31
|
-
) {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
37
|
+
webpackStats: WebpackStats,
|
|
38
|
+
previousSizeMap: SizeMap,
|
|
39
|
+
buildFolder: string,
|
|
40
|
+
maxBundleGzipSize: number,
|
|
41
|
+
maxChunkGzipSize: number
|
|
42
|
+
): void {
|
|
43
|
+
const root = previousSizeMap.root
|
|
44
|
+
const sizes = previousSizeMap.sizes
|
|
45
|
+
const assets = (webpackStats.stats || [webpackStats])
|
|
35
46
|
.map((stats) =>
|
|
36
47
|
stats
|
|
37
48
|
.toJson({ all: false, assets: true })
|
|
38
|
-
.assets
|
|
49
|
+
.assets!.filter((asset) => canReadAsset(asset.name))
|
|
39
50
|
.map((asset) => {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
51
|
+
const fileContents = fs.readFileSync(path.join(root, asset.name))
|
|
52
|
+
const size = gzipSizeSync(fileContents)
|
|
53
|
+
const previousSize = sizes[removeFileNameHash(root, asset.name)]
|
|
54
|
+
const difference = getDifferenceLabel(size, previousSize)
|
|
44
55
|
return {
|
|
45
56
|
folder: path.join(path.basename(buildFolder), path.dirname(asset.name)),
|
|
46
57
|
name: path.basename(asset.name),
|
|
@@ -58,24 +69,24 @@ function printFileSizesAfterBuild(
|
|
|
58
69
|
assets.sort((a, b) => b.size - a.size)
|
|
59
70
|
|
|
60
71
|
// move main file to first
|
|
61
|
-
|
|
72
|
+
const mainAssetIdx = assets.findIndex((asset) => /_\d+\.\d+\.\d+/.test(asset.name))
|
|
62
73
|
assets.unshift(assets.splice(mainAssetIdx, 1)[0])
|
|
63
74
|
|
|
64
|
-
|
|
75
|
+
const longestSizeLabelLength = Math.max.apply(
|
|
65
76
|
null,
|
|
66
77
|
assets.map((a) => stripAnsi(a.sizeLabel).length)
|
|
67
78
|
)
|
|
68
|
-
|
|
79
|
+
let suggestBundleSplitting = false
|
|
69
80
|
assets.forEach((asset) => {
|
|
70
|
-
|
|
71
|
-
|
|
81
|
+
let sizeLabel = asset.sizeLabel
|
|
82
|
+
const sizeLength = stripAnsi(sizeLabel).length
|
|
72
83
|
if (sizeLength < longestSizeLabelLength) {
|
|
73
|
-
|
|
84
|
+
const rightPadding = ' '.repeat(longestSizeLabelLength - sizeLength)
|
|
74
85
|
sizeLabel += rightPadding
|
|
75
86
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
87
|
+
const isMainBundle = /_\d+\.\d+\.\d+\./.test(asset.name)
|
|
88
|
+
const maxRecommendedSize = isMainBundle ? maxBundleGzipSize : maxChunkGzipSize
|
|
89
|
+
const isLarge = maxRecommendedSize && asset.size > maxRecommendedSize
|
|
79
90
|
if (isLarge && path.extname(asset.name) === '.js') {
|
|
80
91
|
suggestBundleSplitting = true
|
|
81
92
|
}
|
|
@@ -100,7 +111,7 @@ function printFileSizesAfterBuild(
|
|
|
100
111
|
console.log()
|
|
101
112
|
}
|
|
102
113
|
|
|
103
|
-
function removeFileNameHash(buildFolder, fileName) {
|
|
114
|
+
function removeFileNameHash(buildFolder: string, fileName: string): string {
|
|
104
115
|
return fileName
|
|
105
116
|
.replace(buildFolder, '')
|
|
106
117
|
.replace(/\\/g, '/')
|
|
@@ -110,10 +121,10 @@ function removeFileNameHash(buildFolder, fileName) {
|
|
|
110
121
|
|
|
111
122
|
// Input: 1024, 2048
|
|
112
123
|
// Output: "(+1 KB)"
|
|
113
|
-
function getDifferenceLabel(currentSize, previousSize) {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
124
|
+
function getDifferenceLabel(currentSize: number, previousSize: number): string {
|
|
125
|
+
const FIFTY_KILOBYTES = 1024 * 50
|
|
126
|
+
const difference = currentSize - previousSize
|
|
127
|
+
const fileSize = !Number.isNaN(difference) ? filesize(difference) : 0
|
|
117
128
|
if (difference >= FIFTY_KILOBYTES) {
|
|
118
129
|
return chalk.red('+' + fileSize)
|
|
119
130
|
} else if (difference < FIFTY_KILOBYTES && difference > 0) {
|
|
@@ -125,17 +136,20 @@ function getDifferenceLabel(currentSize, previousSize) {
|
|
|
125
136
|
}
|
|
126
137
|
}
|
|
127
138
|
|
|
128
|
-
function measureFileSizesBeforeBuild(buildFolder) {
|
|
139
|
+
function measureFileSizesBeforeBuild(buildFolder: string): Promise<SizeMap> {
|
|
129
140
|
return new Promise((resolve) => {
|
|
130
|
-
recursive(buildFolder, (err, fileNames) => {
|
|
131
|
-
|
|
141
|
+
recursive(buildFolder, (err: any, fileNames: any) => {
|
|
142
|
+
let sizes: Record<string, number> | undefined
|
|
132
143
|
if (!err && fileNames) {
|
|
133
|
-
sizes = fileNames.filter(canReadAsset).reduce(
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
144
|
+
sizes = fileNames.filter(canReadAsset).reduce(
|
|
145
|
+
(memo: any, fileName: any) => {
|
|
146
|
+
const contents = fs.readFileSync(fileName)
|
|
147
|
+
const key = removeFileNameHash(buildFolder, fileName)
|
|
148
|
+
memo[key] = gzipSizeSync(contents)
|
|
149
|
+
return memo
|
|
150
|
+
},
|
|
151
|
+
{} as Record<string, number>
|
|
152
|
+
)
|
|
139
153
|
}
|
|
140
154
|
resolve({
|
|
141
155
|
root: buildFolder,
|
|
@@ -1,24 +1,28 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
1
2
|
import { parse, traverse, types as t, transformFromAstSync } from '@babel/core'
|
|
2
3
|
|
|
3
4
|
// ver.js 中定义模块的数组
|
|
4
5
|
const TARGET_IDENTIFIER_NAME = 'project_apiArr'
|
|
5
6
|
const MODULE_IDENTIFIER_NAME = 'module'
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
interface PackageInfo {
|
|
9
|
+
name: string
|
|
10
|
+
version: string
|
|
11
|
+
grayscale?: boolean
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function changeDeployVersion(code: string, pkg: PackageInfo): string {
|
|
8
15
|
const { name, version, grayscale } = pkg
|
|
9
16
|
let ast
|
|
10
17
|
try {
|
|
11
18
|
ast = parse(code, { filename: 'ver.js' })
|
|
12
|
-
} catch (error) {
|
|
19
|
+
} catch (error: any) {
|
|
13
20
|
throw new Error(`代码解析错误: ${error.message}`, { cause: error })
|
|
14
21
|
}
|
|
15
22
|
const keyName = grayscale ? 'grayscale' : 'main'
|
|
16
23
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
*/
|
|
20
|
-
function findTargetDeclarator(ast) {
|
|
21
|
-
let res
|
|
24
|
+
function findTargetDeclarator(ast: any): any | undefined {
|
|
25
|
+
let res: any | undefined
|
|
22
26
|
|
|
23
27
|
traverse(ast, {
|
|
24
28
|
VariableDeclarator(path) {
|
|
@@ -34,18 +38,15 @@ function changeDeployVersion(code, pkg) {
|
|
|
34
38
|
return res
|
|
35
39
|
}
|
|
36
40
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
* @return {babel.NodePath<t.ObjectExpression> | undefined}
|
|
40
|
-
*/
|
|
41
|
-
function findModuleObject(path) {
|
|
42
|
-
let res
|
|
41
|
+
function findModuleObject(path: any): any | undefined {
|
|
42
|
+
let res: any | undefined
|
|
43
43
|
|
|
44
44
|
path.traverse({
|
|
45
45
|
ObjectExpression(path) {
|
|
46
46
|
if (
|
|
47
47
|
path.node.properties.some(
|
|
48
48
|
(node) =>
|
|
49
|
+
t.isObjectProperty(node) &&
|
|
49
50
|
t.isIdentifier(node.key, { name: MODULE_IDENTIFIER_NAME }) &&
|
|
50
51
|
t.isLiteral(node.value, { value: name })
|
|
51
52
|
)
|
|
@@ -58,15 +59,14 @@ function changeDeployVersion(code, pkg) {
|
|
|
58
59
|
return res
|
|
59
60
|
}
|
|
60
61
|
|
|
61
|
-
|
|
62
|
-
* @param {babel.NodePath<t.ObjectExpression>} path
|
|
63
|
-
*/
|
|
64
|
-
function modifyModuleVersion(path) {
|
|
62
|
+
function modifyModuleVersion(path: any): void {
|
|
65
63
|
let hasModify = false
|
|
66
64
|
path.traverse({
|
|
67
65
|
Property(path) {
|
|
68
|
-
if (path.node.key
|
|
69
|
-
path.node.value
|
|
66
|
+
if (t.isObjectProperty(path.node) && t.isIdentifier(path.node.key, { name: keyName })) {
|
|
67
|
+
if (t.isStringLiteral(path.node.value)) {
|
|
68
|
+
path.node.value.value = version
|
|
69
|
+
}
|
|
70
70
|
hasModify = true
|
|
71
71
|
}
|
|
72
72
|
},
|
|
@@ -76,10 +76,8 @@ function changeDeployVersion(code, pkg) {
|
|
|
76
76
|
path.node.properties.push(t.objectProperty(t.identifier(keyName), t.stringLiteral(version)))
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
*/
|
|
82
|
-
function deleteModuleComments(path) {
|
|
79
|
+
|
|
80
|
+
function deleteModuleComments(path: any): void {
|
|
83
81
|
path.traverse({
|
|
84
82
|
ObjectExpression(path) {
|
|
85
83
|
delete path.node.leadingComments
|
|
@@ -87,19 +85,18 @@ function changeDeployVersion(code, pkg) {
|
|
|
87
85
|
})
|
|
88
86
|
}
|
|
89
87
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
)
|
|
88
|
+
function addModuleToTarget(path: any): void {
|
|
89
|
+
if (t.isArrayExpression(path.node.init)) {
|
|
90
|
+
const elements = path.node.init.elements
|
|
91
|
+
elements.splice(
|
|
92
|
+
elements.length - 2,
|
|
93
|
+
0,
|
|
94
|
+
t.objectExpression([
|
|
95
|
+
t.objectProperty(t.identifier(MODULE_IDENTIFIER_NAME), t.stringLiteral(name)),
|
|
96
|
+
t.objectProperty(t.identifier(keyName), t.stringLiteral(version)),
|
|
97
|
+
])
|
|
98
|
+
)
|
|
99
|
+
}
|
|
103
100
|
}
|
|
104
101
|
|
|
105
102
|
const targetPath = findTargetDeclarator(ast)
|
|
@@ -113,7 +110,12 @@ function changeDeployVersion(code, pkg) {
|
|
|
113
110
|
}
|
|
114
111
|
deleteModuleComments(targetPath)
|
|
115
112
|
|
|
116
|
-
|
|
113
|
+
const result = transformFromAstSync(ast, undefined, { filename: 'ver.js', minified: true })
|
|
114
|
+
if (!result || !result.code) {
|
|
115
|
+
throw new Error('代码转换失败')
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return result.code
|
|
117
119
|
}
|
|
118
120
|
|
|
119
121
|
export default changeDeployVersion
|
|
@@ -1,22 +1,17 @@
|
|
|
1
1
|
import type { Chalk } from 'chalk'
|
|
2
|
-
import type { Compiler, Configuration as RspackConfiguration } from '@rspack/core'
|
|
2
|
+
import type { Compiler, Configuration as RspackConfiguration, SwcLoaderOptions } from '@rspack/core'
|
|
3
3
|
import type { Configuration as DevServerConfiguration } from '@rspack/dev-server'
|
|
4
4
|
|
|
5
5
|
type ProxyConfigArray = NonNullable<DevServerConfiguration['proxy']>
|
|
6
6
|
|
|
7
|
-
export type BabelImportPlugin = {
|
|
8
|
-
libraryName: string
|
|
9
|
-
libraryDirectory?: string
|
|
10
|
-
customName?: string
|
|
11
|
-
style?: boolean | 'css' | string
|
|
12
|
-
}
|
|
13
|
-
|
|
14
7
|
export type Configuration = {
|
|
15
8
|
webpack?: (config: RspackConfiguration) => RspackConfiguration | undefined
|
|
16
9
|
devServer?: (config: DevServerConfiguration) => DevServerConfiguration | undefined
|
|
17
10
|
/**
|
|
18
11
|
* webpack alias 配置,会与内置 alias 合并
|
|
19
12
|
*
|
|
13
|
+
* 会自动读取 tsconfig 里 baseUrl + paths 的配置
|
|
14
|
+
*
|
|
20
15
|
* @default
|
|
21
16
|
* { '@': './src' }
|
|
22
17
|
*/
|
|
@@ -76,12 +71,10 @@ export type Configuration = {
|
|
|
76
71
|
/**
|
|
77
72
|
* 与 babel-plugin-import 类似,但是内部是 rspack 重构,libraryDirectory 默认值是 lib
|
|
78
73
|
*
|
|
79
|
-
* 如果 libraryDirectory 传 ’‘ 则必须使用 customName 来写
|
|
80
|
-
*
|
|
81
74
|
* @see https://rspack.rs/zh/guide/features/builtin-swc-loader#rspackexperimentsimport
|
|
82
|
-
* @default [{libraryName: 'lodash',
|
|
75
|
+
* @default [{libraryName: 'lodash',libraryDirectory: '',camelToDashComponentName: false}]
|
|
83
76
|
*/
|
|
84
|
-
import?:
|
|
77
|
+
import?: NonNullable<SwcLoaderOptions['rspackExperiments']>['import']
|
|
85
78
|
}
|
|
86
79
|
export function defineConfig(config: Configuration) {
|
|
87
80
|
return config
|
package/src/utils/getOverride.ts
CHANGED
|
@@ -2,6 +2,7 @@ import fs from 'fs-extra'
|
|
|
2
2
|
import paths from '../config/paths'
|
|
3
3
|
import { createRequire } from 'node:module'
|
|
4
4
|
import { type Configuration } from './defineConfig'
|
|
5
|
+
import { resolveModule } from './resolveModule'
|
|
5
6
|
|
|
6
7
|
const require = createRequire(import.meta.url)
|
|
7
8
|
|
|
@@ -21,7 +22,7 @@ export default function getOverride(): Configuration {
|
|
|
21
22
|
override = Object.assign({}, defaultOverride)
|
|
22
23
|
|
|
23
24
|
if (fs.existsSync(paths.override)) {
|
|
24
|
-
const userOverride = require(paths.override)
|
|
25
|
+
const userOverride = resolveModule(require(paths.override))
|
|
25
26
|
if (typeof userOverride !== 'object')
|
|
26
27
|
throw new Error('格式错误,请使用 npx edu g override 生成文件')
|
|
27
28
|
Object.assign(override, userOverride)
|