@4399ywkf/core 5.0.11 → 5.0.13
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/index.d.ts +61 -15
- package/dist/index.js +638 -108
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2672,6 +2672,7 @@ export async function initGarfishMaster(): Promise<void> {
|
|
|
2672
2672
|
// src/plugin/builtin/tailwind.ts
|
|
2673
2673
|
import { existsSync as existsSync7, writeFileSync as writeFileSync3 } from "fs";
|
|
2674
2674
|
import { join as join7 } from "path";
|
|
2675
|
+
import { rspack as rspack3 } from "@rspack/core";
|
|
2675
2676
|
var tailwindPlugin = createPlugin((options = {}) => ({
|
|
2676
2677
|
name: "@4399ywkf/plugin-tailwind",
|
|
2677
2678
|
version: "1.0.0",
|
|
@@ -2695,7 +2696,7 @@ var tailwindPlugin = createPlugin((options = {}) => ({
|
|
|
2695
2696
|
const tailwindRule = {
|
|
2696
2697
|
test: /tailwind\.css$/,
|
|
2697
2698
|
use: [
|
|
2698
|
-
isProd ?
|
|
2699
|
+
isProd ? rspack3.CssExtractRspackPlugin.loader : "style-loader",
|
|
2699
2700
|
"css-loader",
|
|
2700
2701
|
{
|
|
2701
2702
|
loader: "postcss-loader",
|
|
@@ -2762,33 +2763,38 @@ import { join as join8 } from "path";
|
|
|
2762
2763
|
var i18nPlugin = createPlugin((options = {}) => ({
|
|
2763
2764
|
name: "@4399ywkf/plugin-i18n",
|
|
2764
2765
|
version: "1.0.0",
|
|
2765
|
-
description: "\u56FD\u9645\u5316 (i18next) \u63D2\u4EF6",
|
|
2766
|
+
description: "\u56FD\u9645\u5316 (i18next) \u63D2\u4EF6 \u2014 TS-first \u5DE5\u4F5C\u6D41",
|
|
2766
2767
|
setup(context) {
|
|
2767
2768
|
const {
|
|
2768
2769
|
defaultLocale = "zh-CN",
|
|
2769
2770
|
locales = ["zh-CN", "en-US"],
|
|
2770
2771
|
localesDir = "locales",
|
|
2772
|
+
sourceDir = "src/locales/default",
|
|
2771
2773
|
defaultNS = ["common"],
|
|
2772
2774
|
autoScaffold = true
|
|
2773
2775
|
} = options;
|
|
2774
|
-
const { cwd, logger } = context;
|
|
2776
|
+
const { cwd, logger, isDev } = context;
|
|
2775
2777
|
if (autoScaffold) {
|
|
2776
|
-
|
|
2778
|
+
scaffoldSourceFiles(cwd, sourceDir, defaultNS, logger);
|
|
2779
|
+
scaffoldResourcesFile(cwd, sourceDir, defaultNS, locales, defaultLocale, logger);
|
|
2780
|
+
scaffoldConvertScript(cwd, sourceDir, localesDir, defaultLocale, logger);
|
|
2781
|
+
scaffoldI18nRc(cwd, localesDir, defaultLocale, locales, logger);
|
|
2782
|
+
scaffoldLocaleJsonDirs(cwd, localesDir, locales, defaultLocale, defaultNS, logger);
|
|
2777
2783
|
}
|
|
2778
2784
|
const hooks = {
|
|
2779
2785
|
modifyRspackConfig(rspackConfig) {
|
|
2780
2786
|
const aliases = rspackConfig.resolve?.alias || {};
|
|
2781
2787
|
if (!aliases["@locales"]) {
|
|
2782
2788
|
aliases["@locales"] = join8(cwd, localesDir);
|
|
2783
|
-
rspackConfig.resolve = { ...rspackConfig.resolve, alias: aliases };
|
|
2784
2789
|
}
|
|
2790
|
+
rspackConfig.resolve = { ...rspackConfig.resolve, alias: aliases };
|
|
2785
2791
|
return rspackConfig;
|
|
2786
2792
|
},
|
|
2787
2793
|
generateFiles(ctx) {
|
|
2788
2794
|
return [
|
|
2789
2795
|
{
|
|
2790
2796
|
path: "i18n.ts",
|
|
2791
|
-
content: generateI18nCode(defaultLocale, locales, localesDir, defaultNS)
|
|
2797
|
+
content: generateI18nCode({ defaultLocale, locales, localesDir, sourceDir, defaultNS, isDev })
|
|
2792
2798
|
}
|
|
2793
2799
|
];
|
|
2794
2800
|
},
|
|
@@ -2798,7 +2804,6 @@ var i18nPlugin = createPlugin((options = {}) => ({
|
|
|
2798
2804
|
`import { initI18n } from "./i18n";`
|
|
2799
2805
|
],
|
|
2800
2806
|
topLevel: [
|
|
2801
|
-
`// \u521D\u59CB\u5316 i18n\uFF08\u5728\u5E94\u7528\u542F\u52A8\u524D\uFF09`,
|
|
2802
2807
|
`await initI18n();`
|
|
2803
2808
|
]
|
|
2804
2809
|
};
|
|
@@ -2807,38 +2812,43 @@ var i18nPlugin = createPlugin((options = {}) => ({
|
|
|
2807
2812
|
return hooks;
|
|
2808
2813
|
}
|
|
2809
2814
|
}));
|
|
2810
|
-
function generateI18nCode(
|
|
2815
|
+
function generateI18nCode(opts) {
|
|
2816
|
+
const { defaultLocale, locales, defaultNS, sourceDir } = opts;
|
|
2817
|
+
const defaultDirAlias = sourceDir.replace(/^src\//, "");
|
|
2818
|
+
const parentDirAlias = defaultDirAlias.replace(/\/[^/]+$/, "");
|
|
2811
2819
|
return `// \u6B64\u6587\u4EF6\u7531 @4399ywkf/plugin-i18n \u81EA\u52A8\u751F\u6210
|
|
2812
2820
|
import i18n from "i18next";
|
|
2813
2821
|
import LanguageDetector from "i18next-browser-languagedetector";
|
|
2814
2822
|
import resourcesToBackend from "i18next-resources-to-backend";
|
|
2815
2823
|
import { initReactI18next } from "react-i18next";
|
|
2824
|
+
import { normalizeLocale, SUPPORTED_LOCALES, DEFAULT_LOCALE } from "@/${parentDirAlias}/resources";
|
|
2816
2825
|
|
|
2817
|
-
export
|
|
2826
|
+
export { DEFAULT_LOCALE, SUPPORTED_LOCALES, normalizeLocale };
|
|
2827
|
+
export type { SupportedLocale, NS } from "@/${parentDirAlias}/resources";
|
|
2818
2828
|
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
export type SupportedLocale = typeof SUPPORTED_LOCALES[number];
|
|
2829
|
+
const isDev = process.env.NODE_ENV === "development";
|
|
2822
2830
|
|
|
2823
2831
|
const instance = i18n
|
|
2824
2832
|
.use(initReactI18next)
|
|
2825
2833
|
.use(LanguageDetector)
|
|
2826
2834
|
.use(
|
|
2827
2835
|
resourcesToBackend(async (lng: string, ns: string) => {
|
|
2828
|
-
|
|
2836
|
+
const normalizedLng = normalizeLocale(lng);
|
|
2837
|
+
|
|
2838
|
+
// \u5F00\u53D1\u6A21\u5F0F\u4E0B\uFF0C\u9ED8\u8BA4\u8BED\u8A00\u76F4\u63A5 import TS\uFF08\u5373\u65F6\u751F\u6548\uFF0C\u65E0\u9700\u5148\u751F\u6210 JSON\uFF09
|
|
2839
|
+
if (isDev && normalizedLng === "${defaultLocale}") {
|
|
2840
|
+
return import("@/${defaultDirAlias}/" + ns);
|
|
2841
|
+
}
|
|
2842
|
+
|
|
2843
|
+
// \u5176\u4ED6\u8BED\u8A00 / \u751F\u4EA7\u6A21\u5F0F\uFF1A\u61D2\u52A0\u8F7D JSON
|
|
2844
|
+
return import(
|
|
2845
|
+
/* webpackInclude: /\\.json$/ */
|
|
2846
|
+
/* webpackChunkName: "locales-[request]" */
|
|
2847
|
+
\`@locales/\${normalizedLng}/\${ns}.json\`
|
|
2848
|
+
);
|
|
2829
2849
|
})
|
|
2830
2850
|
);
|
|
2831
2851
|
|
|
2832
|
-
function normalizeLocale(locale?: string): string {
|
|
2833
|
-
if (!locale) return DEFAULT_LOCALE;
|
|
2834
|
-
for (const l of SUPPORTED_LOCALES) {
|
|
2835
|
-
if (l.startsWith(locale) || locale.startsWith(l.split("-")[0])) {
|
|
2836
|
-
return l;
|
|
2837
|
-
}
|
|
2838
|
-
}
|
|
2839
|
-
return DEFAULT_LOCALE;
|
|
2840
|
-
}
|
|
2841
|
-
|
|
2842
2852
|
let initialized = false;
|
|
2843
2853
|
|
|
2844
2854
|
export async function initI18n(lang?: string): Promise<typeof i18n> {
|
|
@@ -2859,19 +2869,191 @@ export { instance as i18n };
|
|
|
2859
2869
|
export default instance;
|
|
2860
2870
|
`;
|
|
2861
2871
|
}
|
|
2862
|
-
function
|
|
2872
|
+
function scaffoldSourceFiles(cwd, sourceDir, namespaces, logger) {
|
|
2873
|
+
const dir = join8(cwd, sourceDir);
|
|
2874
|
+
if (!existsSync8(dir)) {
|
|
2875
|
+
mkdirSync3(dir, { recursive: true });
|
|
2876
|
+
}
|
|
2877
|
+
for (const ns of namespaces) {
|
|
2878
|
+
const filePath = join8(dir, `${ns}.ts`);
|
|
2879
|
+
if (!existsSync8(filePath)) {
|
|
2880
|
+
writeFileSync4(filePath, buildDefaultNsFile(ns), "utf-8");
|
|
2881
|
+
logger.info(`\u5DF2\u751F\u6210\u7FFB\u8BD1\u6E90\u6587\u4EF6: ${sourceDir}/${ns}.ts`);
|
|
2882
|
+
}
|
|
2883
|
+
}
|
|
2884
|
+
const indexPath = join8(dir, "index.ts");
|
|
2885
|
+
if (!existsSync8(indexPath)) {
|
|
2886
|
+
const imports = namespaces.map((ns) => `import ${ns} from "./${ns}";`).join("\n");
|
|
2887
|
+
const entries = namespaces.join(",\n ");
|
|
2888
|
+
const content = `${imports}
|
|
2889
|
+
|
|
2890
|
+
const resources = {
|
|
2891
|
+
${entries},
|
|
2892
|
+
} as const;
|
|
2893
|
+
|
|
2894
|
+
export default resources;
|
|
2895
|
+
`;
|
|
2896
|
+
writeFileSync4(indexPath, content, "utf-8");
|
|
2897
|
+
logger.info(`\u5DF2\u751F\u6210\u7FFB\u8BD1\u7D22\u5F15: ${sourceDir}/index.ts`);
|
|
2898
|
+
}
|
|
2899
|
+
}
|
|
2900
|
+
function buildDefaultNsFile(ns) {
|
|
2901
|
+
if (ns === "common") {
|
|
2902
|
+
return `export default {
|
|
2903
|
+
welcome: "\u6B22\u8FCE\u4F7F\u7528",
|
|
2904
|
+
loading: "\u52A0\u8F7D\u4E2D...",
|
|
2905
|
+
confirm: "\u786E\u5B9A",
|
|
2906
|
+
cancel: "\u53D6\u6D88",
|
|
2907
|
+
save: "\u4FDD\u5B58",
|
|
2908
|
+
delete: "\u5220\u9664",
|
|
2909
|
+
edit: "\u7F16\u8F91",
|
|
2910
|
+
back: "\u8FD4\u56DE",
|
|
2911
|
+
} as const;
|
|
2912
|
+
`;
|
|
2913
|
+
}
|
|
2914
|
+
return `export default {
|
|
2915
|
+
title: "${ns}",
|
|
2916
|
+
} as const;
|
|
2917
|
+
`;
|
|
2918
|
+
}
|
|
2919
|
+
function scaffoldResourcesFile(cwd, sourceDir, namespaces, locales, defaultLocale, logger) {
|
|
2920
|
+
const parentDir = join8(cwd, sourceDir, "..");
|
|
2921
|
+
const filePath = join8(parentDir, "resources.ts");
|
|
2922
|
+
if (existsSync8(filePath)) return;
|
|
2923
|
+
const content = `import resources from "./default";
|
|
2924
|
+
|
|
2925
|
+
export const DEFAULT_LOCALE = "${defaultLocale}";
|
|
2926
|
+
|
|
2927
|
+
export const SUPPORTED_LOCALES = ${JSON.stringify(locales)} as const;
|
|
2928
|
+
|
|
2929
|
+
export type SupportedLocale = (typeof SUPPORTED_LOCALES)[number];
|
|
2930
|
+
|
|
2931
|
+
export type DefaultResources = typeof resources;
|
|
2932
|
+
|
|
2933
|
+
export type NS = keyof DefaultResources;
|
|
2934
|
+
|
|
2935
|
+
export const normalizeLocale = (locale?: string): SupportedLocale => {
|
|
2936
|
+
if (!locale) return DEFAULT_LOCALE as SupportedLocale;
|
|
2937
|
+
|
|
2938
|
+
for (const l of SUPPORTED_LOCALES) {
|
|
2939
|
+
if (l.startsWith(locale) || locale.startsWith(l.split("-")[0])) {
|
|
2940
|
+
return l;
|
|
2941
|
+
}
|
|
2942
|
+
}
|
|
2943
|
+
|
|
2944
|
+
return DEFAULT_LOCALE as SupportedLocale;
|
|
2945
|
+
};
|
|
2946
|
+
|
|
2947
|
+
export const localeOptions = ${JSON.stringify(
|
|
2948
|
+
locales.map((l) => ({ value: l, label: getLocaleLabel(l) })),
|
|
2949
|
+
null,
|
|
2950
|
+
2
|
|
2951
|
+
)} as const;
|
|
2952
|
+
`;
|
|
2953
|
+
writeFileSync4(filePath, content, "utf-8");
|
|
2954
|
+
logger.info(`\u5DF2\u751F\u6210\u7C7B\u578B\u6587\u4EF6: ${sourceDir}/../resources.ts`);
|
|
2955
|
+
}
|
|
2956
|
+
function getLocaleLabel(locale) {
|
|
2957
|
+
const map = {
|
|
2958
|
+
"zh-CN": "\u7B80\u4F53\u4E2D\u6587",
|
|
2959
|
+
"zh-TW": "\u7E41\u9AD4\u4E2D\u6587",
|
|
2960
|
+
"en-US": "English",
|
|
2961
|
+
"ja-JP": "\u65E5\u672C\u8A9E",
|
|
2962
|
+
"ko-KR": "\uD55C\uAD6D\uC5B4",
|
|
2963
|
+
"de-DE": "Deutsch",
|
|
2964
|
+
"fr-FR": "Fran\xE7ais",
|
|
2965
|
+
"es-ES": "Espa\xF1ol",
|
|
2966
|
+
"pt-BR": "Portugu\xEAs",
|
|
2967
|
+
"ru-RU": "\u0420\u0443\u0441\u0441\u043A\u0438\u0439",
|
|
2968
|
+
"it-IT": "Italiano",
|
|
2969
|
+
"vi-VN": "Ti\u1EBFng Vi\u1EC7t",
|
|
2970
|
+
"ar": "\u0627\u0644\u0639\u0631\u0628\u064A\u0629"
|
|
2971
|
+
};
|
|
2972
|
+
return map[locale] || locale;
|
|
2973
|
+
}
|
|
2974
|
+
function scaffoldConvertScript(cwd, sourceDir, localesDir, defaultLocale, logger) {
|
|
2975
|
+
const scriptsDir = join8(cwd, "scripts");
|
|
2976
|
+
const scriptPath = join8(scriptsDir, "i18n-gen.js");
|
|
2977
|
+
if (existsSync8(scriptPath)) return;
|
|
2978
|
+
if (!existsSync8(scriptsDir)) {
|
|
2979
|
+
mkdirSync3(scriptsDir, { recursive: true });
|
|
2980
|
+
}
|
|
2981
|
+
const content = `const fs = require("fs");
|
|
2982
|
+
const path = require("path");
|
|
2983
|
+
|
|
2984
|
+
const sourceDir = path.join(__dirname, "../${sourceDir}");
|
|
2985
|
+
const targetDir = path.join(__dirname, "../${localesDir}/${defaultLocale}");
|
|
2986
|
+
|
|
2987
|
+
const files = fs
|
|
2988
|
+
.readdirSync(sourceDir)
|
|
2989
|
+
.filter((file) => file.endsWith(".ts") && file !== "index.ts")
|
|
2990
|
+
.map((file) => path.basename(file, ".ts"));
|
|
2991
|
+
|
|
2992
|
+
require("ts-node/register");
|
|
2993
|
+
|
|
2994
|
+
if (!fs.existsSync(targetDir)) {
|
|
2995
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
2996
|
+
}
|
|
2997
|
+
|
|
2998
|
+
console.log("\u5F00\u59CB\u8F6C\u6362 TypeScript \u6587\u4EF6\u5230 JSON...\\n");
|
|
2999
|
+
|
|
3000
|
+
files.forEach((fileName) => {
|
|
3001
|
+
try {
|
|
3002
|
+
const modulePath = path.join(sourceDir, \`\${fileName}.ts\`);
|
|
3003
|
+
delete require.cache[require.resolve(modulePath)];
|
|
3004
|
+
const moduleContent = require(modulePath).default;
|
|
3005
|
+
const jsonContent = JSON.stringify(moduleContent, null, 2);
|
|
3006
|
+
const targetPath = path.join(targetDir, \`\${fileName}.json\`);
|
|
3007
|
+
fs.writeFileSync(targetPath, jsonContent, "utf8");
|
|
3008
|
+
console.log(\` \${fileName}.ts \u2192 \${fileName}.json\`);
|
|
3009
|
+
} catch (error) {
|
|
3010
|
+
console.error(\` \u8F6C\u6362 \${fileName}.ts \u5931\u8D25:\`, error.message);
|
|
3011
|
+
}
|
|
3012
|
+
});
|
|
3013
|
+
|
|
3014
|
+
console.log("\\n\u8F6C\u6362\u5B8C\u6210\uFF01");
|
|
3015
|
+
`;
|
|
3016
|
+
writeFileSync4(scriptPath, content, "utf-8");
|
|
3017
|
+
logger.info("\u5DF2\u751F\u6210\u8F6C\u6362\u811A\u672C: scripts/i18n-gen.js");
|
|
3018
|
+
}
|
|
3019
|
+
function scaffoldI18nRc(cwd, localesDir, defaultLocale, locales, logger) {
|
|
3020
|
+
const filePath = join8(cwd, ".i18nrc.js");
|
|
3021
|
+
if (existsSync8(filePath)) return;
|
|
3022
|
+
const outputLocales = locales.filter((l) => l !== defaultLocale).map((l) => `"${l}"`).join(", ");
|
|
3023
|
+
const content = `const { defineConfig } = require("@lobehub/i18n-cli");
|
|
3024
|
+
|
|
3025
|
+
module.exports = defineConfig({
|
|
3026
|
+
entry: "${localesDir}/${defaultLocale}",
|
|
3027
|
+
entryLocale: "${defaultLocale}",
|
|
3028
|
+
output: "${localesDir}",
|
|
3029
|
+
outputLocales: [${outputLocales}],
|
|
3030
|
+
});
|
|
3031
|
+
`;
|
|
3032
|
+
writeFileSync4(filePath, content, "utf-8");
|
|
3033
|
+
logger.info("\u5DF2\u751F\u6210\u7FFB\u8BD1\u914D\u7F6E: .i18nrc.js\uFF08@lobehub/i18n-cli\uFF09");
|
|
3034
|
+
}
|
|
3035
|
+
function scaffoldLocaleJsonDirs(cwd, localesDir, locales, defaultLocale, namespaces, logger) {
|
|
2863
3036
|
const baseDir = join8(cwd, localesDir);
|
|
2864
3037
|
for (const locale of locales) {
|
|
2865
3038
|
const localeDir = join8(baseDir, locale);
|
|
2866
3039
|
if (!existsSync8(localeDir)) {
|
|
2867
3040
|
mkdirSync3(localeDir, { recursive: true });
|
|
2868
3041
|
}
|
|
3042
|
+
if (locale === defaultLocale) continue;
|
|
2869
3043
|
for (const ns of namespaces) {
|
|
2870
3044
|
const filePath = join8(localeDir, `${ns}.json`);
|
|
2871
3045
|
if (!existsSync8(filePath)) {
|
|
2872
|
-
const
|
|
2873
|
-
|
|
2874
|
-
|
|
3046
|
+
const placeholder = ns === "common" ? JSON.stringify({
|
|
3047
|
+
welcome: "Welcome",
|
|
3048
|
+
loading: "Loading...",
|
|
3049
|
+
confirm: "OK",
|
|
3050
|
+
cancel: "Cancel",
|
|
3051
|
+
save: "Save",
|
|
3052
|
+
delete: "Delete",
|
|
3053
|
+
edit: "Edit",
|
|
3054
|
+
back: "Back"
|
|
3055
|
+
}, null, 2) : JSON.stringify({ title: ns }, null, 2);
|
|
3056
|
+
writeFileSync4(filePath, placeholder + "\n", "utf-8");
|
|
2875
3057
|
logger.info(`\u5DF2\u751F\u6210\u7FFB\u8BD1\u6587\u4EF6: ${localesDir}/${locale}/${ns}.json`);
|
|
2876
3058
|
}
|
|
2877
3059
|
}
|
|
@@ -2879,22 +3061,37 @@ function scaffoldLocaleFiles(cwd, localesDir, locales, namespaces, logger) {
|
|
|
2879
3061
|
}
|
|
2880
3062
|
|
|
2881
3063
|
// src/plugin/builtin/theme.ts
|
|
3064
|
+
import { join as join9 } from "path";
|
|
2882
3065
|
var themePlugin = createPlugin((options = {}) => ({
|
|
2883
3066
|
name: "@4399ywkf/plugin-theme",
|
|
2884
|
-
version: "
|
|
2885
|
-
description: "antd-style \u4E3B\u9898\u7CFB\u7EDF\u63D2\u4EF6",
|
|
3067
|
+
version: "2.0.0",
|
|
3068
|
+
description: "antd-style \u54CD\u5E94\u5F0F\u4E3B\u9898\u7CFB\u7EDF\u63D2\u4EF6",
|
|
2886
3069
|
setup(context) {
|
|
2887
3070
|
const {
|
|
2888
3071
|
darkMode = true,
|
|
2889
|
-
defaultAppearance = "
|
|
2890
|
-
primaryColor = "
|
|
3072
|
+
defaultAppearance = "dark",
|
|
3073
|
+
primaryColor = "#1677ff",
|
|
3074
|
+
neutralColor,
|
|
2891
3075
|
prefixCls = "ant",
|
|
2892
3076
|
cssVar = true,
|
|
2893
|
-
globalReset = true
|
|
3077
|
+
globalReset = true,
|
|
3078
|
+
externalTheme = false
|
|
2894
3079
|
} = options;
|
|
2895
3080
|
const { logger } = context;
|
|
2896
|
-
logger.info(`\u4E3B\u9898\u6A21\u5F0F: ${defaultAppearance}, \u4E3B\u8272: ${primaryColor}`);
|
|
3081
|
+
logger.info(`\u4E3B\u9898\u6A21\u5F0F: ${defaultAppearance}, \u4E3B\u8272: ${primaryColor}, \u54CD\u5E94\u5F0F: \u2713`);
|
|
2897
3082
|
const hooks = {
|
|
3083
|
+
modifyRspackConfig(config, ctx) {
|
|
3084
|
+
const themePath = join9(ctx.cwd, ".ywkf", "theme.tsx");
|
|
3085
|
+
const currentAlias = config.resolve?.alias ?? {};
|
|
3086
|
+
config.resolve = {
|
|
3087
|
+
...config.resolve,
|
|
3088
|
+
alias: {
|
|
3089
|
+
...currentAlias,
|
|
3090
|
+
"@ywkf/theme": themePath
|
|
3091
|
+
}
|
|
3092
|
+
};
|
|
3093
|
+
return config;
|
|
3094
|
+
},
|
|
2898
3095
|
generateFiles(ctx) {
|
|
2899
3096
|
return [
|
|
2900
3097
|
{
|
|
@@ -2903,9 +3100,11 @@ var themePlugin = createPlugin((options = {}) => ({
|
|
|
2903
3100
|
darkMode,
|
|
2904
3101
|
defaultAppearance,
|
|
2905
3102
|
primaryColor,
|
|
3103
|
+
neutralColor,
|
|
2906
3104
|
prefixCls,
|
|
2907
3105
|
cssVar,
|
|
2908
|
-
globalReset
|
|
3106
|
+
globalReset,
|
|
3107
|
+
externalTheme
|
|
2909
3108
|
})
|
|
2910
3109
|
}
|
|
2911
3110
|
];
|
|
@@ -2916,61 +3115,168 @@ var themePlugin = createPlugin((options = {}) => ({
|
|
|
2916
3115
|
`import { ThemeWrapper } from "./theme";`
|
|
2917
3116
|
]
|
|
2918
3117
|
};
|
|
3118
|
+
},
|
|
3119
|
+
modifyBootstrapCode(code) {
|
|
3120
|
+
const providerEntry = ` {
|
|
3121
|
+
component: ThemeWrapper as React.ComponentType<{ children: React.ReactNode }>,
|
|
3122
|
+
props: {},
|
|
3123
|
+
order: 10,
|
|
3124
|
+
}`;
|
|
3125
|
+
if (code.includes("providers: []")) {
|
|
3126
|
+
code = code.replace(
|
|
3127
|
+
"providers: []",
|
|
3128
|
+
`providers: [
|
|
3129
|
+
${providerEntry},
|
|
3130
|
+
]`
|
|
3131
|
+
);
|
|
3132
|
+
} else if (code.includes("providers: [")) {
|
|
3133
|
+
code = code.replace(
|
|
3134
|
+
"providers: [",
|
|
3135
|
+
`providers: [
|
|
3136
|
+
${providerEntry},`
|
|
3137
|
+
);
|
|
3138
|
+
}
|
|
3139
|
+
if (!code.includes("import React")) {
|
|
3140
|
+
code = code.replace(
|
|
3141
|
+
`import { bootstrap`,
|
|
3142
|
+
`import React from "react";
|
|
3143
|
+
import { bootstrap`
|
|
3144
|
+
);
|
|
3145
|
+
}
|
|
3146
|
+
return code;
|
|
2919
3147
|
}
|
|
2920
|
-
// Provider 由生成的 theme.tsx 文件在用户层使用
|
|
2921
|
-
// 用户可以在 src/app.config.ts 中通过 providers 引入 ThemeWrapper
|
|
2922
3148
|
};
|
|
2923
3149
|
return hooks;
|
|
2924
3150
|
}
|
|
2925
3151
|
}));
|
|
2926
3152
|
function generateThemeProvider(opts) {
|
|
2927
|
-
const {
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
3153
|
+
const {
|
|
3154
|
+
darkMode,
|
|
3155
|
+
defaultAppearance,
|
|
3156
|
+
primaryColor,
|
|
3157
|
+
neutralColor,
|
|
3158
|
+
prefixCls,
|
|
3159
|
+
cssVar,
|
|
3160
|
+
globalReset,
|
|
3161
|
+
externalTheme
|
|
3162
|
+
} = opts;
|
|
3163
|
+
const sections = [];
|
|
3164
|
+
sections.push(`// \u6B64\u6587\u4EF6\u7531 @4399ywkf/plugin-theme \u81EA\u52A8\u751F\u6210\uFF0C\u8BF7\u52FF\u624B\u52A8\u4FEE\u6539`);
|
|
3165
|
+
sections.push(buildImports({ globalReset, cssVar }));
|
|
3166
|
+
sections.push(TYPES_CODE);
|
|
3167
|
+
sections.push(buildStoreCode({ defaultAppearance, primaryColor, neutralColor }));
|
|
3168
|
+
sections.push(HOOKS_CODE);
|
|
3169
|
+
if (globalReset) sections.push(GLOBAL_RESET_CODE);
|
|
3170
|
+
if (cssVar) sections.push(CSS_VAR_SYNC_CODE);
|
|
3171
|
+
if (darkMode) sections.push(APPEARANCE_SYNC_CODE);
|
|
3172
|
+
if (externalTheme) sections.push(EXTERNAL_THEME_CODE);
|
|
3173
|
+
sections.push(buildWrapperCode({ darkMode, cssVar, globalReset, externalTheme, prefixCls }));
|
|
3174
|
+
return sections.join("\n");
|
|
3175
|
+
}
|
|
3176
|
+
function buildImports(opts) {
|
|
3177
|
+
const reactImports = [
|
|
3178
|
+
"useCallback",
|
|
3179
|
+
"useEffect",
|
|
3180
|
+
...opts.cssVar ? ["useLayoutEffect", "useRef"] : [],
|
|
3181
|
+
"type ReactNode"
|
|
3182
|
+
];
|
|
3183
|
+
const antdStyleImports = [
|
|
3184
|
+
"ThemeProvider as AntdThemeProvider",
|
|
3185
|
+
"type GetAntdTheme",
|
|
3186
|
+
...opts.globalReset ? ["createGlobalStyle", "css"] : []
|
|
3187
|
+
];
|
|
3188
|
+
return `
|
|
3189
|
+
import React, { ${reactImports.join(", ")} } from "react";
|
|
3190
|
+
import { ${antdStyleImports.join(", ")} } from "antd-style";
|
|
3191
|
+
import { createWithEqualityFn } from "zustand/traditional";
|
|
3192
|
+
import { shallow } from "zustand/shallow";`;
|
|
3193
|
+
}
|
|
3194
|
+
var TYPES_CODE = `
|
|
3195
|
+
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 Types \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
2931
3196
|
|
|
2932
|
-
|
|
3197
|
+
export type ThemeAppearance = "light" | "dark" | "auto";
|
|
2933
3198
|
|
|
2934
|
-
|
|
3199
|
+
export interface ThemeState {
|
|
3200
|
+
appearance: ThemeAppearance;
|
|
3201
|
+
primaryColor: string;
|
|
3202
|
+
neutralColor?: string;
|
|
3203
|
+
}
|
|
2935
3204
|
|
|
2936
|
-
interface
|
|
2937
|
-
|
|
3205
|
+
export interface ThemeActions {
|
|
3206
|
+
setAppearance: (mode: ThemeAppearance) => void;
|
|
3207
|
+
setPrimaryColor: (color: string) => void;
|
|
3208
|
+
setNeutralColor: (color: string) => void;
|
|
3209
|
+
/** \u6279\u91CF\u66F4\u65B0\u4E3B\u9898\u72B6\u6001 */
|
|
3210
|
+
setTheme: (partial: Partial<ThemeState>) => void;
|
|
2938
3211
|
}
|
|
2939
3212
|
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
3213
|
+
export type ThemeStore = ThemeState & ThemeActions;`;
|
|
3214
|
+
function buildStoreCode(opts) {
|
|
3215
|
+
const neutralLine = opts.neutralColor ? `
|
|
3216
|
+
neutralColor: "${opts.neutralColor}",` : "";
|
|
3217
|
+
return `
|
|
3218
|
+
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 Theme Store \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
2946
3219
|
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
theme={{
|
|
2952
|
-
cssVar: ${cssVar},
|
|
2953
|
-
token: {
|
|
2954
|
-
colorPrimary: "${primaryColor}",
|
|
2955
|
-
},
|
|
2956
|
-
}}
|
|
2957
|
-
themeMode={DEFAULT_APPEARANCE}
|
|
2958
|
-
>
|
|
2959
|
-
${globalReset ? "<GlobalReset />" : ""}
|
|
2960
|
-
{children}
|
|
2961
|
-
</ThemeProvider>
|
|
2962
|
-
);
|
|
2963
|
-
}
|
|
3220
|
+
const DEFAULT_THEME: ThemeState = {
|
|
3221
|
+
appearance: "${opts.defaultAppearance}",
|
|
3222
|
+
primaryColor: "${opts.primaryColor}",${neutralLine}
|
|
3223
|
+
};
|
|
2964
3224
|
|
|
2965
|
-
export
|
|
2966
|
-
|
|
3225
|
+
export const useThemeStore = createWithEqualityFn<ThemeStore>()(
|
|
3226
|
+
(set) => ({
|
|
3227
|
+
...DEFAULT_THEME,
|
|
3228
|
+
setAppearance: (mode) => set({ appearance: mode }),
|
|
3229
|
+
setPrimaryColor: (color) => set({ primaryColor: color }),
|
|
3230
|
+
setNeutralColor: (color) => set({ neutralColor: color }),
|
|
3231
|
+
setTheme: (partial) => set(partial),
|
|
3232
|
+
}),
|
|
3233
|
+
shallow,
|
|
3234
|
+
);`;
|
|
2967
3235
|
}
|
|
3236
|
+
var HOOKS_CODE = `
|
|
3237
|
+
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 Convenience Hooks \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
3238
|
+
|
|
3239
|
+
/** \u83B7\u53D6\u5F53\u524D\u4E3B\u9898\u72B6\u6001\uFF08appearance + primaryColor + neutralColor\uFF09 */
|
|
3240
|
+
export const useTheme = () =>
|
|
3241
|
+
useThemeStore(
|
|
3242
|
+
(s) => ({
|
|
3243
|
+
appearance: s.appearance,
|
|
3244
|
+
primaryColor: s.primaryColor,
|
|
3245
|
+
neutralColor: s.neutralColor,
|
|
3246
|
+
}),
|
|
3247
|
+
shallow,
|
|
3248
|
+
);
|
|
3249
|
+
|
|
3250
|
+
/** \u4EC5\u8BA2\u9605 appearance */
|
|
3251
|
+
export const useAppearance = () => useThemeStore((s) => s.appearance);
|
|
3252
|
+
|
|
3253
|
+
/** \u4EC5\u8BA2\u9605 primaryColor */
|
|
3254
|
+
export const usePrimaryColor = () => useThemeStore((s) => s.primaryColor);`;
|
|
2968
3255
|
var GLOBAL_RESET_CODE = `
|
|
2969
|
-
|
|
3256
|
+
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 Global Style \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
3257
|
+
// \u53C2\u8003 lobe-ui GlobalStyle\uFF1A\u4F7F\u7528 theme tokens \u5B9E\u73B0\u54CD\u5E94\u5F0F\u5168\u5C40\u6837\u5F0F
|
|
3258
|
+
|
|
3259
|
+
const GlobalReset = createGlobalStyle(({ theme }) => css\`
|
|
3260
|
+
:root {
|
|
3261
|
+
--font-settings: "cv01", "tnum", "kern";
|
|
3262
|
+
--font-variations: "opsz" auto, tabular-nums;
|
|
3263
|
+
}
|
|
3264
|
+
|
|
2970
3265
|
*,
|
|
2971
3266
|
*::before,
|
|
2972
3267
|
*::after {
|
|
2973
3268
|
box-sizing: border-box;
|
|
3269
|
+
vertical-align: baseline;
|
|
3270
|
+
}
|
|
3271
|
+
|
|
3272
|
+
* {
|
|
3273
|
+
scrollbar-color: \${theme.colorFill} transparent;
|
|
3274
|
+
scrollbar-width: thin;
|
|
3275
|
+
}
|
|
3276
|
+
|
|
3277
|
+
html {
|
|
3278
|
+
overscroll-behavior: none;
|
|
3279
|
+
color-scheme: \${theme.isDarkMode ? "dark" : "light"};
|
|
2974
3280
|
}
|
|
2975
3281
|
|
|
2976
3282
|
html, body, #root, #app {
|
|
@@ -2980,34 +3286,191 @@ const GlobalReset = createGlobalStyle\`
|
|
|
2980
3286
|
}
|
|
2981
3287
|
|
|
2982
3288
|
body {
|
|
2983
|
-
|
|
2984
|
-
|
|
3289
|
+
overflow: hidden auto;
|
|
3290
|
+
min-height: 100vh;
|
|
3291
|
+
font-family: \${theme.fontFamily};
|
|
3292
|
+
font-size: \${theme.fontSize}px;
|
|
3293
|
+
font-feature-settings: var(--font-settings);
|
|
3294
|
+
font-variation-settings: var(--font-variations);
|
|
3295
|
+
line-height: 1;
|
|
3296
|
+
color: \${theme.colorTextBase};
|
|
3297
|
+
text-size-adjust: none;
|
|
3298
|
+
text-rendering: optimizelegibility;
|
|
3299
|
+
word-wrap: break-word;
|
|
3300
|
+
background-color: \${theme.colorBgLayout};
|
|
2985
3301
|
-webkit-font-smoothing: antialiased;
|
|
2986
3302
|
-moz-osx-font-smoothing: grayscale;
|
|
3303
|
+
-webkit-overflow-scrolling: touch;
|
|
3304
|
+
-webkit-tap-highlight-color: transparent;
|
|
2987
3305
|
}
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
3306
|
+
|
|
3307
|
+
code {
|
|
3308
|
+
font-family: \${theme.fontFamilyCode} !important;
|
|
3309
|
+
}
|
|
3310
|
+
|
|
3311
|
+
::selection {
|
|
3312
|
+
color: #000;
|
|
3313
|
+
-webkit-text-fill-color: unset !important;
|
|
3314
|
+
}
|
|
3315
|
+
\`);`;
|
|
3316
|
+
var CSS_VAR_SYNC_CODE = `
|
|
3317
|
+
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 CSS Variable Sync \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
3318
|
+
// \u5C06 antd-style \u6CE8\u5165\u7684 css-var-* class \u540C\u6B65\u5230 <html>\uFF0C
|
|
3319
|
+
// \u4F7F\u5168\u5C40 CSS / Tailwind \u4E5F\u80FD\u6D88\u8D39 antd CSS \u53D8\u91CF
|
|
3320
|
+
|
|
3321
|
+
const CSS_VAR_PREFIX = "css-var-";
|
|
3322
|
+
|
|
3323
|
+
function useCssVarSync(ref: React.RefObject<HTMLDivElement | null>) {
|
|
3324
|
+
useLayoutEffect(() => {
|
|
3325
|
+
const node = ref.current;
|
|
3326
|
+
if (!node) return;
|
|
3327
|
+
|
|
3328
|
+
const htmlEl = document.documentElement;
|
|
3329
|
+
let currentClasses: string[] = [];
|
|
3330
|
+
|
|
3331
|
+
const sync = () => {
|
|
3332
|
+
for (const cls of currentClasses) htmlEl.classList.remove(cls);
|
|
3333
|
+
|
|
3334
|
+
const next: string[] = [];
|
|
3335
|
+
let el: HTMLElement | null = node;
|
|
3336
|
+
while (el && el !== htmlEl) {
|
|
3337
|
+
for (const cls of el.classList) {
|
|
3338
|
+
if (cls.startsWith(CSS_VAR_PREFIX)) next.push(cls);
|
|
3339
|
+
}
|
|
3340
|
+
el = el.parentElement;
|
|
3341
|
+
}
|
|
3342
|
+
|
|
3343
|
+
for (const cls of next) htmlEl.classList.add(cls);
|
|
3344
|
+
currentClasses = next;
|
|
3345
|
+
};
|
|
3346
|
+
|
|
3347
|
+
sync();
|
|
3348
|
+
|
|
3349
|
+
const observer = new MutationObserver(sync);
|
|
3350
|
+
let el: HTMLElement | null = node;
|
|
3351
|
+
while (el && el !== htmlEl) {
|
|
3352
|
+
observer.observe(el, { attributeFilter: ["class"] });
|
|
3353
|
+
el = el.parentElement;
|
|
3354
|
+
}
|
|
3355
|
+
|
|
3356
|
+
return () => {
|
|
3357
|
+
observer.disconnect();
|
|
3358
|
+
for (const cls of currentClasses) htmlEl.classList.remove(cls);
|
|
3359
|
+
};
|
|
3360
|
+
}, []);
|
|
3361
|
+
}`;
|
|
3362
|
+
var APPEARANCE_SYNC_CODE = `
|
|
3363
|
+
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 Appearance Sync \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
3364
|
+
|
|
3365
|
+
function useAppearanceSync(appearance: ThemeAppearance) {
|
|
2991
3366
|
useEffect(() => {
|
|
2992
|
-
if (
|
|
2993
|
-
document.documentElement.dataset.theme =
|
|
3367
|
+
if (appearance !== "auto") {
|
|
3368
|
+
document.documentElement.dataset.theme = appearance;
|
|
2994
3369
|
return;
|
|
2995
3370
|
}
|
|
2996
3371
|
|
|
2997
|
-
const
|
|
2998
|
-
document.documentElement.dataset.theme =
|
|
3372
|
+
const mq = window.matchMedia("(prefers-color-scheme: dark)");
|
|
3373
|
+
document.documentElement.dataset.theme = mq.matches ? "dark" : "light";
|
|
2999
3374
|
|
|
3000
3375
|
function handleChange(e: MediaQueryListEvent) {
|
|
3001
3376
|
document.documentElement.dataset.theme = e.matches ? "dark" : "light";
|
|
3002
3377
|
}
|
|
3003
3378
|
|
|
3004
|
-
|
|
3005
|
-
return () =>
|
|
3379
|
+
mq.addEventListener("change", handleChange);
|
|
3380
|
+
return () => mq.removeEventListener("change", handleChange);
|
|
3381
|
+
}, [appearance]);
|
|
3382
|
+
}`;
|
|
3383
|
+
var EXTERNAL_THEME_CODE = `
|
|
3384
|
+
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 External Theme Injection \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
3385
|
+
// \u5FAE\u524D\u7AEF\u573A\u666F\uFF1A\u76D1\u542C\u4E3B\u5E94\u7528\u4E0B\u53D1\u7684\u4E3B\u9898\u53D8\u66F4
|
|
3386
|
+
|
|
3387
|
+
function useExternalTheme() {
|
|
3388
|
+
useEffect(() => {
|
|
3389
|
+
const hostTheme = (window as any).__YWKF_THEME__;
|
|
3390
|
+
if (hostTheme && typeof hostTheme === "object") {
|
|
3391
|
+
useThemeStore.getState().setTheme(hostTheme);
|
|
3392
|
+
}
|
|
3393
|
+
|
|
3394
|
+
const handler = (e: Event) => {
|
|
3395
|
+
const detail = (e as CustomEvent<Partial<ThemeState>>).detail;
|
|
3396
|
+
if (detail) useThemeStore.getState().setTheme(detail);
|
|
3397
|
+
};
|
|
3398
|
+
|
|
3399
|
+
window.addEventListener("ywkf:theme-change", handler);
|
|
3400
|
+
return () => window.removeEventListener("ywkf:theme-change", handler);
|
|
3006
3401
|
}, []);
|
|
3402
|
+
}`;
|
|
3403
|
+
function buildWrapperCode(opts) {
|
|
3404
|
+
const { darkMode, cssVar, globalReset, externalTheme, prefixCls } = opts;
|
|
3405
|
+
const refLine = cssVar ? "\n const containerRef = useRef<HTMLDivElement>(null);" : "";
|
|
3406
|
+
const cssVarSyncLine = cssVar ? "\n useCssVarSync(containerRef);" : "";
|
|
3407
|
+
const appearanceSyncLine = darkMode ? "\n useAppearanceSync(appearance);" : "";
|
|
3408
|
+
const externalThemeLine = externalTheme ? "\n useExternalTheme();" : "";
|
|
3409
|
+
const childrenSlot = cssVar ? `<div ref={containerRef} style={{ display: "contents" }}>
|
|
3410
|
+
{children}
|
|
3411
|
+
</div>` : "{children}";
|
|
3412
|
+
return `
|
|
3413
|
+
// \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 ThemeWrapper \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
3414
|
+
|
|
3415
|
+
interface ThemeWrapperProps {
|
|
3416
|
+
children: ReactNode;
|
|
3417
|
+
}
|
|
3418
|
+
|
|
3419
|
+
/**
|
|
3420
|
+
* \u4E3B\u9898\u5305\u88F9\u7EC4\u4EF6
|
|
3421
|
+
*
|
|
3422
|
+
* \u7531 themePlugin \u81EA\u52A8\u6CE8\u5165\u5230\u5E94\u7528\u542F\u52A8\u5C42\uFF0C\u4ECE useThemeStore \u8BFB\u53D6\u4E3B\u9898\u72B6\u6001\u3002
|
|
3423
|
+
* \u4E1A\u52A1\u4FA7\u901A\u8FC7 useThemeStore / useTheme \u6D88\u8D39\u6216\u4FEE\u6539\u4E3B\u9898\u3002
|
|
3424
|
+
*/
|
|
3425
|
+
export function ThemeWrapper({ children }: ThemeWrapperProps) {${refLine}
|
|
3426
|
+
const { appearance, primaryColor } = useThemeStore(
|
|
3427
|
+
(s) => ({ appearance: s.appearance, primaryColor: s.primaryColor }),
|
|
3428
|
+
shallow,
|
|
3429
|
+
);${cssVarSyncLine}${appearanceSyncLine}${externalThemeLine}
|
|
3430
|
+
|
|
3431
|
+
const theme = useCallback<GetAntdTheme>(
|
|
3432
|
+
() => ({${cssVar ? "\n cssVar: true," : ""}
|
|
3433
|
+
token: {
|
|
3434
|
+
colorPrimary: primaryColor,
|
|
3435
|
+
// lobe-ui base tokens
|
|
3436
|
+
borderRadius: 8,
|
|
3437
|
+
borderRadiusLG: 12,
|
|
3438
|
+
borderRadiusSM: 6,
|
|
3439
|
+
borderRadiusXS: 4,
|
|
3440
|
+
controlHeight: 36,
|
|
3441
|
+
fontFamily: [
|
|
3442
|
+
'"HarmonyOS Sans", "Segoe UI", "SF Pro Display"',
|
|
3443
|
+
'-apple-system, BlinkMacSystemFont, Roboto, "Helvetica Neue", Arial',
|
|
3444
|
+
'"PingFang SC", "Hiragino Sans GB", "Microsoft Yahei", "Noto Sans SC", sans-serif',
|
|
3445
|
+
'"Segoe UI Emoji", "Noto Color Emoji"',
|
|
3446
|
+
].join(", "),
|
|
3447
|
+
fontFamilyCode: [
|
|
3448
|
+
'Hack, ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas',
|
|
3449
|
+
'"PingFang SC", "Noto Sans SC", monospace',
|
|
3450
|
+
].join(", "),
|
|
3451
|
+
},
|
|
3452
|
+
}),
|
|
3453
|
+
[primaryColor],
|
|
3454
|
+
);
|
|
3455
|
+
|
|
3456
|
+
return (
|
|
3457
|
+
<AntdThemeProvider
|
|
3458
|
+
prefixCls="${prefixCls}"
|
|
3459
|
+
themeMode={appearance}
|
|
3460
|
+
theme={theme}
|
|
3461
|
+
>
|
|
3462
|
+
${globalReset ? "<GlobalReset />" : ""}
|
|
3463
|
+
${childrenSlot}
|
|
3464
|
+
</AntdThemeProvider>
|
|
3465
|
+
);
|
|
3466
|
+
}
|
|
3467
|
+
|
|
3468
|
+
export default ThemeWrapper;
|
|
3007
3469
|
`;
|
|
3470
|
+
}
|
|
3008
3471
|
|
|
3009
3472
|
// src/plugin/builtin/mock.ts
|
|
3010
|
-
import { resolve as resolve2, join as
|
|
3473
|
+
import { resolve as resolve2, join as join10 } from "path";
|
|
3011
3474
|
import { existsSync as existsSync9, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
|
|
3012
3475
|
var mockPlugin = createPlugin((options = {}) => ({
|
|
3013
3476
|
name: "@4399ywkf/plugin-mock",
|
|
@@ -3062,7 +3525,7 @@ function scanMockFiles(dir) {
|
|
|
3062
3525
|
}
|
|
3063
3526
|
const entries = readdirSync2(dir);
|
|
3064
3527
|
for (const entry of entries) {
|
|
3065
|
-
const fullPath =
|
|
3528
|
+
const fullPath = join10(dir, entry);
|
|
3066
3529
|
const stat = statSync2(fullPath);
|
|
3067
3530
|
if (stat.isFile() && /\.(ts|js|mjs)$/.test(entry)) {
|
|
3068
3531
|
files.push(fullPath);
|
|
@@ -3231,7 +3694,8 @@ function buildRequestFile(opts) {
|
|
|
3231
3694
|
return `// \u6B64\u6587\u4EF6\u7531 @4399ywkf/plugin-react-query \u81EA\u52A8\u751F\u6210\uFF0C\u8BF7\u52FF\u624B\u52A8\u4FEE\u6539
|
|
3232
3695
|
// \u5982\u9700\u5B9A\u5236\u62E6\u622A\u5668\uFF0C\u8BF7\u7F16\u8F91 src/request.ts
|
|
3233
3696
|
import axios from "axios";
|
|
3234
|
-
import
|
|
3697
|
+
import qs from "qs";
|
|
3698
|
+
import type { AxiosInstance, AxiosRequestConfig, InternalAxiosRequestConfig, AxiosResponse, AxiosError } from "axios";
|
|
3235
3699
|
import type { RequestConfig, Result } from "@4399ywkf/core/runtime";
|
|
3236
3700
|
|
|
3237
3701
|
// ============ \u52A0\u8F7D\u7528\u6237\u914D\u7F6E ============
|
|
@@ -3245,9 +3709,38 @@ try {
|
|
|
3245
3709
|
// src/request.ts \u4E0D\u5B58\u5728\uFF0C\u4F7F\u7528\u9ED8\u8BA4\u914D\u7F6E
|
|
3246
3710
|
}
|
|
3247
3711
|
|
|
3712
|
+
// ============ \u53C2\u6570\u5E8F\u5217\u5316\uFF08GET \u8BF7\u6C42\u4E13\u7528\uFF09============
|
|
3713
|
+
|
|
3714
|
+
/**
|
|
3715
|
+
* GET \u8BF7\u6C42\u53C2\u6570\u5E8F\u5217\u5316\u89C4\u5219\uFF1A
|
|
3716
|
+
* - \u6570\u7EC4\uFF1Arepeat \u6A21\u5F0F\uFF08key=1&key=2\uFF09
|
|
3717
|
+
* - \u5BF9\u8C61\uFF1AJSON.stringify \u540E\u4F5C\u4E3A\u5B57\u7B26\u4E32\u4F20\u9012
|
|
3718
|
+
* - null / undefined\uFF1AskipNulls \u8DF3\u8FC7
|
|
3719
|
+
* - \u57FA\u672C\u7C7B\u578B\uFF1A\u539F\u6837\u4F20\u9012
|
|
3720
|
+
*/
|
|
3721
|
+
export function paramsSerializer(params: Record<string, any>): string {
|
|
3722
|
+
const normalized: Record<string, any> = {};
|
|
3723
|
+
|
|
3724
|
+
Object.keys(params).forEach((key) => {
|
|
3725
|
+
const value = params[key];
|
|
3726
|
+
|
|
3727
|
+
if (value === null || value === undefined) {
|
|
3728
|
+
normalized[key] = value;
|
|
3729
|
+
} else if (Array.isArray(value)) {
|
|
3730
|
+
normalized[key] = value;
|
|
3731
|
+
} else if (typeof value === "object") {
|
|
3732
|
+
normalized[key] = JSON.stringify(value);
|
|
3733
|
+
} else {
|
|
3734
|
+
normalized[key] = value;
|
|
3735
|
+
}
|
|
3736
|
+
});
|
|
3737
|
+
|
|
3738
|
+
return qs.stringify(normalized, { arrayFormat: "repeat", skipNulls: true });
|
|
3739
|
+
}
|
|
3740
|
+
|
|
3248
3741
|
// ============ \u521B\u5EFA Axios \u5B9E\u4F8B ============
|
|
3249
3742
|
|
|
3250
|
-
|
|
3743
|
+
const instance: AxiosInstance = axios.create({
|
|
3251
3744
|
baseURL: userConfig.baseURL ?? ("${baseURL}" || ""),
|
|
3252
3745
|
timeout: userConfig.timeout ?? ${timeout},
|
|
3253
3746
|
withCredentials: userConfig.withCredentials ?? false,
|
|
@@ -3259,7 +3752,7 @@ export const request: AxiosInstance = axios.create({
|
|
|
3259
3752
|
|
|
3260
3753
|
// ============ \u8BF7\u6C42\u62E6\u622A\u5668 ============
|
|
3261
3754
|
|
|
3262
|
-
|
|
3755
|
+
instance.interceptors.request.use(
|
|
3263
3756
|
(config: InternalAxiosRequestConfig) => {
|
|
3264
3757
|
// 1. Token \u6CE8\u5165
|
|
3265
3758
|
if (userConfig.getToken) {
|
|
@@ -3290,7 +3783,7 @@ request.interceptors.request.use(
|
|
|
3290
3783
|
|
|
3291
3784
|
// ============ \u54CD\u5E94\u62E6\u622A\u5668 ============
|
|
3292
3785
|
|
|
3293
|
-
|
|
3786
|
+
instance.interceptors.response.use(
|
|
3294
3787
|
(response: AxiosResponse) => {
|
|
3295
3788
|
// \u7528\u6237\u81EA\u5B9A\u4E49\u54CD\u5E94\u62E6\u622A
|
|
3296
3789
|
if (userConfig.responseInterceptor) {
|
|
@@ -3329,8 +3822,45 @@ request.interceptors.response.use(
|
|
|
3329
3822
|
}
|
|
3330
3823
|
);
|
|
3331
3824
|
|
|
3825
|
+
// ============ \u8BF7\u6C42\u5C01\u88C5\u7C7B ============
|
|
3826
|
+
|
|
3827
|
+
type ExtraConfig = AxiosRequestConfig & { suppressErrorNotification?: boolean };
|
|
3828
|
+
|
|
3829
|
+
class Request {
|
|
3830
|
+
constructor(private readonly http: AxiosInstance) {}
|
|
3831
|
+
|
|
3832
|
+
get<T = any>(url: string, params?: Record<string, any>, config?: ExtraConfig): Promise<Result<T>> {
|
|
3833
|
+
return this.http.get(url, {
|
|
3834
|
+
...config,
|
|
3835
|
+
params,
|
|
3836
|
+
paramsSerializer,
|
|
3837
|
+
});
|
|
3838
|
+
}
|
|
3839
|
+
|
|
3840
|
+
post<T = any>(url: string, data?: any, config?: ExtraConfig): Promise<Result<T>> {
|
|
3841
|
+
return this.http.post(url, data, config);
|
|
3842
|
+
}
|
|
3843
|
+
|
|
3844
|
+
put<T = any>(url: string, data?: any, config?: ExtraConfig): Promise<Result<T>> {
|
|
3845
|
+
return this.http.put(url, data, config);
|
|
3846
|
+
}
|
|
3847
|
+
|
|
3848
|
+
delete<T = any>(url: string, params?: Record<string, any>, config?: ExtraConfig): Promise<Result<T>> {
|
|
3849
|
+
return this.http.delete(url, {
|
|
3850
|
+
...config,
|
|
3851
|
+
params,
|
|
3852
|
+
paramsSerializer,
|
|
3853
|
+
});
|
|
3854
|
+
}
|
|
3855
|
+
|
|
3856
|
+
patch<T = any>(url: string, data?: any, config?: ExtraConfig): Promise<Result<T>> {
|
|
3857
|
+
return this.http.patch(url, data, config);
|
|
3858
|
+
}
|
|
3859
|
+
}
|
|
3860
|
+
|
|
3332
3861
|
// ============ \u5BFC\u51FA ============
|
|
3333
3862
|
|
|
3863
|
+
export const request = new Request(instance);
|
|
3334
3864
|
export type { Result };
|
|
3335
3865
|
export default request;
|
|
3336
3866
|
`;
|
|
@@ -3338,7 +3868,7 @@ export default request;
|
|
|
3338
3868
|
|
|
3339
3869
|
// src/plugin/builtin/zustand.ts
|
|
3340
3870
|
import { existsSync as existsSync10, mkdirSync as mkdirSync4, writeFileSync as writeFileSync5 } from "fs";
|
|
3341
|
-
import { join as
|
|
3871
|
+
import { join as join11 } from "path";
|
|
3342
3872
|
var zustandPlugin = createPlugin((options = {}) => ({
|
|
3343
3873
|
name: "@4399ywkf/plugin-zustand",
|
|
3344
3874
|
version: "1.0.0",
|
|
@@ -3346,7 +3876,7 @@ var zustandPlugin = createPlugin((options = {}) => ({
|
|
|
3346
3876
|
setup(context) {
|
|
3347
3877
|
const { scaffold = true, storeDir = "store" } = options;
|
|
3348
3878
|
const { cwd, logger } = context;
|
|
3349
|
-
const storePath =
|
|
3879
|
+
const storePath = join11(cwd, storeDir);
|
|
3350
3880
|
if (scaffold && !existsSync10(storePath)) {
|
|
3351
3881
|
scaffoldStore(storePath, logger);
|
|
3352
3882
|
}
|
|
@@ -3375,10 +3905,10 @@ var zustandPlugin = createPlugin((options = {}) => ({
|
|
|
3375
3905
|
function scaffoldStore(storePath, logger) {
|
|
3376
3906
|
const dirs = [
|
|
3377
3907
|
storePath,
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3908
|
+
join11(storePath, "middleware"),
|
|
3909
|
+
join11(storePath, "app"),
|
|
3910
|
+
join11(storePath, "app", "slices"),
|
|
3911
|
+
join11(storePath, "app", "slices", "counter")
|
|
3382
3912
|
];
|
|
3383
3913
|
for (const dir of dirs) {
|
|
3384
3914
|
if (!existsSync10(dir)) {
|
|
@@ -3386,36 +3916,36 @@ function scaffoldStore(storePath, logger) {
|
|
|
3386
3916
|
}
|
|
3387
3917
|
}
|
|
3388
3918
|
writeFileSync5(
|
|
3389
|
-
|
|
3919
|
+
join11(storePath, "middleware", "createDevtools.ts"),
|
|
3390
3920
|
TPL_CREATE_DEVTOOLS,
|
|
3391
3921
|
"utf-8"
|
|
3392
3922
|
);
|
|
3393
3923
|
writeFileSync5(
|
|
3394
|
-
|
|
3924
|
+
join11(storePath, "app", "slices", "counter", "initialState.ts"),
|
|
3395
3925
|
TPL_COUNTER_INITIAL_STATE,
|
|
3396
3926
|
"utf-8"
|
|
3397
3927
|
);
|
|
3398
3928
|
writeFileSync5(
|
|
3399
|
-
|
|
3929
|
+
join11(storePath, "app", "slices", "counter", "actions.ts"),
|
|
3400
3930
|
TPL_COUNTER_ACTIONS,
|
|
3401
3931
|
"utf-8"
|
|
3402
3932
|
);
|
|
3403
3933
|
writeFileSync5(
|
|
3404
|
-
|
|
3934
|
+
join11(storePath, "app", "initialState.ts"),
|
|
3405
3935
|
TPL_APP_INITIAL_STATE,
|
|
3406
3936
|
"utf-8"
|
|
3407
3937
|
);
|
|
3408
3938
|
writeFileSync5(
|
|
3409
|
-
|
|
3939
|
+
join11(storePath, "app", "store.ts"),
|
|
3410
3940
|
TPL_APP_STORE,
|
|
3411
3941
|
"utf-8"
|
|
3412
3942
|
);
|
|
3413
3943
|
writeFileSync5(
|
|
3414
|
-
|
|
3944
|
+
join11(storePath, "app", "index.tsx"),
|
|
3415
3945
|
TPL_APP_INDEX,
|
|
3416
3946
|
"utf-8"
|
|
3417
3947
|
);
|
|
3418
|
-
writeFileSync5(
|
|
3948
|
+
writeFileSync5(join11(storePath, "index.ts"), TPL_STORE_INDEX, "utf-8");
|
|
3419
3949
|
logger.info("\u5DF2\u751F\u6210 store/ \u811A\u624B\u67B6\uFF08Agent/Slice \u67B6\u6784\uFF09");
|
|
3420
3950
|
}
|
|
3421
3951
|
var TPL_CREATE_DEVTOOLS = `import type { DevtoolsOptions } from "zustand/middleware";
|
|
@@ -3578,7 +4108,7 @@ export type { StateCreator, StoreApi } from "zustand";
|
|
|
3578
4108
|
}
|
|
3579
4109
|
|
|
3580
4110
|
// src/cli/dev.ts
|
|
3581
|
-
import { rspack as
|
|
4111
|
+
import { rspack as rspack4 } from "@rspack/core";
|
|
3582
4112
|
import { RspackDevServer } from "@rspack/dev-server";
|
|
3583
4113
|
import chalk2 from "chalk";
|
|
3584
4114
|
|
|
@@ -3672,7 +4202,7 @@ import chalk from "chalk";
|
|
|
3672
4202
|
import os from "os";
|
|
3673
4203
|
import { createRequire as createRequire3 } from "module";
|
|
3674
4204
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
3675
|
-
import { dirname as dirname2, join as
|
|
4205
|
+
import { dirname as dirname2, join as join12 } from "path";
|
|
3676
4206
|
var __filename = fileURLToPath2(import.meta.url);
|
|
3677
4207
|
var __dirname2 = dirname2(__filename);
|
|
3678
4208
|
var require4 = createRequire3(import.meta.url);
|
|
@@ -3680,7 +4210,7 @@ var _version = null;
|
|
|
3680
4210
|
function getFrameworkVersion() {
|
|
3681
4211
|
if (_version) return _version;
|
|
3682
4212
|
try {
|
|
3683
|
-
const pkgPath =
|
|
4213
|
+
const pkgPath = join12(__dirname2, "../../package.json");
|
|
3684
4214
|
const pkg = require4(pkgPath);
|
|
3685
4215
|
_version = pkg.version || "0.0.0";
|
|
3686
4216
|
} catch {
|
|
@@ -3889,7 +4419,7 @@ async function dev(options = {}) {
|
|
|
3889
4419
|
printer.updateProgress(0, "preparing");
|
|
3890
4420
|
rspackConfig.plugins = rspackConfig.plugins || [];
|
|
3891
4421
|
rspackConfig.plugins.push(
|
|
3892
|
-
new
|
|
4422
|
+
new rspack4.ProgressPlugin(createProgressHandler(printer))
|
|
3893
4423
|
);
|
|
3894
4424
|
rspackConfig.stats = "none";
|
|
3895
4425
|
rspackConfig.infrastructureLogging = { level: "none" };
|
|
@@ -3903,7 +4433,7 @@ async function dev(options = {}) {
|
|
|
3903
4433
|
progress: false
|
|
3904
4434
|
};
|
|
3905
4435
|
}
|
|
3906
|
-
const compiler =
|
|
4436
|
+
const compiler = rspack4(rspackConfig);
|
|
3907
4437
|
compiler.hooks.done.tap("ywkf-dev-printer", (stats) => {
|
|
3908
4438
|
const hasErrors = stats.hasErrors();
|
|
3909
4439
|
if (hasErrors) {
|
|
@@ -3953,7 +4483,7 @@ async function dev(options = {}) {
|
|
|
3953
4483
|
}
|
|
3954
4484
|
|
|
3955
4485
|
// src/cli/build.ts
|
|
3956
|
-
import { rspack as
|
|
4486
|
+
import { rspack as rspack5 } from "@rspack/core";
|
|
3957
4487
|
import chalk3 from "chalk";
|
|
3958
4488
|
function formatSize(bytes) {
|
|
3959
4489
|
if (bytes < 1024) return `${bytes} B`;
|
|
@@ -4014,11 +4544,11 @@ async function build(options = {}) {
|
|
|
4014
4544
|
printer.updateProgress(0, "preparing");
|
|
4015
4545
|
rspackConfig.plugins = rspackConfig.plugins || [];
|
|
4016
4546
|
rspackConfig.plugins.push(
|
|
4017
|
-
new
|
|
4547
|
+
new rspack5.ProgressPlugin(createProgressHandler(printer))
|
|
4018
4548
|
);
|
|
4019
4549
|
rspackConfig.stats = "none";
|
|
4020
4550
|
rspackConfig.infrastructureLogging = { level: "none" };
|
|
4021
|
-
const compiler =
|
|
4551
|
+
const compiler = rspack5(rspackConfig);
|
|
4022
4552
|
const stats = await new Promise((resolve4, reject) => {
|
|
4023
4553
|
compiler.run((err, stats2) => {
|
|
4024
4554
|
if (err) {
|