@4399ywkf/core 4.0.85 → 5.0.0

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.
Files changed (81) hide show
  1. package/dist/cli/index.js +2180 -0
  2. package/dist/cli/index.js.map +1 -0
  3. package/dist/config/index.d.ts +37 -0
  4. package/dist/config/index.js +143 -0
  5. package/dist/config/index.js.map +1 -0
  6. package/dist/index.d.ts +496 -6
  7. package/dist/index.js +3671 -49
  8. package/dist/index.js.map +1 -0
  9. package/dist/plugin/index.d.ts +110 -0
  10. package/dist/plugin/index.js +277 -0
  11. package/dist/plugin/index.js.map +1 -0
  12. package/dist/router/index.d.ts +126 -0
  13. package/dist/router/index.js +390 -0
  14. package/dist/router/index.js.map +1 -0
  15. package/dist/rspack/index.d.ts +29 -0
  16. package/dist/rspack/index.js +1574 -0
  17. package/dist/rspack/index.js.map +1 -0
  18. package/dist/runtime/index.d.ts +120 -0
  19. package/dist/runtime/index.js +406 -0
  20. package/dist/runtime/index.js.map +1 -0
  21. package/dist/schema-BuqmN_ra.d.ts +390 -0
  22. package/dist/types-BZV_2QtD.d.ts +97 -0
  23. package/package.json +88 -37
  24. package/README.md +0 -3
  25. package/compiled/dotenv/LICENSE +0 -23
  26. package/compiled/dotenv/index.js +0 -1
  27. package/compiled/dotenv/lib/main.d.ts +0 -73
  28. package/compiled/dotenv/package.json +0 -1
  29. package/compiled/dotenv/types/index.d.ts +0 -59
  30. package/compiled/dotenv-expand/LICENSE +0 -24
  31. package/compiled/dotenv-expand/index.js +0 -1
  32. package/compiled/dotenv-expand/lib/main.d.ts +0 -29
  33. package/compiled/dotenv-expand/package.json +0 -1
  34. package/compiled/just-diff/LICENSE +0 -21
  35. package/compiled/just-diff/index.d.ts +0 -20
  36. package/compiled/just-diff/index.js +0 -1
  37. package/compiled/just-diff/package.json +0 -1
  38. package/dist/config/config.d.ts +0 -62
  39. package/dist/config/config.js +0 -240
  40. package/dist/config/utils.d.ts +0 -8
  41. package/dist/config/utils.js +0 -40
  42. package/dist/constants.d.ts +0 -9
  43. package/dist/constants.js +0 -45
  44. package/dist/route/defineRoutes.d.ts +0 -1
  45. package/dist/route/defineRoutes.js +0 -61
  46. package/dist/route/route.d.ts +0 -3
  47. package/dist/route/route.js +0 -27
  48. package/dist/route/routeUtils.d.ts +0 -8
  49. package/dist/route/routeUtils.js +0 -46
  50. package/dist/route/routesConfig.d.ts +0 -6
  51. package/dist/route/routesConfig.js +0 -125
  52. package/dist/route/routesConvention.d.ts +0 -5
  53. package/dist/route/routesConvention.js +0 -88
  54. package/dist/route/utils.d.ts +0 -8
  55. package/dist/route/utils.js +0 -59
  56. package/dist/service/command.d.ts +0 -30
  57. package/dist/service/command.js +0 -39
  58. package/dist/service/env.d.ts +0 -4
  59. package/dist/service/env.js +0 -47
  60. package/dist/service/generatePlugin.d.ts +0 -4
  61. package/dist/service/generatePlugin.js +0 -102
  62. package/dist/service/generator.d.ts +0 -71
  63. package/dist/service/generator.js +0 -40
  64. package/dist/service/hook.d.ts +0 -16
  65. package/dist/service/hook.js +0 -52
  66. package/dist/service/path.d.ts +0 -15
  67. package/dist/service/path.js +0 -55
  68. package/dist/service/plugin.d.ts +0 -61
  69. package/dist/service/plugin.js +0 -174
  70. package/dist/service/pluginAPI.d.ts +0 -49
  71. package/dist/service/pluginAPI.js +0 -233
  72. package/dist/service/service.d.ts +0 -147
  73. package/dist/service/service.js +0 -544
  74. package/dist/service/servicePlugin.d.ts +0 -3
  75. package/dist/service/servicePlugin.js +0 -37
  76. package/dist/service/telemetry.d.ts +0 -32
  77. package/dist/service/telemetry.js +0 -127
  78. package/dist/service/utils.d.ts +0 -2
  79. package/dist/service/utils.js +0 -36
  80. package/dist/types.d.ts +0 -116
  81. package/dist/types.js +0 -77
package/dist/index.js CHANGED
@@ -1,51 +1,3673 @@
1
- var __defProp = Object.defineProperty;
2
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
- var __getOwnPropNames = Object.getOwnPropertyNames;
4
- var __hasOwnProp = Object.prototype.hasOwnProperty;
5
- var __export = (target, all) => {
6
- for (var name in all)
7
- __defProp(target, name, { get: all[name], enumerable: true });
8
- };
9
- var __copyProps = (to, from, except, desc) => {
10
- if (from && typeof from === "object" || typeof from === "function") {
11
- for (let key of __getOwnPropNames(from))
12
- if (!__hasOwnProp.call(to, key) && key !== except)
13
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
- }
15
- return to;
16
- };
17
- var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
18
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
-
20
- // src/index.ts
21
- var src_exports = {};
22
- __export(src_exports, {
23
- Env: () => import_types.Env,
24
- Generator: () => import_generator.Generator,
25
- GeneratorType: () => import_generator.GeneratorType,
26
- IAdd: () => import_types.IAdd,
27
- IEvent: () => import_types.IEvent,
28
- IModify: () => import_types.IModify,
29
- IRoute: () => import_types.IRoute
1
+ // src/config/schema.ts
2
+ function defineConfig(config) {
3
+ return config;
4
+ }
5
+ var defaultConfig = {
6
+ appName: "app",
7
+ appCName: "\u5E94\u7528",
8
+ dev: {
9
+ port: 3e3,
10
+ host: "localhost",
11
+ proxy: {},
12
+ https: false
13
+ },
14
+ output: {
15
+ path: "dist",
16
+ publicPath: "/",
17
+ clean: true
18
+ },
19
+ html: {
20
+ title: "\u5E94\u7528",
21
+ template: "public/index.html",
22
+ favicon: "public/favicon.ico",
23
+ mountRoot: "root"
24
+ },
25
+ style: {
26
+ cssModules: true,
27
+ less: { enabled: true, lessOptions: { javascriptEnabled: true } },
28
+ sass: { enabled: true, sassOptions: {} },
29
+ tailwindcss: true
30
+ },
31
+ router: {
32
+ basename: "/",
33
+ conventional: false,
34
+ pagesDir: "src/pages",
35
+ exclude: [
36
+ /\/components?\//,
37
+ /\/models\//,
38
+ /\/utils?\//,
39
+ /^_/,
40
+ /\.d\.ts$/,
41
+ /\.(test|spec|e2e)\.(ts|tsx|js|jsx)$/
42
+ ]
43
+ },
44
+ microFrontend: {
45
+ enabled: false,
46
+ name: "app",
47
+ framework: "qiankun"
48
+ },
49
+ performance: {
50
+ rsdoctor: false,
51
+ splitChunks: true,
52
+ dropConsole: false
53
+ },
54
+ tools: {},
55
+ env: {
56
+ publicEnvFile: "config/env/.env.public",
57
+ envDir: "config/env"
58
+ },
59
+ alias: {},
60
+ plugins: []
61
+ };
62
+
63
+ // src/config/loader.ts
64
+ import { existsSync } from "fs";
65
+ import { resolve, extname } from "path";
66
+ import { pathToFileURL } from "url";
67
+ import deepmerge from "deepmerge";
68
+ var CONFIG_FILES = [
69
+ "ywkf.config.ts",
70
+ "ywkf.config.mts",
71
+ "ywkf.config.js",
72
+ "ywkf.config.mjs"
73
+ ];
74
+ function findConfigFile(cwd) {
75
+ for (const file of CONFIG_FILES) {
76
+ const configPath = resolve(cwd, file);
77
+ if (existsSync(configPath)) {
78
+ return configPath;
79
+ }
80
+ }
81
+ return null;
82
+ }
83
+ async function loadTsConfig(configPath) {
84
+ const jiti = (await import("jiti")).default;
85
+ const loader = jiti(configPath, {
86
+ interopDefault: true
87
+ });
88
+ const config = loader(configPath);
89
+ return config.default || config;
90
+ }
91
+ async function loadJsConfig(configPath) {
92
+ const fileUrl = pathToFileURL(configPath).href;
93
+ const module = await import(fileUrl);
94
+ return module.default || module;
95
+ }
96
+ async function loadConfigFile(configPath) {
97
+ const ext = extname(configPath);
98
+ if (ext === ".ts" || ext === ".mts") {
99
+ return loadTsConfig(configPath);
100
+ }
101
+ return loadJsConfig(configPath);
102
+ }
103
+ function mergeConfig(userConfig, baseConfig = defaultConfig) {
104
+ return deepmerge(baseConfig, userConfig, {
105
+ arrayMerge: (_, sourceArray) => sourceArray
106
+ });
107
+ }
108
+ async function resolveConfig(cwd) {
109
+ const configPath = findConfigFile(cwd);
110
+ if (!configPath) {
111
+ console.warn(
112
+ "\u26A0\uFE0F \u672A\u627E\u5230\u914D\u7F6E\u6587\u4EF6 (ywkf.config.ts)\uFF0C\u4F7F\u7528\u9ED8\u8BA4\u914D\u7F6E"
113
+ );
114
+ return {
115
+ config: defaultConfig,
116
+ configPath: null
117
+ };
118
+ }
119
+ try {
120
+ const userConfig = await loadConfigFile(configPath);
121
+ const config = mergeConfig(userConfig);
122
+ return { config, configPath };
123
+ } catch (error) {
124
+ console.error("\u274C \u914D\u7F6E\u6587\u4EF6\u52A0\u8F7D\u5931\u8D25:", error);
125
+ throw error;
126
+ }
127
+ }
128
+ function createPathResolver(cwd) {
129
+ return {
130
+ resolveApp: (relativePath) => resolve(cwd, relativePath),
131
+ cwd
132
+ };
133
+ }
134
+
135
+ // src/rspack/index.ts
136
+ import { RsdoctorRspackPlugin } from "@rsdoctor/rspack-plugin";
137
+
138
+ // src/rspack/dev.ts
139
+ import { merge } from "webpack-merge";
140
+ import { createRequire as createRequire2 } from "module";
141
+
142
+ // src/rspack/base.ts
143
+ import { rspack } from "@rspack/core";
144
+ import { createRequire } from "module";
145
+ import { fileURLToPath } from "url";
146
+ import { dirname, join as join5 } from "path";
147
+
148
+ // src/generator/plugin.ts
149
+ import { watch, existsSync as existsSync5 } from "fs";
150
+ import { join as join4 } from "path";
151
+
152
+ // src/generator/generator.ts
153
+ import { existsSync as existsSync4, mkdirSync as mkdirSync2, writeFileSync as writeFileSync2, readFileSync as readFileSync2 } from "fs";
154
+ import { join as join3 } from "path";
155
+
156
+ // src/router/generator.ts
157
+ import { existsSync as existsSync2, readdirSync, statSync, mkdirSync, writeFileSync } from "fs";
158
+ import { join, relative } from "path";
159
+ var EXCLUDED_DIRS = /* @__PURE__ */ new Set([
160
+ "components",
161
+ "hooks",
162
+ "utils",
163
+ "services",
164
+ "models",
165
+ "assets",
166
+ "types",
167
+ "constants",
168
+ "styles"
169
+ ]);
170
+ var CONVENTION_FILES = {
171
+ page: /^page\.(tsx?|jsx?)$/,
172
+ layout: /^layout\.(tsx?|jsx?)$/,
173
+ error: /^error\.(tsx?|jsx?)$/,
174
+ loading: /^loading\.(tsx?|jsx?)$/,
175
+ catchAll: /^\$\.(tsx?|jsx?)$/
176
+ };
177
+ var ConventionalRouteGenerator = class {
178
+ options;
179
+ constructor(options) {
180
+ this.options = options;
181
+ }
182
+ generate() {
183
+ const { pagesDir } = this.options;
184
+ if (!existsSync2(pagesDir)) {
185
+ console.warn(`[ywkf] \u9875\u9762\u76EE\u5F55\u4E0D\u5B58\u5728: ${pagesDir}`);
186
+ return [];
187
+ }
188
+ return this.scanDirectory(pagesDir, "/");
189
+ }
190
+ /**
191
+ * 扫描目录,生成路由树
192
+ */
193
+ scanDirectory(dir, routePath) {
194
+ const entries = readdirSync(dir);
195
+ const layoutFile = entries.find((e) => CONVENTION_FILES.layout.test(e));
196
+ const pageFile = entries.find((e) => CONVENTION_FILES.page.test(e));
197
+ const errorFile = entries.find((e) => CONVENTION_FILES.error.test(e));
198
+ const loadingFile = entries.find((e) => CONVENTION_FILES.loading.test(e));
199
+ const catchAllFile = entries.find((e) => CONVENTION_FILES.catchAll.test(e));
200
+ const subDirs = entries.filter((e) => {
201
+ if (e.startsWith(".")) return false;
202
+ if (EXCLUDED_DIRS.has(e)) return false;
203
+ return statSync(join(dir, e)).isDirectory();
204
+ });
205
+ const childRoutes = [];
206
+ for (const subDir of subDirs) {
207
+ const subDirPath = join(dir, subDir);
208
+ if (subDir.startsWith("__")) {
209
+ const pathlessRoutes = this.scanDirectory(subDirPath, routePath);
210
+ const pathlessLayout = readdirSync(subDirPath).find(
211
+ (e) => CONVENTION_FILES.layout.test(e)
212
+ );
213
+ if (pathlessLayout) {
214
+ const pathlessChildren = this.scanDirectory(subDirPath, routePath);
215
+ childRoutes.push({
216
+ path: routePath,
217
+ name: this.generateRouteName(subDir.slice(2)),
218
+ layoutFile: relative(this.options.pagesDir, join(subDirPath, pathlessLayout)),
219
+ isLayout: true,
220
+ pathless: true,
221
+ children: pathlessChildren.filter(
222
+ (r) => r.layoutFile !== relative(this.options.pagesDir, join(subDirPath, pathlessLayout))
223
+ )
224
+ });
225
+ } else {
226
+ childRoutes.push(...pathlessRoutes);
227
+ }
228
+ continue;
229
+ }
230
+ const subRoutePath = this.resolveRoutePath(subDir, routePath);
231
+ childRoutes.push(...this.scanDirectory(subDirPath, subRoutePath));
232
+ }
233
+ const routeName = this.generateRouteName(routePath);
234
+ const relPath = (file) => relative(this.options.pagesDir, join(dir, file));
235
+ if (layoutFile) {
236
+ const layoutChildren = [];
237
+ if (pageFile) {
238
+ layoutChildren.push({
239
+ path: routePath,
240
+ file: relPath(pageFile),
241
+ name: routeName + "Index",
242
+ index: true
243
+ });
244
+ }
245
+ if (catchAllFile) {
246
+ layoutChildren.push({
247
+ path: "*",
248
+ file: relPath(catchAllFile),
249
+ name: routeName + "CatchAll"
250
+ });
251
+ }
252
+ layoutChildren.push(...childRoutes);
253
+ return [
254
+ {
255
+ path: routePath,
256
+ layoutFile: relPath(layoutFile),
257
+ errorFile: errorFile ? relPath(errorFile) : void 0,
258
+ loadingFile: loadingFile ? relPath(loadingFile) : void 0,
259
+ name: routeName,
260
+ isLayout: true,
261
+ children: layoutChildren
262
+ }
263
+ ];
264
+ }
265
+ const result = [];
266
+ if (pageFile) {
267
+ result.push({
268
+ path: routePath,
269
+ file: relPath(pageFile),
270
+ errorFile: errorFile ? relPath(errorFile) : void 0,
271
+ name: routeName
272
+ });
273
+ }
274
+ if (catchAllFile) {
275
+ result.push({
276
+ path: "*",
277
+ file: relPath(catchAllFile),
278
+ name: routeName + "CatchAll"
279
+ });
280
+ }
281
+ result.push(...childRoutes);
282
+ return result;
283
+ }
284
+ /**
285
+ * 解析目录名到路由路径
286
+ *
287
+ * - [id] → :id
288
+ * - [id$] → :id?
289
+ * - [...slug] → *
290
+ * - user.profile → user/profile
291
+ */
292
+ resolveRoutePath(dirName, parentPath) {
293
+ let segment;
294
+ if (dirName.match(/^\[\.\.\.(.+)\]$/)) {
295
+ segment = "*";
296
+ } else if (dirName.match(/^\[(.+)\$\]$/)) {
297
+ const param = dirName.slice(1, -2);
298
+ segment = `:${param}?`;
299
+ } else if (dirName.match(/^\[(.+)\]$/)) {
300
+ const param = dirName.slice(1, -1);
301
+ segment = `:${param}`;
302
+ } else if (dirName.includes(".")) {
303
+ segment = dirName.replace(/\./g, "/");
304
+ } else {
305
+ segment = dirName;
306
+ }
307
+ return parentPath === "/" ? `/${segment}` : `${parentPath}/${segment}`;
308
+ }
309
+ /**
310
+ * 生成有效的 JS 标识符名称
311
+ */
312
+ generateRouteName(path) {
313
+ const name = path.split("/").filter(Boolean).map(
314
+ (s) => s.replace(/^:/, "Param").replace(/\?$/, "Optional").replace(/^\*$/, "CatchAll")
315
+ ).map((s) => {
316
+ const cleaned = s.replace(/[^a-zA-Z0-9]/g, "");
317
+ if (!cleaned) return "";
318
+ return cleaned.charAt(0).toUpperCase() + cleaned.slice(1);
319
+ }).join("");
320
+ if (!name || /^\d/.test(name)) {
321
+ return "Page" + (name || "Root");
322
+ }
323
+ return name;
324
+ }
325
+ // ===== 代码生成 =====
326
+ generateCode() {
327
+ const routes = this.generate();
328
+ const lazyImports = [];
329
+ const errorImports = [];
330
+ const loadingImports = [];
331
+ this.collectImports(routes, lazyImports, errorImports, loadingImports);
332
+ return `// \u6B64\u6587\u4EF6\u7531 @4399ywkf/core \u81EA\u52A8\u751F\u6210\uFF0C\u8BF7\u52FF\u624B\u52A8\u4FEE\u6539
333
+ // Generated at: ${(/* @__PURE__ */ new Date()).toISOString()}
334
+
335
+ import React, { lazy, Suspense } from "react";
336
+ import { createBrowserRouter, type RouteObject } from "react-router";
337
+
338
+ // \u61D2\u52A0\u8F7D\u9875\u9762\u7EC4\u4EF6
339
+ ${lazyImports.join("\n")}
340
+ ${errorImports.length > 0 ? "\n// \u9519\u8BEF\u8FB9\u754C\u7EC4\u4EF6\n" + errorImports.join("\n") : ""}
341
+ ${loadingImports.length > 0 ? "\n// \u52A0\u8F7D\u72B6\u6001\u7EC4\u4EF6\n" + loadingImports.join("\n") : ""}
342
+
343
+ // \u9ED8\u8BA4\u52A0\u8F7D\u72B6\u6001
344
+ const DefaultLoading = () => <div style={{ padding: 24, textAlign: "center" }}>\u52A0\u8F7D\u4E2D...</div>;
345
+
346
+ // \u61D2\u52A0\u8F7D\u5305\u88C5
347
+ function LazyRoute({
348
+ Component,
349
+ Loading = DefaultLoading,
350
+ }: {
351
+ Component: React.LazyExoticComponent<React.ComponentType<unknown>>;
352
+ Loading?: React.ComponentType;
353
+ }) {
354
+ return (
355
+ <Suspense fallback={<Loading />}>
356
+ <Component />
357
+ </Suspense>
358
+ );
359
+ }
360
+
361
+ // \u8DEF\u7531\u914D\u7F6E
362
+ export const routes: RouteObject[] = ${this.emitRouteArray(routes)};
363
+
364
+ /**
365
+ * \u521B\u5EFA\u8DEF\u7531\u5B9E\u4F8B
366
+ */
367
+ export function createRouter(basename?: string) {
368
+ return createBrowserRouter(routes, { basename: basename || "/" });
369
+ }
370
+
371
+ export default routes;
372
+ `;
373
+ }
374
+ collectImports(routes, lazyImports, errorImports, loadingImports) {
375
+ for (const route of routes) {
376
+ const name = route.name;
377
+ const toImportPath = (f) => f.replace(/\.(tsx?|jsx?)$/, "");
378
+ if (route.isLayout && route.layoutFile) {
379
+ lazyImports.push(
380
+ `const ${name}Layout = lazy(() => import("@/pages/${toImportPath(route.layoutFile)}"));`
381
+ );
382
+ }
383
+ if (route.file) {
384
+ lazyImports.push(
385
+ `const ${name}Page = lazy(() => import("@/pages/${toImportPath(route.file)}"));`
386
+ );
387
+ }
388
+ if (route.errorFile) {
389
+ errorImports.push(
390
+ `const ${name}Error = lazy(() => import("@/pages/${toImportPath(route.errorFile)}"));`
391
+ );
392
+ }
393
+ if (route.loadingFile) {
394
+ loadingImports.push(
395
+ `const ${name}Loading = lazy(() => import("@/pages/${toImportPath(route.loadingFile)}"));`
396
+ );
397
+ }
398
+ if (route.children) {
399
+ this.collectImports(route.children, lazyImports, errorImports, loadingImports);
400
+ }
401
+ }
402
+ }
403
+ emitRouteArray(routes, parentPath) {
404
+ const items = routes.map((r) => this.emitRouteObject(r, parentPath));
405
+ return `[
406
+ ${items.join(",\n ")}
407
+ ]`;
408
+ }
409
+ emitRouteObject(route, parentPath) {
410
+ const parts = [];
411
+ const name = route.name;
412
+ if (route.index) {
413
+ parts.push("index: true");
414
+ } else if (route.pathless) {
415
+ } else if (route.path === "*") {
416
+ parts.push(`path: "*"`);
417
+ } else if (parentPath && route.path.startsWith(parentPath) && parentPath !== "/") {
418
+ const rel = route.path.slice(parentPath.length + 1);
419
+ parts.push(`path: "${rel || ""}"`);
420
+ } else {
421
+ parts.push(`path: "${route.path}"`);
422
+ }
423
+ if (route.isLayout && route.layoutFile) {
424
+ const loadingProp = route.loadingFile ? ` Loading={${name}Loading}` : "";
425
+ parts.push(`element: <LazyRoute Component={${name}Layout}${loadingProp} />`);
426
+ } else if (route.file) {
427
+ parts.push(`element: <LazyRoute Component={${name}Page} />`);
428
+ }
429
+ if (route.errorFile) {
430
+ parts.push(`errorElement: <LazyRoute Component={${name}Error} />`);
431
+ }
432
+ if (route.children && route.children.length > 0) {
433
+ const childParent = route.pathless ? parentPath : route.path;
434
+ parts.push(`children: ${this.emitRouteArray(route.children, childParent)}`);
435
+ }
436
+ return `{
437
+ ${parts.join(",\n ")}
438
+ }`;
439
+ }
440
+ /**
441
+ * 写入路由文件
442
+ */
443
+ write() {
444
+ const { outputDir } = this.options;
445
+ const code = this.generateCode();
446
+ if (!existsSync2(outputDir)) {
447
+ mkdirSync(outputDir, { recursive: true });
448
+ }
449
+ writeFileSync(join(outputDir, "routes.tsx"), code, "utf-8");
450
+ console.log(`[ywkf] \u7EA6\u5B9A\u5F0F\u8DEF\u7531\u5DF2\u751F\u6210`);
451
+ }
452
+ };
453
+ function generateConventionalRoutes(options) {
454
+ new ConventionalRouteGenerator(options).write();
455
+ }
456
+
457
+ // src/generator/templates/entry.ts
458
+ function generateEntry(config, injections = {}) {
459
+ const imports = [
460
+ `import "@/index.css";`,
461
+ `import { runApp } from "./bootstrap";`,
462
+ ...injections.imports || []
463
+ ];
464
+ const topLevel = injections.topLevel || [];
465
+ const exports = injections.exports || [];
466
+ const hasPluginExports = exports.length > 0;
467
+ const startupCode = hasPluginExports ? `// \u72EC\u7ACB\u8FD0\u884C\u6A21\u5F0F
468
+ if (shouldRunIndependently !== false) {
469
+ runApp();
470
+ }` : `// \u542F\u52A8\u5E94\u7528
471
+ runApp();`;
472
+ return `// \u6B64\u6587\u4EF6\u7531 @4399ywkf/core \u81EA\u52A8\u751F\u6210\uFF0C\u8BF7\u52FF\u624B\u52A8\u4FEE\u6539
473
+ // Generated at: ${(/* @__PURE__ */ new Date()).toISOString()}
474
+
475
+ ${imports.join("\n")}
476
+
477
+ ${topLevel.length > 0 ? topLevel.join("\n") + "\n" : ""}${exports.length > 0 ? exports.join("\n") + "\n\n" : ""}${startupCode}
478
+ `;
479
+ }
480
+
481
+ // src/generator/templates/bootstrap.ts
482
+ function generateBootstrap(config, injections = {}) {
483
+ const { appName, router } = config;
484
+ const routerImport = router.conventional ? `import { createRouter } from "./routes";` : `import { createRouter } from "@/routes";`;
485
+ const imports = [
486
+ `import { bootstrap, type AppConfig } from "@4399ywkf/core/runtime";`,
487
+ routerImport,
488
+ ...injections.imports || []
489
+ ];
490
+ const topLevel = injections.topLevel || [];
491
+ const exports = injections.exports || [];
492
+ return `// \u6B64\u6587\u4EF6\u7531 @4399ywkf/core \u81EA\u52A8\u751F\u6210\uFF0C\u8BF7\u52FF\u624B\u52A8\u4FEE\u6539
493
+ // Generated at: ${(/* @__PURE__ */ new Date()).toISOString()}
494
+
495
+ ${imports.join("\n")}
496
+
497
+ /**
498
+ * \u5E94\u7528\u540D\u79F0
499
+ */
500
+ export const APP_NAME = "${appName}";
501
+
502
+ /**
503
+ * \u8DEF\u7531 basename
504
+ */
505
+ export const BASENAME = "${router.basename || "/"}";
506
+
507
+ /**
508
+ * \u83B7\u53D6\u7528\u6237\u81EA\u5B9A\u4E49\u914D\u7F6E\uFF08\u5982\u679C\u5B58\u5728\uFF09
509
+ * \u7528\u6237\u53EF\u5728 src/app.config.ts \u4E2D\u5BFC\u51FA\u914D\u7F6E\u6765\u8986\u76D6\u9ED8\u8BA4\u503C
510
+ */
511
+ async function getUserConfig(): Promise<Partial<AppConfig>> {
512
+ try {
513
+ // webpackIgnore \u6CE8\u91CA\u8BA9\u6253\u5305\u5668\u8DF3\u8FC7\u6A21\u5757\u5B58\u5728\u6027\u68C0\u67E5
514
+ const userConfigModule = await import(/* webpackIgnore: true */ "@/app.config");
515
+ return userConfigModule.default || {};
516
+ } catch {
517
+ // \u6587\u4EF6\u4E0D\u5B58\u5728\u65F6\u8FD4\u56DE\u7A7A\u914D\u7F6E
518
+ return {};
519
+ }
520
+ }
521
+
522
+ /**
523
+ * \u521B\u5EFA\u5E94\u7528\u914D\u7F6E
524
+ */
525
+ export function createAppConfig(userConfig: Partial<AppConfig> = {}): AppConfig {
526
+ const router = createRouter(BASENAME);
527
+
528
+ const defaultConfig: AppConfig = {
529
+ appName: APP_NAME,
530
+ router,
531
+ basename: BASENAME,
532
+ rootId: APP_NAME,
533
+ strictMode: true,
534
+ antd: {
535
+ enabled: true,
536
+ },
537
+ providers: [],
538
+ lifecycle: {
539
+ onMounted() {
540
+ console.log(\`[\${APP_NAME}] \u5E94\u7528\u5DF2\u6302\u8F7D\`);
541
+ },
542
+ onUnmount() {
543
+ console.log(\`[\${APP_NAME}] \u5E94\u7528\u5DF2\u5378\u8F7D\`);
544
+ },
545
+ onError(error) {
546
+ console.error(\`[\${APP_NAME}] \u5168\u5C40\u9519\u8BEF:\`, error);
547
+ },
548
+ },
549
+ };
550
+
551
+ // \u6DF1\u5EA6\u5408\u5E76\u7528\u6237\u914D\u7F6E
552
+ return {
553
+ ...defaultConfig,
554
+ ...userConfig,
555
+ antd: { ...defaultConfig.antd, ...userConfig.antd },
556
+ providers: [...(defaultConfig.providers || []), ...(userConfig.providers || [])],
557
+ lifecycle: { ...defaultConfig.lifecycle, ...userConfig.lifecycle },
558
+ };
559
+ }
560
+
561
+ /**
562
+ * \u542F\u52A8\u5E94\u7528
563
+ */
564
+ export async function runApp(): Promise<void> {
565
+ const userConfig = await getUserConfig();
566
+ await bootstrap(createAppConfig(userConfig));
567
+ }
568
+ ${topLevel.length > 0 ? "\n" + topLevel.join("\n") : ""}
569
+ ${exports.length > 0 ? "\n" + exports.join("\n") : ""}
570
+ `;
571
+ }
572
+
573
+ // src/generator/templates/env-types.ts
574
+ import { existsSync as existsSync3, readFileSync } from "fs";
575
+ import { join as join2 } from "path";
576
+ function generateEnvTypes(cwd, config) {
577
+ const envVars = collectEnvVars(cwd, config);
578
+ const envInterface = envVars.map((key) => ` readonly ${key}: string;`).join("\n");
579
+ return `// \u6B64\u6587\u4EF6\u7531 @4399ywkf/core \u81EA\u52A8\u751F\u6210\uFF0C\u8BF7\u52FF\u624B\u52A8\u4FEE\u6539
580
+ // Generated at: ${(/* @__PURE__ */ new Date()).toISOString()}
581
+
582
+ /// <reference types="react" />
583
+ /// <reference types="react-dom" />
584
+
585
+ declare namespace NodeJS {
586
+ interface ProcessEnv {
587
+ ${envInterface}
588
+ readonly NODE_ENV: "development" | "production" | "test";
589
+ }
590
+ }
591
+
592
+ declare module "*.svg" {
593
+ import * as React from "react";
594
+ const ReactComponent: React.FunctionComponent<
595
+ React.SVGProps<SVGSVGElement> & { title?: string }
596
+ >;
597
+ export default ReactComponent;
598
+ }
599
+
600
+ declare module "*.png" {
601
+ const src: string;
602
+ export default src;
603
+ }
604
+
605
+ declare module "*.jpg" {
606
+ const src: string;
607
+ export default src;
608
+ }
609
+
610
+ declare module "*.jpeg" {
611
+ const src: string;
612
+ export default src;
613
+ }
614
+
615
+ declare module "*.gif" {
616
+ const src: string;
617
+ export default src;
618
+ }
619
+
620
+ declare module "*.webp" {
621
+ const src: string;
622
+ export default src;
623
+ }
624
+
625
+ declare module "*.css" {
626
+ const classes: { readonly [key: string]: string };
627
+ export default classes;
628
+ }
629
+
630
+ declare module "*.less" {
631
+ const classes: { readonly [key: string]: string };
632
+ export default classes;
633
+ }
634
+
635
+ declare module "*.scss" {
636
+ const classes: { readonly [key: string]: string };
637
+ export default classes;
638
+ }
639
+
640
+ declare module "*.md" {
641
+ const content: string;
642
+ export default content;
643
+ }
644
+ `;
645
+ }
646
+ function collectEnvVars(cwd, config) {
647
+ const envVars = /* @__PURE__ */ new Set();
648
+ const publicEnvPath = join2(cwd, config.env.publicEnvFile || "config/env/.env.public");
649
+ if (existsSync3(publicEnvPath)) {
650
+ const content = readFileSync(publicEnvPath, "utf-8");
651
+ parseEnvFile(content, envVars);
652
+ }
653
+ const devEnvPath = join2(cwd, config.env.envDir || "config/env", ".env.development");
654
+ if (existsSync3(devEnvPath)) {
655
+ const content = readFileSync(devEnvPath, "utf-8");
656
+ parseEnvFile(content, envVars);
657
+ }
658
+ const prodEnvPath = join2(cwd, config.env.envDir || "config/env", ".env.production");
659
+ if (existsSync3(prodEnvPath)) {
660
+ const content = readFileSync(prodEnvPath, "utf-8");
661
+ parseEnvFile(content, envVars);
662
+ }
663
+ return Array.from(envVars).sort();
664
+ }
665
+ function parseEnvFile(content, envVars) {
666
+ const lines = content.split("\n");
667
+ for (const line of lines) {
668
+ const trimmed = line.trim();
669
+ if (!trimmed || trimmed.startsWith("#")) {
670
+ continue;
671
+ }
672
+ const match = trimmed.match(/^([A-Z_][A-Z0-9_]*)\s*=/);
673
+ if (match) {
674
+ envVars.add(match[1]);
675
+ }
676
+ }
677
+ }
678
+
679
+ // src/generator/templates/route-types.ts
680
+ function generateRouteTypes() {
681
+ return `// \u6B64\u6587\u4EF6\u7531 @4399ywkf/core \u81EA\u52A8\u751F\u6210\uFF0C\u8BF7\u52FF\u624B\u52A8\u4FEE\u6539
682
+ // Generated at: ${(/* @__PURE__ */ new Date()).toISOString()}
683
+
684
+ import type { RouteObject } from "react-router";
685
+
686
+ declare module "@ywkf/routes" {
687
+ export const routes: RouteObject[];
688
+ export function createRouter(basename?: string): ReturnType<typeof import("react-router").createBrowserRouter>;
689
+ export default routes;
690
+ }
691
+ `;
692
+ }
693
+
694
+ // src/generator/generator.ts
695
+ var YwkfGenerator = class {
696
+ context;
697
+ pluginHooks;
698
+ lastGeneratedContent = /* @__PURE__ */ new Map();
699
+ constructor(context, pluginHooks = []) {
700
+ this.context = {
701
+ ...context,
702
+ outputDir: context.outputDir || join3(context.cwd, ".ywkf")
703
+ };
704
+ this.pluginHooks = pluginHooks;
705
+ }
706
+ /**
707
+ * 生成所有文件
708
+ */
709
+ async generate() {
710
+ const { outputDir } = this.context;
711
+ this.ensureDir(outputDir);
712
+ this.ensureDir(join3(outputDir, "types"));
713
+ this.generateConfigSnapshot();
714
+ this.generateRoutes();
715
+ this.generateBootstrapFile();
716
+ this.generateEntryFile();
717
+ this.generateTypes();
718
+ await this.generatePluginFiles();
719
+ for (const hooks of this.pluginHooks) {
720
+ if (hooks.afterGenerate) {
721
+ await hooks.afterGenerate(this.context);
722
+ }
723
+ }
724
+ console.log(`[ywkf] \u5DF2\u751F\u6210 .ywkf \u76EE\u5F55`);
725
+ }
726
+ /**
727
+ * 生成配置快照
728
+ */
729
+ generateConfigSnapshot() {
730
+ const { outputDir, config } = this.context;
731
+ const configPath = join3(outputDir, "config.json");
732
+ const serializableConfig = JSON.parse(
733
+ JSON.stringify(config, (key, value) => {
734
+ if (typeof value === "function") {
735
+ return "[Function]";
736
+ }
737
+ return value;
738
+ })
739
+ );
740
+ this.writeFileIfChanged(
741
+ configPath,
742
+ JSON.stringify(serializableConfig, null, 2)
743
+ );
744
+ }
745
+ /**
746
+ * 生成约定式路由
747
+ */
748
+ generateRoutes() {
749
+ const { cwd, outputDir, config } = this.context;
750
+ if (!config.router.conventional) {
751
+ return;
752
+ }
753
+ const pagesDir = join3(cwd, config.router.pagesDir || "src/pages");
754
+ const generator = new ConventionalRouteGenerator({
755
+ pagesDir,
756
+ outputDir,
757
+ basename: config.router.basename
758
+ });
759
+ const content = generator.generateCode();
760
+ const routesPath = join3(outputDir, "routes.tsx");
761
+ this.writeFileIfChanged(routesPath, content);
762
+ }
763
+ /**
764
+ * 生成启动文件
765
+ */
766
+ generateBootstrapFile() {
767
+ const { outputDir, config } = this.context;
768
+ const injections = this.collectInjections("bootstrap");
769
+ let content = generateBootstrap(config, injections);
770
+ for (const hooks of this.pluginHooks) {
771
+ if (hooks.modifyBootstrapCode) {
772
+ const result = hooks.modifyBootstrapCode(content, this.context);
773
+ if (result) {
774
+ content = result;
775
+ }
776
+ }
777
+ }
778
+ const bootstrapPath = join3(outputDir, "bootstrap.tsx");
779
+ this.writeFileIfChanged(bootstrapPath, content);
780
+ }
781
+ /**
782
+ * 生成入口文件
783
+ */
784
+ generateEntryFile() {
785
+ const { outputDir, config } = this.context;
786
+ const injections = this.collectInjections("entry");
787
+ let content = generateEntry(config, injections);
788
+ for (const hooks of this.pluginHooks) {
789
+ if (hooks.modifyEntryCode) {
790
+ const result = hooks.modifyEntryCode(content, this.context);
791
+ if (result) {
792
+ content = result;
793
+ }
794
+ }
795
+ }
796
+ const entryPath = join3(outputDir, "index.tsx");
797
+ this.writeFileIfChanged(entryPath, content);
798
+ }
799
+ /**
800
+ * 收集插件代码注入
801
+ */
802
+ collectInjections(type) {
803
+ const result = {
804
+ imports: [],
805
+ topLevel: [],
806
+ exports: []
807
+ };
808
+ const hookName = type === "entry" ? "injectEntry" : "injectBootstrap";
809
+ for (const hooks of this.pluginHooks) {
810
+ const hook = hooks[hookName];
811
+ if (hook) {
812
+ const injection = hook(this.context);
813
+ if (injection) {
814
+ result.imports?.push(...injection.imports || []);
815
+ result.topLevel?.push(...injection.topLevel || []);
816
+ result.exports?.push(...injection.exports || []);
817
+ }
818
+ }
819
+ }
820
+ return result;
821
+ }
822
+ /**
823
+ * 生成插件附加文件
824
+ */
825
+ async generatePluginFiles() {
826
+ const { outputDir } = this.context;
827
+ for (const hooks of this.pluginHooks) {
828
+ if (hooks.generateFiles) {
829
+ const files = hooks.generateFiles(this.context);
830
+ if (files) {
831
+ for (const file of files) {
832
+ const filePath = join3(outputDir, file.path);
833
+ const dir = join3(filePath, "..");
834
+ this.ensureDir(dir);
835
+ this.writeFileIfChanged(filePath, file.content);
836
+ }
837
+ }
838
+ }
839
+ }
840
+ }
841
+ /**
842
+ * 生成类型定义
843
+ */
844
+ generateTypes() {
845
+ const { outputDir, config, cwd } = this.context;
846
+ const envTypesContent = generateEnvTypes(cwd, config);
847
+ this.writeFileIfChanged(
848
+ join3(outputDir, "types", "env.d.ts"),
849
+ envTypesContent
850
+ );
851
+ if (config.router.conventional) {
852
+ const routeTypesContent = generateRouteTypes();
853
+ this.writeFileIfChanged(
854
+ join3(outputDir, "types", "routes.d.ts"),
855
+ routeTypesContent
856
+ );
857
+ }
858
+ }
859
+ /**
860
+ * 确保目录存在
861
+ */
862
+ ensureDir(dir) {
863
+ if (!existsSync4(dir)) {
864
+ mkdirSync2(dir, { recursive: true });
865
+ }
866
+ }
867
+ /**
868
+ * 只在内容变化时写入文件(避免触发不必要的热更新)
869
+ */
870
+ writeFileIfChanged(filePath, content) {
871
+ const normalizedContent = this.normalizeContent(content);
872
+ const lastContent = this.lastGeneratedContent.get(filePath);
873
+ if (lastContent === normalizedContent) {
874
+ return;
875
+ }
876
+ if (existsSync4(filePath)) {
877
+ const existingContent = readFileSync2(filePath, "utf-8");
878
+ if (this.normalizeContent(existingContent) === normalizedContent) {
879
+ this.lastGeneratedContent.set(filePath, normalizedContent);
880
+ return;
881
+ }
882
+ }
883
+ writeFileSync2(filePath, content, "utf-8");
884
+ this.lastGeneratedContent.set(filePath, normalizedContent);
885
+ }
886
+ /**
887
+ * 标准化内容(去掉时间戳等动态部分)
888
+ */
889
+ normalizeContent(content) {
890
+ return content.replace(/\/\/ Generated at: .+/g, "").replace(/\/\*\* Generated at: .+ \*\//g, "");
891
+ }
892
+ };
893
+
894
+ // src/generator/plugin.ts
895
+ var YwkfGeneratorPlugin = class {
896
+ options;
897
+ hasGenerated = false;
898
+ isWatching = false;
899
+ generator = null;
900
+ pluginHooks = [];
901
+ initialized = false;
902
+ constructor(options) {
903
+ this.options = options;
904
+ }
905
+ /**
906
+ * 解析插件配置为插件实例
907
+ */
908
+ async resolvePlugin(pluginConfig) {
909
+ try {
910
+ let plugin;
911
+ let options = {};
912
+ if (typeof pluginConfig === "string") {
913
+ const module = await import(pluginConfig);
914
+ plugin = module.default || module;
915
+ } else if (Array.isArray(pluginConfig)) {
916
+ const [pluginOrName, pluginOptions] = pluginConfig;
917
+ options = pluginOptions;
918
+ if (typeof pluginOrName === "string") {
919
+ const module = await import(pluginOrName);
920
+ plugin = module.default || module;
921
+ } else {
922
+ plugin = pluginOrName;
923
+ }
924
+ } else {
925
+ plugin = pluginConfig;
926
+ }
927
+ if (typeof plugin === "function") {
928
+ plugin = plugin(options);
929
+ }
930
+ return plugin;
931
+ } catch (error) {
932
+ console.error(`[ywkf] \u89E3\u6790\u63D2\u4EF6\u5931\u8D25: ${error}`);
933
+ return null;
934
+ }
935
+ }
936
+ /**
937
+ * 初始化插件钩子
938
+ */
939
+ async initialize() {
940
+ if (this.initialized) {
941
+ return;
942
+ }
943
+ const { cwd, config, isDev, pluginConfigs = [] } = this.options;
944
+ const context = {
945
+ cwd,
946
+ isDev,
947
+ isProd: !isDev,
948
+ config,
949
+ logger: {
950
+ info: (msg) => console.log(`[ywkf] ${msg}`),
951
+ warn: (msg) => console.warn(`[ywkf] ${msg}`),
952
+ error: (msg) => console.error(`[ywkf] ${msg}`),
953
+ debug: (msg) => {
954
+ if (process.env.DEBUG) {
955
+ console.log(`[ywkf:debug] ${msg}`);
956
+ }
957
+ }
958
+ }
959
+ };
960
+ for (const pluginConfig of pluginConfigs) {
961
+ const plugin = await this.resolvePlugin(pluginConfig);
962
+ if (plugin) {
963
+ const hooks = await plugin.setup(context);
964
+ this.pluginHooks.push(hooks);
965
+ console.log(`[ywkf] \u63D2\u4EF6\u5DF2\u52A0\u8F7D: ${plugin.name}`);
966
+ }
967
+ }
968
+ this.generator = new YwkfGenerator(
969
+ {
970
+ cwd: this.options.cwd,
971
+ config: this.options.config,
972
+ outputDir: this.options.outputDir,
973
+ isDev: this.options.isDev
974
+ },
975
+ this.pluginHooks
976
+ );
977
+ this.initialized = true;
978
+ }
979
+ apply(compiler) {
980
+ const pluginName = "YwkfGeneratorPlugin";
981
+ compiler.hooks.beforeCompile.tapAsync(pluginName, async (params, callback) => {
982
+ try {
983
+ await this.initialize();
984
+ if (!this.hasGenerated && this.generator) {
985
+ await this.generator.generate();
986
+ this.hasGenerated = true;
987
+ }
988
+ callback();
989
+ } catch (error) {
990
+ callback(error);
991
+ }
992
+ });
993
+ if (this.options.isDev && !this.isWatching) {
994
+ this.watchPages();
995
+ }
996
+ }
997
+ /**
998
+ * 监听页面目录变化
999
+ */
1000
+ watchPages() {
1001
+ const { config, cwd } = this.options;
1002
+ const pagesDir = join4(cwd, config.router.pagesDir || "src/pages");
1003
+ if (!existsSync5(pagesDir)) {
1004
+ return;
1005
+ }
1006
+ this.isWatching = true;
1007
+ let debounceTimer = null;
1008
+ const watcher = watch(
1009
+ pagesDir,
1010
+ { recursive: true },
1011
+ (eventType, filename) => {
1012
+ if (!filename?.match(/\.(tsx?|jsx?)$/)) {
1013
+ return;
1014
+ }
1015
+ if (debounceTimer) {
1016
+ clearTimeout(debounceTimer);
1017
+ }
1018
+ debounceTimer = setTimeout(async () => {
1019
+ console.log(`[ywkf] \u68C0\u6D4B\u5230\u9875\u9762\u53D8\u5316: ${filename}`);
1020
+ if (this.generator) {
1021
+ await this.generator.generate();
1022
+ }
1023
+ }, 500);
1024
+ }
1025
+ );
1026
+ process.on("exit", () => {
1027
+ watcher.close();
1028
+ });
1029
+ }
1030
+ };
1031
+
1032
+ // src/rspack/base.ts
1033
+ var require2 = createRequire(import.meta.url);
1034
+ var __dirname = dirname(fileURLToPath(import.meta.url));
1035
+ var coreNodeModules = join5(__dirname, "../../node_modules");
1036
+ function createBaseConfig(config, cwd) {
1037
+ const { resolveApp } = createPathResolver(cwd);
1038
+ const {
1039
+ appName,
1040
+ appCName,
1041
+ output,
1042
+ html,
1043
+ alias: userAlias,
1044
+ microFrontend,
1045
+ router
1046
+ } = config;
1047
+ const ywkfOutputDir = resolveApp(".ywkf");
1048
+ const defaultAlias = {
1049
+ "@": resolveApp("src"),
1050
+ "@config": resolveApp("config"),
1051
+ "@store": resolveApp("store"),
1052
+ "@locales": resolveApp("locales"),
1053
+ "@public": resolveApp("public"),
1054
+ // 约定式路由生成的文件
1055
+ "@ywkf/routes": join5(ywkfOutputDir, "routes.tsx"),
1056
+ // 请求层(由 reactQueryPlugin 生成)
1057
+ "@ywkf/request": join5(ywkfOutputDir, "request.ts"),
1058
+ // Store 工具(由 zustandPlugin 生成)
1059
+ "@ywkf/store": join5(ywkfOutputDir, "store.ts")
1060
+ };
1061
+ const alias = { ...defaultAlias, ...userAlias };
1062
+ return {
1063
+ // 使用 .ywkf/index.tsx 作为入口(由框架生成)
1064
+ entry: [join5(ywkfOutputDir, "index.tsx")],
1065
+ resolve: {
1066
+ extensions: [".ts", ".tsx", ".jsx", ".js", ".json", ".mjs"],
1067
+ symlinks: false,
1068
+ alias: {
1069
+ ...alias,
1070
+ "process/browser.js": require2.resolve("process/browser.js"),
1071
+ "process/browser": require2.resolve("process/browser.js"),
1072
+ // 确保 React 系列包从用户项目的 node_modules 解析
1073
+ react: resolveApp("node_modules/react"),
1074
+ "react-dom": resolveApp("node_modules/react-dom"),
1075
+ "react-router": resolveApp("node_modules/react-router")
1076
+ },
1077
+ fallback: {
1078
+ path: require2.resolve("path-browserify"),
1079
+ process: require2.resolve("process/browser.js"),
1080
+ buffer: require2.resolve("buffer/"),
1081
+ util: require2.resolve("util/"),
1082
+ stream: require2.resolve("stream-browserify"),
1083
+ crypto: require2.resolve("crypto-browserify"),
1084
+ zlib: require2.resolve("browserify-zlib"),
1085
+ querystring: require2.resolve("querystring-es3"),
1086
+ url: require2.resolve("url/"),
1087
+ assert: require2.resolve("assert/"),
1088
+ fs: false,
1089
+ net: false,
1090
+ tls: false,
1091
+ os: false,
1092
+ https: false,
1093
+ http: false
1094
+ }
1095
+ },
1096
+ resolveLoader: {
1097
+ modules: [coreNodeModules, "node_modules"]
1098
+ },
1099
+ module: {
1100
+ rules: [
1101
+ {
1102
+ test: /\.m?js$/,
1103
+ resolve: {
1104
+ fullySpecified: false
1105
+ }
1106
+ },
1107
+ {
1108
+ test: /\.[jt]sx?$/,
1109
+ include: [
1110
+ resolveApp("src"),
1111
+ resolveApp("config"),
1112
+ resolveApp("store"),
1113
+ resolveApp("packages"),
1114
+ ywkfOutputDir
1115
+ // 约定式路由生成的文件
1116
+ ],
1117
+ exclude: [resolveApp("node_modules")],
1118
+ use: [
1119
+ {
1120
+ loader: "builtin:swc-loader",
1121
+ options: {
1122
+ jsc: {
1123
+ parser: {
1124
+ syntax: "typescript",
1125
+ tsx: true,
1126
+ decorators: true
1127
+ },
1128
+ transform: {
1129
+ react: {
1130
+ runtime: "automatic"
1131
+ }
1132
+ },
1133
+ target: "es2015"
1134
+ },
1135
+ sourceMaps: true
1136
+ }
1137
+ }
1138
+ ]
1139
+ },
1140
+ {
1141
+ test: /\.(png|jpg|jpeg|gif|webp|m3u8|exr|hdr|json|woff2)$/,
1142
+ include: [resolveApp("public")],
1143
+ exclude: [resolveApp("src"), resolveApp("store")],
1144
+ type: "asset",
1145
+ parser: {
1146
+ dataUrlCondition: {
1147
+ maxSize: 10 * 1024
1148
+ }
1149
+ }
1150
+ },
1151
+ {
1152
+ test: /\.(md)$/,
1153
+ include: [resolveApp("src")],
1154
+ type: "asset/source"
1155
+ },
1156
+ {
1157
+ test: /\.svg$/,
1158
+ use: ["@svgr/webpack"]
1159
+ }
1160
+ ]
1161
+ },
1162
+ plugins: [
1163
+ new rspack.ProvidePlugin({
1164
+ process: "process/browser.js",
1165
+ Buffer: ["buffer", "Buffer"]
1166
+ }),
1167
+ new rspack.DefinePlugin({
1168
+ "process.env": JSON.stringify(process.env)
1169
+ }),
1170
+ new rspack.HtmlRspackPlugin({
1171
+ template: resolveApp(html.template ?? "public/index.html"),
1172
+ filename: "index.html",
1173
+ inject: "body",
1174
+ hash: true,
1175
+ minify: process.env.NODE_ENV === "production",
1176
+ favicon: resolveApp(html.favicon ?? "public/favicon.ico"),
1177
+ templateParameters: {
1178
+ title: html.title ?? appCName,
1179
+ mountRoot: html.mountRoot ?? appName
1180
+ }
1181
+ }),
1182
+ new rspack.CopyRspackPlugin({
1183
+ patterns: [
1184
+ {
1185
+ from: resolveApp("public/images"),
1186
+ to: "public/images",
1187
+ noErrorOnMissing: true
1188
+ }
1189
+ ]
1190
+ }),
1191
+ // .ywkf 目录生成插件(传递用户配置的插件列表)
1192
+ new YwkfGeneratorPlugin({
1193
+ cwd,
1194
+ config,
1195
+ outputDir: ywkfOutputDir,
1196
+ isDev: process.env.NODE_ENV !== "production",
1197
+ pluginConfigs: config.plugins
1198
+ })
1199
+ ].filter(Boolean),
1200
+ output: {
1201
+ assetModuleFilename: "images/[hash][ext]",
1202
+ library: microFrontend.enabled ? `${appCName}-[name]` : void 0,
1203
+ chunkFilename: "[name].[contenthash].js",
1204
+ libraryTarget: microFrontend.enabled ? "umd" : void 0,
1205
+ globalObject: microFrontend.enabled ? "window" : void 0,
1206
+ chunkLoadingGlobal: microFrontend.enabled ? `chunk_global_${appName}` : void 0,
1207
+ publicPath: output.publicPath ?? "/",
1208
+ path: resolveApp(output.path ?? "dist")
1209
+ },
1210
+ ignoreWarnings: [
1211
+ {
1212
+ module: /@testing-library\/react/,
1213
+ message: /export 'act'/
1214
+ }
1215
+ ],
1216
+ devtool: "source-map"
1217
+ };
1218
+ }
1219
+
1220
+ // src/rspack/dev.ts
1221
+ var require3 = createRequire2(import.meta.url);
1222
+ function convertProxyToArray(proxy) {
1223
+ if (!proxy || Object.keys(proxy).length === 0) {
1224
+ return void 0;
1225
+ }
1226
+ return Object.entries(proxy).map(([context, target]) => {
1227
+ if (typeof target === "string") {
1228
+ return {
1229
+ context: [context],
1230
+ target,
1231
+ changeOrigin: true,
1232
+ secure: false
1233
+ };
1234
+ }
1235
+ return {
1236
+ context: [context],
1237
+ changeOrigin: true,
1238
+ secure: false,
1239
+ ...target
1240
+ };
1241
+ });
1242
+ }
1243
+ function createDevConfig(config, cwd) {
1244
+ const baseConfig = createBaseConfig(config, cwd);
1245
+ const { resolveApp } = createPathResolver(cwd);
1246
+ const { dev: dev2, style } = config;
1247
+ const styleRules = {
1248
+ rules: [
1249
+ // Less - antd
1250
+ {
1251
+ test: /\.less$/,
1252
+ include: [
1253
+ /[\\/]node_modules[\\/].*antd/,
1254
+ /[\\/]node_modules[\\/]@4399ywkf[\\/]design/
1255
+ ],
1256
+ use: [
1257
+ { loader: "style-loader" },
1258
+ {
1259
+ loader: "css-loader",
1260
+ options: { sourceMap: true }
1261
+ },
1262
+ {
1263
+ loader: "less-loader",
1264
+ options: {
1265
+ sourceMap: true,
1266
+ lessOptions: {
1267
+ strictMath: false,
1268
+ math: "always",
1269
+ javascriptEnabled: true
1270
+ }
1271
+ }
1272
+ }
1273
+ ]
1274
+ },
1275
+ // Less - 项目文件
1276
+ ...style.less?.enabled !== false ? [
1277
+ {
1278
+ test: /\.less$/,
1279
+ include: [resolveApp("src")],
1280
+ exclude: [resolveApp("node_modules")],
1281
+ oneOf: [
1282
+ {
1283
+ test: /\.module\.less$/,
1284
+ use: [
1285
+ { loader: "style-loader" },
1286
+ {
1287
+ loader: "css-loader",
1288
+ options: {
1289
+ sourceMap: true,
1290
+ modules: {
1291
+ localIdentName: "[path][name]__[local]--[hash:base64:5]"
1292
+ },
1293
+ importLoaders: 2
1294
+ }
1295
+ },
1296
+ {
1297
+ loader: "less-loader",
1298
+ options: {
1299
+ sourceMap: true,
1300
+ lessOptions: {
1301
+ javascriptEnabled: true,
1302
+ math: "always",
1303
+ ...style.less?.lessOptions
1304
+ }
1305
+ }
1306
+ }
1307
+ ]
1308
+ },
1309
+ {
1310
+ use: [
1311
+ { loader: "style-loader" },
1312
+ {
1313
+ loader: "css-loader",
1314
+ options: { sourceMap: true }
1315
+ },
1316
+ {
1317
+ loader: "less-loader",
1318
+ options: {
1319
+ sourceMap: true,
1320
+ lessOptions: {
1321
+ javascriptEnabled: true,
1322
+ ...style.less?.lessOptions
1323
+ }
1324
+ }
1325
+ }
1326
+ ]
1327
+ }
1328
+ ]
1329
+ }
1330
+ ] : [],
1331
+ // Sass
1332
+ ...style.sass?.enabled !== false ? [
1333
+ {
1334
+ test: /\.s[ac]ss$/i,
1335
+ include: [resolveApp("src")],
1336
+ exclude: [resolveApp("node_modules")],
1337
+ oneOf: [
1338
+ {
1339
+ test: /\.module\.s[ac]ss$/,
1340
+ use: [
1341
+ { loader: "style-loader" },
1342
+ {
1343
+ loader: "css-loader",
1344
+ options: {
1345
+ sourceMap: true,
1346
+ modules: {
1347
+ localIdentName: "[path][name]__[local]--[hash:base64:5]"
1348
+ },
1349
+ importLoaders: 2
1350
+ }
1351
+ },
1352
+ {
1353
+ loader: "sass-loader",
1354
+ options: {
1355
+ sourceMap: true,
1356
+ sassOptions: {
1357
+ outputStyle: "compressed",
1358
+ ...style.sass?.sassOptions
1359
+ }
1360
+ }
1361
+ }
1362
+ ]
1363
+ },
1364
+ {
1365
+ use: [
1366
+ { loader: "style-loader" },
1367
+ {
1368
+ loader: "css-loader",
1369
+ options: { sourceMap: true }
1370
+ },
1371
+ {
1372
+ loader: "sass-loader",
1373
+ options: {
1374
+ sourceMap: true,
1375
+ sassOptions: {
1376
+ outputStyle: "compressed",
1377
+ ...style.sass?.sassOptions
1378
+ }
1379
+ }
1380
+ }
1381
+ ]
1382
+ }
1383
+ ]
1384
+ }
1385
+ ] : [],
1386
+ // TailwindCSS
1387
+ ...style.tailwindcss ? [
1388
+ {
1389
+ test: /\.css$/,
1390
+ include: [resolveApp("src/index.css")],
1391
+ use: [
1392
+ "style-loader",
1393
+ "css-loader",
1394
+ {
1395
+ loader: "postcss-loader",
1396
+ options: {
1397
+ postcssOptions: {
1398
+ config: resolveApp("postcss.config.js")
1399
+ }
1400
+ }
1401
+ }
1402
+ ]
1403
+ }
1404
+ ] : [],
1405
+ // 其他 CSS
1406
+ {
1407
+ test: /\.css$/,
1408
+ include: [resolveApp("src"), resolveApp("node_modules")],
1409
+ exclude: style.tailwindcss ? [resolveApp("src/index.css")] : [],
1410
+ use: [
1411
+ { loader: "style-loader" },
1412
+ {
1413
+ loader: "css-loader",
1414
+ options: { sourceMap: true }
1415
+ }
1416
+ ]
1417
+ }
1418
+ ]
1419
+ };
1420
+ const devConfig = {
1421
+ mode: "development",
1422
+ devtool: "inline-source-map",
1423
+ output: {
1424
+ filename: "[name].bundle.js",
1425
+ clean: false
1426
+ },
1427
+ stats: "errors-only",
1428
+ devServer: {
1429
+ host: dev2.host,
1430
+ port: dev2.port,
1431
+ compress: true,
1432
+ historyApiFallback: true,
1433
+ hot: true,
1434
+ allowedHosts: "all",
1435
+ client: {
1436
+ overlay: false,
1437
+ progress: true
1438
+ },
1439
+ proxy: convertProxyToArray(dev2.proxy)
1440
+ },
1441
+ module: styleRules
1442
+ };
1443
+ return merge(baseConfig, devConfig);
1444
+ }
1445
+
1446
+ // src/rspack/prod.ts
1447
+ import { rspack as rspack2 } from "@rspack/core";
1448
+ import { merge as merge2 } from "webpack-merge";
1449
+ function createProdConfig(config, cwd) {
1450
+ const baseConfig = createBaseConfig(config, cwd);
1451
+ const { resolveApp } = createPathResolver(cwd);
1452
+ const { style, performance, output } = config;
1453
+ const styleRules = {
1454
+ rules: [
1455
+ // Less - antd
1456
+ {
1457
+ test: /\.less$/,
1458
+ include: [
1459
+ /[\\/]node_modules[\\/].*antd/,
1460
+ /[\\/]node_modules[\\/]@4399ywkf[\\/]design/
1461
+ ],
1462
+ use: [
1463
+ { loader: rspack2.CssExtractRspackPlugin.loader },
1464
+ {
1465
+ loader: "css-loader",
1466
+ options: { sourceMap: true }
1467
+ },
1468
+ {
1469
+ loader: "less-loader",
1470
+ options: {
1471
+ sourceMap: true,
1472
+ lessOptions: {
1473
+ strictMath: false,
1474
+ math: "always",
1475
+ javascriptEnabled: true
1476
+ }
1477
+ }
1478
+ }
1479
+ ]
1480
+ },
1481
+ // Less - 项目文件
1482
+ ...style.less?.enabled !== false ? [
1483
+ {
1484
+ test: /\.less$/,
1485
+ include: [resolveApp("src")],
1486
+ exclude: [resolveApp("node_modules")],
1487
+ oneOf: [
1488
+ {
1489
+ test: /\.module\.less$/,
1490
+ use: [
1491
+ { loader: rspack2.CssExtractRspackPlugin.loader },
1492
+ {
1493
+ loader: "css-loader",
1494
+ options: {
1495
+ sourceMap: true,
1496
+ modules: {
1497
+ localIdentName: "[path][name]__[local]--[hash:base64:5]"
1498
+ },
1499
+ importLoaders: 2
1500
+ }
1501
+ },
1502
+ {
1503
+ loader: "less-loader",
1504
+ options: {
1505
+ sourceMap: true,
1506
+ lessOptions: {
1507
+ javascriptEnabled: true,
1508
+ ...style.less?.lessOptions
1509
+ }
1510
+ }
1511
+ }
1512
+ ]
1513
+ },
1514
+ {
1515
+ use: [
1516
+ { loader: rspack2.CssExtractRspackPlugin.loader },
1517
+ {
1518
+ loader: "css-loader",
1519
+ options: { sourceMap: true }
1520
+ },
1521
+ {
1522
+ loader: "less-loader",
1523
+ options: {
1524
+ sourceMap: true,
1525
+ lessOptions: {
1526
+ javascriptEnabled: true,
1527
+ ...style.less?.lessOptions
1528
+ }
1529
+ }
1530
+ }
1531
+ ]
1532
+ }
1533
+ ]
1534
+ }
1535
+ ] : [],
1536
+ // Sass
1537
+ ...style.sass?.enabled !== false ? [
1538
+ {
1539
+ test: /\.s[ac]ss$/i,
1540
+ include: [resolveApp("src")],
1541
+ exclude: [resolveApp("node_modules")],
1542
+ oneOf: [
1543
+ {
1544
+ test: /\.module\.s[ac]ss$/,
1545
+ use: [
1546
+ { loader: rspack2.CssExtractRspackPlugin.loader },
1547
+ {
1548
+ loader: "css-loader",
1549
+ options: {
1550
+ sourceMap: true,
1551
+ modules: {
1552
+ localIdentName: "[path][name]__[local]--[hash:base64:5]"
1553
+ },
1554
+ importLoaders: 2
1555
+ }
1556
+ },
1557
+ {
1558
+ loader: "sass-loader",
1559
+ options: {
1560
+ sourceMap: true,
1561
+ sassOptions: {
1562
+ outputStyle: "compressed",
1563
+ ...style.sass?.sassOptions
1564
+ }
1565
+ }
1566
+ }
1567
+ ]
1568
+ },
1569
+ {
1570
+ use: [
1571
+ { loader: rspack2.CssExtractRspackPlugin.loader },
1572
+ {
1573
+ loader: "css-loader",
1574
+ options: { sourceMap: true }
1575
+ },
1576
+ {
1577
+ loader: "sass-loader",
1578
+ options: {
1579
+ sourceMap: true,
1580
+ sassOptions: {
1581
+ outputStyle: "compressed",
1582
+ ...style.sass?.sassOptions
1583
+ }
1584
+ }
1585
+ }
1586
+ ]
1587
+ }
1588
+ ]
1589
+ }
1590
+ ] : [],
1591
+ // TailwindCSS
1592
+ ...style.tailwindcss ? [
1593
+ {
1594
+ test: /\.css$/,
1595
+ include: [resolveApp("src/index.css")],
1596
+ use: [
1597
+ { loader: rspack2.CssExtractRspackPlugin.loader },
1598
+ "css-loader",
1599
+ {
1600
+ loader: "postcss-loader",
1601
+ options: {
1602
+ postcssOptions: {
1603
+ config: resolveApp("postcss.config.js")
1604
+ }
1605
+ }
1606
+ }
1607
+ ]
1608
+ }
1609
+ ] : [],
1610
+ // src 目录中的其他 CSS
1611
+ {
1612
+ test: /\.css$/,
1613
+ include: [resolveApp("src")],
1614
+ exclude: style.tailwindcss ? [resolveApp("src/index.css")] : [],
1615
+ use: [
1616
+ { loader: rspack2.CssExtractRspackPlugin.loader },
1617
+ {
1618
+ loader: "css-loader",
1619
+ options: { sourceMap: true }
1620
+ }
1621
+ ]
1622
+ },
1623
+ // node_modules CSS
1624
+ {
1625
+ test: /\.css$/,
1626
+ include: [resolveApp("node_modules")],
1627
+ use: [
1628
+ { loader: "style-loader" },
1629
+ {
1630
+ loader: "css-loader",
1631
+ options: { sourceMap: true }
1632
+ }
1633
+ ]
1634
+ }
1635
+ ]
1636
+ };
1637
+ const prodConfig = {
1638
+ mode: "production",
1639
+ devtool: "hidden-source-map",
1640
+ output: {
1641
+ filename: "[name].[contenthash].bundle.js",
1642
+ chunkFilename: "[name].[contenthash].chunk.js",
1643
+ clean: output.clean
1644
+ },
1645
+ module: styleRules,
1646
+ plugins: [
1647
+ new rspack2.CssExtractRspackPlugin({
1648
+ filename: "[name].[contenthash:8].css",
1649
+ chunkFilename: "[name].[contenthash:8].chunk.css"
1650
+ })
1651
+ ],
1652
+ optimization: {
1653
+ minimize: true,
1654
+ minimizer: [
1655
+ new rspack2.SwcJsMinimizerRspackPlugin({
1656
+ exclude: [resolveApp("node_modules")],
1657
+ minimizerOptions: {
1658
+ compress: {
1659
+ pure_funcs: performance.dropConsole ? ["console.log", "console.info", "console.debug", "console.warn"] : ["console.info", "console.debug"],
1660
+ drop_console: false,
1661
+ drop_debugger: true
1662
+ }
1663
+ }
1664
+ }),
1665
+ new rspack2.LightningCssMinimizerRspackPlugin()
1666
+ ]
1667
+ }
1668
+ };
1669
+ return merge2(baseConfig, prodConfig);
1670
+ }
1671
+
1672
+ // src/rspack/index.ts
1673
+ function createRspackConfig(config, cwd, options = {}) {
1674
+ const isDev = options.isDev ?? process.env.NODE_ENV !== "production";
1675
+ let rspackConfig = isDev ? createDevConfig(config, cwd) : createProdConfig(config, cwd);
1676
+ if (config.performance.rsdoctor) {
1677
+ rspackConfig.plugins = [
1678
+ ...rspackConfig.plugins || [],
1679
+ new RsdoctorRspackPlugin({})
1680
+ ];
1681
+ }
1682
+ if (config.tools.rspack) {
1683
+ const userConfig = config.tools.rspack(rspackConfig, {
1684
+ isDev,
1685
+ isProd: !isDev
1686
+ });
1687
+ if (userConfig) {
1688
+ rspackConfig = userConfig;
1689
+ }
1690
+ }
1691
+ return rspackConfig;
1692
+ }
1693
+
1694
+ // src/router/plugin.ts
1695
+ import { join as join6 } from "path";
1696
+ import { watch as watch2, existsSync as existsSync6 } from "fs";
1697
+ var ConventionalRoutePlugin = class {
1698
+ options;
1699
+ isWatching = false;
1700
+ hasGenerated = false;
1701
+ lastGeneratedContent = "";
1702
+ constructor(options) {
1703
+ this.options = options;
1704
+ }
1705
+ apply(compiler) {
1706
+ const pluginName = "ConventionalRoutePlugin";
1707
+ compiler.hooks.beforeCompile.tapAsync(pluginName, (params, callback) => {
1708
+ if (!this.hasGenerated) {
1709
+ this.generateRoutes();
1710
+ this.hasGenerated = true;
1711
+ }
1712
+ callback();
1713
+ });
1714
+ if (this.options.watch && !this.isWatching) {
1715
+ this.watchPages();
1716
+ }
1717
+ }
1718
+ /**
1719
+ * 生成路由文件(带内容比对,避免不必要的重复生成)
1720
+ */
1721
+ generateRoutes() {
1722
+ try {
1723
+ const generator = new ConventionalRouteGenerator({
1724
+ pagesDir: this.options.pagesDir,
1725
+ outputDir: this.options.outputDir,
1726
+ basename: this.options.basename
1727
+ });
1728
+ const newContent = generator.generateCode();
1729
+ const outputPath = join6(this.options.outputDir, "routes.tsx");
1730
+ const normalizedNew = this.normalizeContent(newContent);
1731
+ const normalizedOld = this.normalizeContent(this.lastGeneratedContent);
1732
+ if (normalizedNew === normalizedOld) {
1733
+ return;
1734
+ }
1735
+ generator.write();
1736
+ this.lastGeneratedContent = newContent;
1737
+ } catch (error) {
1738
+ console.error("[ywkf] \u751F\u6210\u8DEF\u7531\u5931\u8D25:", error);
1739
+ }
1740
+ }
1741
+ /**
1742
+ * 标准化内容(去掉时间戳等动态部分)
1743
+ */
1744
+ normalizeContent(content) {
1745
+ return content.replace(/\/\/ Generated at: .+/g, "");
1746
+ }
1747
+ /**
1748
+ * 监听页面目录变化
1749
+ */
1750
+ watchPages() {
1751
+ if (!existsSync6(this.options.pagesDir)) {
1752
+ return;
1753
+ }
1754
+ this.isWatching = true;
1755
+ let debounceTimer = null;
1756
+ const watcher = watch2(
1757
+ this.options.pagesDir,
1758
+ { recursive: true },
1759
+ (eventType, filename) => {
1760
+ if (!filename?.match(/\.(tsx?|jsx?)$/)) {
1761
+ return;
1762
+ }
1763
+ if (debounceTimer) {
1764
+ clearTimeout(debounceTimer);
1765
+ }
1766
+ debounceTimer = setTimeout(() => {
1767
+ console.log(`[ywkf] \u68C0\u6D4B\u5230\u9875\u9762\u53D8\u5316: ${filename}`);
1768
+ this.generateRoutes();
1769
+ }, 500);
1770
+ }
1771
+ );
1772
+ process.on("exit", () => {
1773
+ watcher.close();
1774
+ });
1775
+ }
1776
+ };
1777
+
1778
+ // src/runtime/context.tsx
1779
+ import { createContext, useContext } from "react";
1780
+ import { jsx } from "react/jsx-runtime";
1781
+ var defaultContextValue = {
1782
+ appName: "app",
1783
+ basename: "/",
1784
+ isDev: process.env.NODE_ENV === "development",
1785
+ env: {}
1786
+ };
1787
+ var AppContext = createContext(defaultContextValue);
1788
+ function AppContextProvider({
1789
+ value,
1790
+ children
1791
+ }) {
1792
+ const contextValue = {
1793
+ ...defaultContextValue,
1794
+ ...value,
1795
+ env: {
1796
+ ...defaultContextValue.env,
1797
+ ...value.env
1798
+ }
1799
+ };
1800
+ return /* @__PURE__ */ jsx(AppContext.Provider, { value: contextValue, children });
1801
+ }
1802
+ function useApp() {
1803
+ const context = useContext(AppContext);
1804
+ if (!context) {
1805
+ throw new Error("useApp must be used within AppContextProvider");
1806
+ }
1807
+ return context;
1808
+ }
1809
+ function useAppName() {
1810
+ return useApp().appName;
1811
+ }
1812
+ function useBasename() {
1813
+ return useApp().basename;
1814
+ }
1815
+ function useEnv() {
1816
+ return useApp().env;
1817
+ }
1818
+ function useIsDev() {
1819
+ return useApp().isDev;
1820
+ }
1821
+
1822
+ // src/runtime/error-boundary.tsx
1823
+ import { Component } from "react";
1824
+ import { jsx as jsx2, jsxs } from "react/jsx-runtime";
1825
+ var ErrorBoundary = class extends Component {
1826
+ constructor(props) {
1827
+ super(props);
1828
+ this.state = { hasError: false, error: null };
1829
+ }
1830
+ static getDerivedStateFromError(error) {
1831
+ return { hasError: true, error };
1832
+ }
1833
+ componentDidCatch(error, errorInfo) {
1834
+ console.error("[ErrorBoundary] Caught error:", error, errorInfo);
1835
+ this.props.onError?.(error, errorInfo);
1836
+ }
1837
+ reset = () => {
1838
+ this.setState({ hasError: false, error: null });
1839
+ };
1840
+ render() {
1841
+ const { hasError, error } = this.state;
1842
+ const { children, fallback } = this.props;
1843
+ if (hasError && error) {
1844
+ if (typeof fallback === "function") {
1845
+ return fallback(error, this.reset);
1846
+ }
1847
+ if (fallback) {
1848
+ return fallback;
1849
+ }
1850
+ return /* @__PURE__ */ jsx2(DefaultErrorFallback, { error, onReset: this.reset });
1851
+ }
1852
+ return children;
1853
+ }
1854
+ };
1855
+ function DefaultErrorFallback({ error, onReset }) {
1856
+ const isDev = process.env.NODE_ENV === "development";
1857
+ return /* @__PURE__ */ jsx2(
1858
+ "div",
1859
+ {
1860
+ style: {
1861
+ padding: 24,
1862
+ display: "flex",
1863
+ flexDirection: "column",
1864
+ alignItems: "center",
1865
+ justifyContent: "center",
1866
+ minHeight: "100vh",
1867
+ backgroundColor: "#f5f5f5"
1868
+ },
1869
+ children: /* @__PURE__ */ jsxs(
1870
+ "div",
1871
+ {
1872
+ style: {
1873
+ maxWidth: 600,
1874
+ padding: 32,
1875
+ backgroundColor: "#fff",
1876
+ borderRadius: 8,
1877
+ boxShadow: "0 2px 8px rgba(0,0,0,0.1)"
1878
+ },
1879
+ children: [
1880
+ /* @__PURE__ */ jsx2("h1", { style: { color: "#ff4d4f", marginBottom: 16 }, children: "\u9875\u9762\u51FA\u9519\u4E86" }),
1881
+ /* @__PURE__ */ jsx2("p", { style: { color: "#666", marginBottom: 16 }, children: "\u62B1\u6B49\uFF0C\u9875\u9762\u9047\u5230\u4E86\u4E00\u4E9B\u95EE\u9898\u3002\u8BF7\u5C1D\u8BD5\u5237\u65B0\u9875\u9762\u6216\u8054\u7CFB\u7BA1\u7406\u5458\u3002" }),
1882
+ isDev && /* @__PURE__ */ jsxs(
1883
+ "details",
1884
+ {
1885
+ style: {
1886
+ marginBottom: 16,
1887
+ padding: 12,
1888
+ backgroundColor: "#fff2f0",
1889
+ borderRadius: 4,
1890
+ border: "1px solid #ffccc7"
1891
+ },
1892
+ children: [
1893
+ /* @__PURE__ */ jsx2("summary", { style: { cursor: "pointer", fontWeight: "bold" }, children: "\u9519\u8BEF\u8BE6\u60C5\uFF08\u4EC5\u5F00\u53D1\u73AF\u5883\u53EF\u89C1\uFF09" }),
1894
+ /* @__PURE__ */ jsxs(
1895
+ "pre",
1896
+ {
1897
+ style: {
1898
+ marginTop: 8,
1899
+ padding: 8,
1900
+ backgroundColor: "#fff",
1901
+ borderRadius: 4,
1902
+ overflow: "auto",
1903
+ fontSize: 12
1904
+ },
1905
+ children: [
1906
+ error.message,
1907
+ "\n\n",
1908
+ error.stack
1909
+ ]
1910
+ }
1911
+ )
1912
+ ]
1913
+ }
1914
+ ),
1915
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", gap: 8 }, children: [
1916
+ /* @__PURE__ */ jsx2(
1917
+ "button",
1918
+ {
1919
+ onClick: onReset,
1920
+ style: {
1921
+ padding: "8px 16px",
1922
+ backgroundColor: "#1890ff",
1923
+ color: "#fff",
1924
+ border: "none",
1925
+ borderRadius: 4,
1926
+ cursor: "pointer"
1927
+ },
1928
+ children: "\u91CD\u8BD5"
1929
+ }
1930
+ ),
1931
+ /* @__PURE__ */ jsx2(
1932
+ "button",
1933
+ {
1934
+ onClick: () => window.location.reload(),
1935
+ style: {
1936
+ padding: "8px 16px",
1937
+ backgroundColor: "#fff",
1938
+ color: "#666",
1939
+ border: "1px solid #d9d9d9",
1940
+ borderRadius: 4,
1941
+ cursor: "pointer"
1942
+ },
1943
+ children: "\u5237\u65B0\u9875\u9762"
1944
+ }
1945
+ )
1946
+ ] })
1947
+ ]
1948
+ }
1949
+ )
1950
+ }
1951
+ );
1952
+ }
1953
+
1954
+ // src/runtime/providers.tsx
1955
+ import {
1956
+ StrictMode,
1957
+ Suspense
1958
+ } from "react";
1959
+ import { RouterProvider } from "react-router";
1960
+ import { ConfigProvider } from "antd";
1961
+ import zhCN from "antd/locale/zh_CN.js";
1962
+ import { jsx as jsx3 } from "react/jsx-runtime";
1963
+ function DefaultLoading() {
1964
+ return /* @__PURE__ */ jsx3(
1965
+ "div",
1966
+ {
1967
+ style: {
1968
+ display: "flex",
1969
+ alignItems: "center",
1970
+ justifyContent: "center",
1971
+ height: "100vh",
1972
+ fontSize: 16,
1973
+ color: "#999"
1974
+ },
1975
+ children: "\u52A0\u8F7D\u4E2D..."
1976
+ }
1977
+ );
1978
+ }
1979
+ function composeProviders(providers) {
1980
+ const sortedProviders = [...providers].sort(
1981
+ (a, b) => (a.order ?? 100) - (b.order ?? 100)
1982
+ );
1983
+ return function ComposedProviders({ children }) {
1984
+ return sortedProviders.reduceRight((acc, { component: Provider, props }) => {
1985
+ return /* @__PURE__ */ jsx3(Provider, { ...props, children: acc });
1986
+ }, children);
1987
+ };
1988
+ }
1989
+ function RootProvider({ config, children }) {
1990
+ const {
1991
+ appName = "app",
1992
+ router,
1993
+ basename: basename2 = "/",
1994
+ strictMode = true,
1995
+ antd = { enabled: true },
1996
+ providers = [],
1997
+ lifecycle
1998
+ } = config;
1999
+ const appContextValue = {
2000
+ appName,
2001
+ basename: basename2,
2002
+ isDev: process.env.NODE_ENV === "development",
2003
+ env: typeof process !== "undefined" ? process.env : {}
2004
+ };
2005
+ const allProviders = [
2006
+ // 应用上下文 Provider(最外层)
2007
+ {
2008
+ component: AppContextProvider,
2009
+ props: { value: appContextValue },
2010
+ order: 0
2011
+ },
2012
+ // Ant Design ConfigProvider
2013
+ ...antd.enabled !== false ? [
2014
+ {
2015
+ component: ConfigProvider,
2016
+ props: {
2017
+ locale: antd.locale || zhCN,
2018
+ theme: antd.theme,
2019
+ ...antd.configProvider
2020
+ },
2021
+ order: 10
2022
+ }
2023
+ ] : [],
2024
+ // 用户自定义 Providers
2025
+ ...providers.map((p) => ({ ...p, order: p.order ?? 50 }))
2026
+ ];
2027
+ const ComposedProviders = composeProviders(allProviders);
2028
+ const content = router ? /* @__PURE__ */ jsx3(Suspense, { fallback: /* @__PURE__ */ jsx3(DefaultLoading, {}), children: /* @__PURE__ */ jsx3(RouterProvider, { router }) }) : children;
2029
+ const app = /* @__PURE__ */ jsx3(ErrorBoundary, { onError: lifecycle?.onError, children: /* @__PURE__ */ jsx3(ComposedProviders, { children: content }) });
2030
+ if (strictMode) {
2031
+ return /* @__PURE__ */ jsx3(StrictMode, { children: app });
2032
+ }
2033
+ return app;
2034
+ }
2035
+ function createProvider(component, props, order) {
2036
+ return {
2037
+ component,
2038
+ props,
2039
+ order
2040
+ };
2041
+ }
2042
+
2043
+ // src/runtime/bootstrap.tsx
2044
+ import { createRoot } from "react-dom/client";
2045
+ import { jsx as jsx4 } from "react/jsx-runtime";
2046
+ var root = null;
2047
+ async function resolveAppConfig(config) {
2048
+ if (config.router || !config.conventionalRoutes) {
2049
+ return config;
2050
+ }
2051
+ try {
2052
+ const routesModule = await import("@ywkf/routes");
2053
+ const createRouter = routesModule.createRouter || routesModule.default?.createRouter;
2054
+ if (typeof createRouter === "function") {
2055
+ const router = createRouter(config.basename);
2056
+ console.log("[ywkf] \u5DF2\u81EA\u52A8\u6CE8\u5165\u7EA6\u5B9A\u5F0F\u8DEF\u7531");
2057
+ return { ...config, router };
2058
+ } else {
2059
+ console.warn("[ywkf] @ywkf/routes \u672A\u5BFC\u51FA createRouter \u51FD\u6570");
2060
+ }
2061
+ } catch (error) {
2062
+ console.error("[ywkf] \u52A0\u8F7D\u7EA6\u5B9A\u5F0F\u8DEF\u7531\u5931\u8D25:", error);
2063
+ console.warn("[ywkf] \u8BF7\u786E\u4FDD\u5DF2\u542F\u7528\u7EA6\u5B9A\u5F0F\u8DEF\u7531\u4E14 src/pages \u76EE\u5F55\u5B58\u5728");
2064
+ }
2065
+ return config;
2066
+ }
2067
+ async function bootstrap(config) {
2068
+ const { rootId = "root", lifecycle } = config;
2069
+ const resolvedConfig = await resolveAppConfig(config);
2070
+ if (lifecycle?.onBeforeMount) {
2071
+ await lifecycle.onBeforeMount();
2072
+ }
2073
+ const rootElement = document.getElementById(rootId);
2074
+ if (!rootElement) {
2075
+ throw new Error(`\u627E\u4E0D\u5230\u6839\u5143\u7D20 #${rootId}`);
2076
+ }
2077
+ root = createRoot(rootElement);
2078
+ root.render(/* @__PURE__ */ jsx4(RootProvider, { config: resolvedConfig }));
2079
+ if (lifecycle?.onMounted) {
2080
+ setTimeout(() => {
2081
+ lifecycle.onMounted?.();
2082
+ }, 0);
2083
+ }
2084
+ if (lifecycle?.onUnmount) {
2085
+ window.addEventListener("beforeunload", () => {
2086
+ lifecycle.onUnmount?.();
2087
+ });
2088
+ }
2089
+ }
2090
+ function unmount() {
2091
+ if (root) {
2092
+ root.unmount();
2093
+ root = null;
2094
+ }
2095
+ }
2096
+ function createMicroApp(getConfig) {
2097
+ let microRoot = null;
2098
+ return {
2099
+ /**
2100
+ * 微前端 bootstrap 生命周期
2101
+ */
2102
+ async bootstrap() {
2103
+ console.log("[MicroApp] bootstrap");
2104
+ },
2105
+ /**
2106
+ * 微前端 mount 生命周期
2107
+ */
2108
+ async mount(props) {
2109
+ console.log("[MicroApp] mount", props);
2110
+ const config = getConfig(props);
2111
+ const resolvedConfig = await resolveAppConfig(config);
2112
+ const container = props?.masterProps?.container;
2113
+ const rootId = resolvedConfig.rootId || "root";
2114
+ const rootElement = container ? container.querySelector(`#${rootId}`) : document.getElementById(rootId);
2115
+ if (!rootElement) {
2116
+ throw new Error(`[MicroApp] \u627E\u4E0D\u5230\u6839\u5143\u7D20 #${rootId}`);
2117
+ }
2118
+ if (resolvedConfig.lifecycle?.onBeforeMount) {
2119
+ await resolvedConfig.lifecycle.onBeforeMount();
2120
+ }
2121
+ microRoot = createRoot(rootElement);
2122
+ microRoot.render(/* @__PURE__ */ jsx4(RootProvider, { config: resolvedConfig }));
2123
+ if (resolvedConfig.lifecycle?.onMounted) {
2124
+ setTimeout(() => {
2125
+ resolvedConfig.lifecycle?.onMounted?.();
2126
+ }, 0);
2127
+ }
2128
+ },
2129
+ /**
2130
+ * 微前端 unmount 生命周期
2131
+ */
2132
+ async unmount(props) {
2133
+ console.log("[MicroApp] unmount", props);
2134
+ const config = getConfig(props);
2135
+ if (config.lifecycle?.onUnmount) {
2136
+ config.lifecycle.onUnmount();
2137
+ }
2138
+ if (microRoot) {
2139
+ microRoot.unmount();
2140
+ microRoot = null;
2141
+ }
2142
+ },
2143
+ /**
2144
+ * 微前端 update 生命周期(可选)
2145
+ */
2146
+ async update(props) {
2147
+ console.log("[MicroApp] update", props);
2148
+ }
2149
+ };
2150
+ }
2151
+ function isMicroAppEnv() {
2152
+ if (window.__POWERED_BY_QIANKUN__) {
2153
+ return true;
2154
+ }
2155
+ if (window.__GARFISH__) {
2156
+ return true;
2157
+ }
2158
+ return false;
2159
+ }
2160
+ function getMicroAppPublicPath() {
2161
+ if (window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__) {
2162
+ return window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__;
2163
+ }
2164
+ return "/";
2165
+ }
2166
+
2167
+ // src/plugin/define.ts
2168
+ function definePlugin(plugin) {
2169
+ return plugin;
2170
+ }
2171
+ function createPlugin(factory) {
2172
+ return factory;
2173
+ }
2174
+
2175
+ // src/plugin/manager.ts
2176
+ function createLogger(pluginName) {
2177
+ const prefix = `[${pluginName}]`;
2178
+ return {
2179
+ info: (msg) => console.log(`${prefix} ${msg}`),
2180
+ warn: (msg) => console.warn(`${prefix} ${msg}`),
2181
+ error: (msg) => console.error(`${prefix} ${msg}`),
2182
+ debug: (msg) => {
2183
+ if (process.env.DEBUG) {
2184
+ console.debug(`${prefix} ${msg}`);
2185
+ }
2186
+ }
2187
+ };
2188
+ }
2189
+ async function resolvePlugin(pluginConfig, cwd) {
2190
+ let plugin;
2191
+ let options = {};
2192
+ if (typeof pluginConfig === "string") {
2193
+ const module = await import(pluginConfig);
2194
+ plugin = module.default || module;
2195
+ } else if (Array.isArray(pluginConfig)) {
2196
+ const [pluginOrName, pluginOptions] = pluginConfig;
2197
+ options = pluginOptions;
2198
+ if (typeof pluginOrName === "string") {
2199
+ const module = await import(pluginOrName);
2200
+ plugin = module.default || module;
2201
+ } else {
2202
+ plugin = pluginOrName;
2203
+ }
2204
+ } else {
2205
+ plugin = pluginConfig;
2206
+ }
2207
+ if (typeof plugin === "function") {
2208
+ plugin = plugin(options);
2209
+ }
2210
+ return { plugin, options };
2211
+ }
2212
+ var PluginManager = class {
2213
+ plugins = /* @__PURE__ */ new Map();
2214
+ context;
2215
+ constructor(config, cwd, isDev) {
2216
+ this.context = {
2217
+ cwd,
2218
+ isDev,
2219
+ isProd: !isDev,
2220
+ config,
2221
+ logger: createLogger("PluginManager")
2222
+ };
2223
+ }
2224
+ /**
2225
+ * 加载并初始化所有插件
2226
+ */
2227
+ async loadPlugins(pluginConfigs) {
2228
+ for (const pluginConfig of pluginConfigs) {
2229
+ try {
2230
+ const { plugin } = await resolvePlugin(pluginConfig, this.context.cwd);
2231
+ if (this.plugins.has(plugin.name)) {
2232
+ this.context.logger.warn(`\u63D2\u4EF6 ${plugin.name} \u5DF2\u52A0\u8F7D\uFF0C\u8DF3\u8FC7\u91CD\u590D\u52A0\u8F7D`);
2233
+ continue;
2234
+ }
2235
+ const pluginContext = {
2236
+ ...this.context,
2237
+ logger: createLogger(plugin.name)
2238
+ };
2239
+ const hooks = await plugin.setup(pluginContext);
2240
+ this.plugins.set(plugin.name, { plugin, hooks });
2241
+ this.context.logger.info(`\u5DF2\u52A0\u8F7D\u63D2\u4EF6: ${plugin.name}`);
2242
+ } catch (error) {
2243
+ this.context.logger.error(
2244
+ `\u52A0\u8F7D\u63D2\u4EF6\u5931\u8D25: ${String(pluginConfig)} - ${error}`
2245
+ );
2246
+ }
2247
+ }
2248
+ }
2249
+ /**
2250
+ * 执行 modifyRspackConfig 钩子
2251
+ */
2252
+ async applyRspackConfigHooks(config) {
2253
+ let result = config;
2254
+ for (const [name, { hooks }] of this.plugins) {
2255
+ if (hooks.modifyRspackConfig) {
2256
+ try {
2257
+ const modified = await hooks.modifyRspackConfig(result, this.context);
2258
+ if (modified) {
2259
+ result = modified;
2260
+ }
2261
+ } catch (error) {
2262
+ this.context.logger.error(
2263
+ `\u63D2\u4EF6 ${name} modifyRspackConfig \u6267\u884C\u5931\u8D25: ${error}`
2264
+ );
2265
+ }
2266
+ }
2267
+ }
2268
+ return result;
2269
+ }
2270
+ /**
2271
+ * 执行 modifyRoutes 钩子
2272
+ */
2273
+ async applyRoutesHooks(routes) {
2274
+ let result = routes;
2275
+ for (const [name, { hooks }] of this.plugins) {
2276
+ if (hooks.modifyRoutes) {
2277
+ try {
2278
+ const modified = await hooks.modifyRoutes(result, this.context);
2279
+ if (modified) {
2280
+ result = modified;
2281
+ }
2282
+ } catch (error) {
2283
+ this.context.logger.error(
2284
+ `\u63D2\u4EF6 ${name} modifyRoutes \u6267\u884C\u5931\u8D25: ${error}`
2285
+ );
2286
+ }
2287
+ }
2288
+ }
2289
+ return result;
2290
+ }
2291
+ /**
2292
+ * 执行 modifyAppConfig 钩子
2293
+ */
2294
+ applyAppConfigHooks(appConfig) {
2295
+ let result = appConfig;
2296
+ for (const [name, { hooks }] of this.plugins) {
2297
+ if (hooks.modifyAppConfig) {
2298
+ try {
2299
+ const modified = hooks.modifyAppConfig(result, this.context);
2300
+ if (modified) {
2301
+ result = modified;
2302
+ }
2303
+ } catch (error) {
2304
+ this.context.logger.error(
2305
+ `\u63D2\u4EF6 ${name} modifyAppConfig \u6267\u884C\u5931\u8D25: ${error}`
2306
+ );
2307
+ }
2308
+ }
2309
+ }
2310
+ return result;
2311
+ }
2312
+ /**
2313
+ * 收集所有插件的 Provider
2314
+ */
2315
+ collectProviders() {
2316
+ const providers = [];
2317
+ for (const [name, { hooks }] of this.plugins) {
2318
+ if (hooks.addProvider) {
2319
+ try {
2320
+ const result = hooks.addProvider(this.context);
2321
+ if (Array.isArray(result)) {
2322
+ providers.push(...result);
2323
+ } else if (result) {
2324
+ providers.push(result);
2325
+ }
2326
+ } catch (error) {
2327
+ this.context.logger.error(
2328
+ `\u63D2\u4EF6 ${name} addProvider \u6267\u884C\u5931\u8D25: ${error}`
2329
+ );
2330
+ }
2331
+ }
2332
+ }
2333
+ return providers;
2334
+ }
2335
+ /**
2336
+ * 执行 beforeBuild 钩子
2337
+ */
2338
+ async runBeforeBuild() {
2339
+ for (const [name, { hooks }] of this.plugins) {
2340
+ if (hooks.beforeBuild) {
2341
+ try {
2342
+ await hooks.beforeBuild(this.context);
2343
+ } catch (error) {
2344
+ this.context.logger.error(
2345
+ `\u63D2\u4EF6 ${name} beforeBuild \u6267\u884C\u5931\u8D25: ${error}`
2346
+ );
2347
+ }
2348
+ }
2349
+ }
2350
+ }
2351
+ /**
2352
+ * 执行 afterBuild 钩子
2353
+ */
2354
+ async runAfterBuild(stats) {
2355
+ for (const [name, { hooks }] of this.plugins) {
2356
+ if (hooks.afterBuild) {
2357
+ try {
2358
+ await hooks.afterBuild(this.context, stats);
2359
+ } catch (error) {
2360
+ this.context.logger.error(
2361
+ `\u63D2\u4EF6 ${name} afterBuild \u6267\u884C\u5931\u8D25: ${error}`
2362
+ );
2363
+ }
2364
+ }
2365
+ }
2366
+ }
2367
+ /**
2368
+ * 执行 beforeDevServer 钩子
2369
+ */
2370
+ async runBeforeDevServer() {
2371
+ for (const [name, { hooks }] of this.plugins) {
2372
+ if (hooks.beforeDevServer) {
2373
+ try {
2374
+ await hooks.beforeDevServer(this.context);
2375
+ } catch (error) {
2376
+ this.context.logger.error(
2377
+ `\u63D2\u4EF6 ${name} beforeDevServer \u6267\u884C\u5931\u8D25: ${error}`
2378
+ );
2379
+ }
2380
+ }
2381
+ }
2382
+ }
2383
+ /**
2384
+ * 执行 afterDevServer 钩子
2385
+ */
2386
+ async runAfterDevServer(server) {
2387
+ for (const [name, { hooks }] of this.plugins) {
2388
+ if (hooks.afterDevServer) {
2389
+ try {
2390
+ await hooks.afterDevServer(this.context, server);
2391
+ } catch (error) {
2392
+ this.context.logger.error(
2393
+ `\u63D2\u4EF6 ${name} afterDevServer \u6267\u884C\u5931\u8D25: ${error}`
2394
+ );
2395
+ }
2396
+ }
2397
+ }
2398
+ }
2399
+ /**
2400
+ * 获取所有已加载的插件名称
2401
+ */
2402
+ getPluginNames() {
2403
+ return Array.from(this.plugins.keys());
2404
+ }
2405
+ /**
2406
+ * 获取所有已加载的插件
2407
+ */
2408
+ getPlugins() {
2409
+ return Array.from(this.plugins.values()).map((p) => p.plugin);
2410
+ }
2411
+ /**
2412
+ * 获取所有已加载的插件钩子
2413
+ */
2414
+ getPluginHooks() {
2415
+ return Array.from(this.plugins.values()).map((p) => p.hooks);
2416
+ }
2417
+ };
2418
+
2419
+ // src/plugin/builtin/garfish.ts
2420
+ var garfishPlugin = createPlugin((options = {}) => ({
2421
+ name: "@4399ywkf/plugin-garfish",
2422
+ version: "1.0.0",
2423
+ description: "Garfish \u5FAE\u524D\u7AEF\u63D2\u4EF6",
2424
+ setup(context) {
2425
+ const { appName, master = false, apps = [], sandbox = {} } = options;
2426
+ const { config, logger, isDev } = context;
2427
+ const finalAppName = appName || config.appName;
2428
+ const hooks = {
2429
+ // ===== 构建阶段钩子 =====
2430
+ modifyRspackConfig(rspackConfig) {
2431
+ if (!master) {
2432
+ rspackConfig.output = {
2433
+ ...rspackConfig.output,
2434
+ library: finalAppName,
2435
+ libraryTarget: "umd",
2436
+ globalObject: "window",
2437
+ chunkLoadingGlobal: `garfish_${finalAppName}`
2438
+ };
2439
+ logger.info(`\u914D\u7F6E UMD \u8F93\u51FA: ${finalAppName}`);
2440
+ }
2441
+ return rspackConfig;
2442
+ },
2443
+ beforeDevServer() {
2444
+ if (master) {
2445
+ logger.info("Garfish \u4E3B\u5E94\u7528\u6A21\u5F0F");
2446
+ logger.info(`\u5B50\u5E94\u7528\u5217\u8868: ${apps.map((a) => a.name).join(", ")}`);
2447
+ } else {
2448
+ logger.info(`Garfish \u5B50\u5E94\u7528\u6A21\u5F0F: ${finalAppName}`);
2449
+ }
2450
+ },
2451
+ // ===== 代码生成阶段钩子 =====
2452
+ injectEntry(ctx) {
2453
+ if (master) {
2454
+ return {};
2455
+ }
2456
+ return {
2457
+ imports: [
2458
+ `import { microApp, isMicroAppEnv } from "./bootstrap";`
2459
+ ],
2460
+ exports: [
2461
+ `// Garfish \u5FAE\u524D\u7AEF\u751F\u547D\u5468\u671F\u5BFC\u51FA`,
2462
+ `export const { mount, unmount } = microApp;`,
2463
+ `export const provider = microApp;`,
2464
+ `export default microApp;`
2465
+ ],
2466
+ topLevel: [
2467
+ `// Garfish \u5FAE\u524D\u7AEF\uFF1A\u72EC\u7ACB\u8FD0\u884C\u5224\u65AD`,
2468
+ `const shouldRunIndependently = !isMicroAppEnv();`
2469
+ ]
2470
+ };
2471
+ },
2472
+ injectBootstrap(ctx) {
2473
+ const imports = [
2474
+ `import { createMicroApp, isMicroAppEnv } from "@4399ywkf/core/runtime";`
2475
+ ];
2476
+ const exports = [
2477
+ `/**`,
2478
+ ` * Garfish \u5FAE\u524D\u7AEF\u5E94\u7528\u5B9E\u4F8B`,
2479
+ ` */`,
2480
+ `export const microApp = createMicroApp(createAppConfig);`,
2481
+ ``,
2482
+ `/**`,
2483
+ ` * \u5224\u65AD\u662F\u5426\u5728\u5FAE\u524D\u7AEF\u73AF\u5883`,
2484
+ ` */`,
2485
+ `export { isMicroAppEnv };`
2486
+ ];
2487
+ const topLevel = [];
2488
+ if (master && apps.length > 0) {
2489
+ imports.push(`import Garfish from "garfish";`);
2490
+ topLevel.push(generateMasterInitCode(apps, config.router.basename));
2491
+ }
2492
+ return { imports, exports, topLevel };
2493
+ },
2494
+ modifyBootstrapCode(code, ctx) {
2495
+ if (!master) {
2496
+ return code.replace(
2497
+ /antd:\s*\{\s*enabled:\s*true/,
2498
+ "antd: { enabled: false"
2499
+ );
2500
+ }
2501
+ return code;
2502
+ },
2503
+ // ===== 运行时阶段钩子 =====
2504
+ modifyAppConfig(appConfig) {
2505
+ return {
2506
+ ...appConfig,
2507
+ // 微前端模式下禁用 antd 样式注入(由主应用管理)
2508
+ antd: {
2509
+ ...appConfig.antd,
2510
+ enabled: master
2511
+ }
2512
+ };
2513
+ }
2514
+ };
2515
+ return hooks;
2516
+ }
2517
+ }));
2518
+ function generateMasterInitCode(apps, basename2) {
2519
+ const appConfigs = apps.map(
2520
+ (app) => `{
2521
+ name: "${app.name}",
2522
+ entry: "${app.entry}",
2523
+ activeWhen: "${app.activeRule}",
2524
+ ${app.basename ? `basename: "${app.basename}",` : ""}
2525
+ }`
2526
+ ).join(",\n ");
2527
+ return `
2528
+ /**
2529
+ * Garfish \u4E3B\u5E94\u7528\u521D\u59CB\u5316
2530
+ * \u5728 runApp \u4E4B\u524D\u8C03\u7528
2531
+ */
2532
+ export async function initGarfishMaster(): Promise<void> {
2533
+ await Garfish.run({
2534
+ basename: "${basename2 || "/"}",
2535
+ apps: [
2536
+ ${appConfigs}
2537
+ ],
2538
+ });
2539
+ }
2540
+ `;
2541
+ }
2542
+
2543
+ // src/plugin/builtin/tailwind.ts
2544
+ import { existsSync as existsSync7, writeFileSync as writeFileSync3 } from "fs";
2545
+ import { join as join7 } from "path";
2546
+ var tailwindPlugin = createPlugin((options = {}) => ({
2547
+ name: "@4399ywkf/plugin-tailwind",
2548
+ version: "1.0.0",
2549
+ description: "Tailwind CSS \u96C6\u6210\u63D2\u4EF6",
2550
+ setup(context) {
2551
+ const {
2552
+ darkModeSelector = '&:where([data-theme="dark"], [data-theme="dark"] *)',
2553
+ autoConfig = true,
2554
+ extraCSS = ""
2555
+ } = options;
2556
+ const { cwd, logger } = context;
2557
+ if (autoConfig) {
2558
+ ensurePostcssConfig(cwd, logger);
2559
+ }
2560
+ const hooks = {
2561
+ modifyRspackConfig(rspackConfig) {
2562
+ logger.info("Tailwind CSS \u5DF2\u542F\u7528");
2563
+ const rules = rspackConfig.module?.rules || [];
2564
+ const postcssConfigPath = join7(cwd, "postcss.config.js");
2565
+ const isProd = rspackConfig.mode === "production";
2566
+ const tailwindRule = {
2567
+ test: /tailwind\.css$/,
2568
+ use: [
2569
+ isProd ? "mini-css-extract-plugin/loader" : "style-loader",
2570
+ "css-loader",
2571
+ {
2572
+ loader: "postcss-loader",
2573
+ options: {
2574
+ postcssOptions: {
2575
+ config: postcssConfigPath
2576
+ }
2577
+ }
2578
+ }
2579
+ ]
2580
+ };
2581
+ rules.unshift(tailwindRule);
2582
+ rspackConfig.module = { ...rspackConfig.module, rules };
2583
+ return rspackConfig;
2584
+ },
2585
+ generateFiles(ctx) {
2586
+ const cssContent = buildTailwindCSS(darkModeSelector, extraCSS);
2587
+ return [
2588
+ {
2589
+ path: "tailwind.css",
2590
+ content: cssContent
2591
+ }
2592
+ ];
2593
+ },
2594
+ injectEntry(ctx) {
2595
+ return {
2596
+ imports: [
2597
+ `import "./tailwind.css";`
2598
+ ]
2599
+ };
2600
+ }
2601
+ };
2602
+ return hooks;
2603
+ }
2604
+ }));
2605
+ function buildTailwindCSS(darkModeSelector, extraCSS) {
2606
+ return `/* \u6B64\u6587\u4EF6\u7531 @4399ywkf/plugin-tailwind \u81EA\u52A8\u751F\u6210 */
2607
+ @import "tailwindcss";
2608
+ @variant dark (${darkModeSelector});
2609
+ ${extraCSS ? `
2610
+ ${extraCSS}` : ""}
2611
+ `;
2612
+ }
2613
+ function ensurePostcssConfig(cwd, logger) {
2614
+ const configPath = join7(cwd, "postcss.config.js");
2615
+ if (!existsSync7(configPath)) {
2616
+ writeFileSync3(
2617
+ configPath,
2618
+ `module.exports = {
2619
+ plugins: {
2620
+ "@tailwindcss/postcss": {},
2621
+ },
2622
+ };
2623
+ `,
2624
+ "utf-8"
2625
+ );
2626
+ logger.info("\u5DF2\u81EA\u52A8\u751F\u6210 postcss.config.js");
2627
+ }
2628
+ }
2629
+
2630
+ // src/plugin/builtin/i18n.ts
2631
+ import { existsSync as existsSync8, mkdirSync as mkdirSync3, writeFileSync as writeFileSync4 } from "fs";
2632
+ import { join as join8 } from "path";
2633
+ var i18nPlugin = createPlugin((options = {}) => ({
2634
+ name: "@4399ywkf/plugin-i18n",
2635
+ version: "1.0.0",
2636
+ description: "\u56FD\u9645\u5316 (i18next) \u63D2\u4EF6",
2637
+ setup(context) {
2638
+ const {
2639
+ defaultLocale = "zh-CN",
2640
+ locales = ["zh-CN", "en-US"],
2641
+ localesDir = "locales",
2642
+ defaultNS = ["common"],
2643
+ autoScaffold = true
2644
+ } = options;
2645
+ const { cwd, logger } = context;
2646
+ if (autoScaffold) {
2647
+ scaffoldLocaleFiles(cwd, localesDir, locales, defaultNS, logger);
2648
+ }
2649
+ const hooks = {
2650
+ modifyRspackConfig(rspackConfig) {
2651
+ const aliases = rspackConfig.resolve?.alias || {};
2652
+ if (!aliases["@locales"]) {
2653
+ aliases["@locales"] = join8(cwd, localesDir);
2654
+ rspackConfig.resolve = { ...rspackConfig.resolve, alias: aliases };
2655
+ }
2656
+ return rspackConfig;
2657
+ },
2658
+ generateFiles(ctx) {
2659
+ return [
2660
+ {
2661
+ path: "i18n.ts",
2662
+ content: generateI18nCode(defaultLocale, locales, localesDir, defaultNS)
2663
+ }
2664
+ ];
2665
+ },
2666
+ injectBootstrap(ctx) {
2667
+ return {
2668
+ imports: [
2669
+ `import { initI18n } from "./i18n";`
2670
+ ],
2671
+ topLevel: [
2672
+ `// \u521D\u59CB\u5316 i18n\uFF08\u5728\u5E94\u7528\u542F\u52A8\u524D\uFF09`,
2673
+ `await initI18n();`
2674
+ ]
2675
+ };
2676
+ }
2677
+ };
2678
+ return hooks;
2679
+ }
2680
+ }));
2681
+ function generateI18nCode(defaultLocale, locales, localesDir, defaultNS) {
2682
+ return `// \u6B64\u6587\u4EF6\u7531 @4399ywkf/plugin-i18n \u81EA\u52A8\u751F\u6210
2683
+ import i18n from "i18next";
2684
+ import LanguageDetector from "i18next-browser-languagedetector";
2685
+ import resourcesToBackend from "i18next-resources-to-backend";
2686
+ import { initReactI18next } from "react-i18next";
2687
+
2688
+ export const DEFAULT_LOCALE = "${defaultLocale}";
2689
+
2690
+ export const SUPPORTED_LOCALES = ${JSON.stringify(locales)} as const;
2691
+
2692
+ export type SupportedLocale = typeof SUPPORTED_LOCALES[number];
2693
+
2694
+ const instance = i18n
2695
+ .use(initReactI18next)
2696
+ .use(LanguageDetector)
2697
+ .use(
2698
+ resourcesToBackend(async (lng: string, ns: string) => {
2699
+ return import(\`@locales/\${normalizeLocale(lng)}/\${ns}.json\`);
2700
+ })
2701
+ );
2702
+
2703
+ function normalizeLocale(locale?: string): string {
2704
+ if (!locale) return DEFAULT_LOCALE;
2705
+ for (const l of SUPPORTED_LOCALES) {
2706
+ if (l.startsWith(locale) || locale.startsWith(l.split("-")[0])) {
2707
+ return l;
2708
+ }
2709
+ }
2710
+ return DEFAULT_LOCALE;
2711
+ }
2712
+
2713
+ let initialized = false;
2714
+
2715
+ export async function initI18n(lang?: string): Promise<typeof i18n> {
2716
+ if (initialized) return instance;
2717
+
2718
+ await instance.init({
2719
+ defaultNS: ${JSON.stringify(defaultNS)},
2720
+ fallbackLng: DEFAULT_LOCALE,
2721
+ interpolation: { escapeValue: false },
2722
+ lng: lang,
2723
+ });
2724
+
2725
+ initialized = true;
2726
+ return instance;
2727
+ }
2728
+
2729
+ export { instance as i18n };
2730
+ export default instance;
2731
+ `;
2732
+ }
2733
+ function scaffoldLocaleFiles(cwd, localesDir, locales, namespaces, logger) {
2734
+ const baseDir = join8(cwd, localesDir);
2735
+ for (const locale of locales) {
2736
+ const localeDir = join8(baseDir, locale);
2737
+ if (!existsSync8(localeDir)) {
2738
+ mkdirSync3(localeDir, { recursive: true });
2739
+ }
2740
+ for (const ns of namespaces) {
2741
+ const filePath = join8(localeDir, `${ns}.json`);
2742
+ if (!existsSync8(filePath)) {
2743
+ const isDefault = locale === locales[0];
2744
+ const content = isDefault ? JSON.stringify({ welcome: "\u6B22\u8FCE\u4F7F\u7528" }, null, 2) : JSON.stringify({ welcome: "Welcome" }, null, 2);
2745
+ writeFileSync4(filePath, content + "\n", "utf-8");
2746
+ logger.info(`\u5DF2\u751F\u6210\u7FFB\u8BD1\u6587\u4EF6: ${localesDir}/${locale}/${ns}.json`);
2747
+ }
2748
+ }
2749
+ }
2750
+ }
2751
+
2752
+ // src/plugin/builtin/theme.ts
2753
+ var themePlugin = createPlugin((options = {}) => ({
2754
+ name: "@4399ywkf/plugin-theme",
2755
+ version: "1.0.0",
2756
+ description: "antd-style \u4E3B\u9898\u7CFB\u7EDF\u63D2\u4EF6",
2757
+ setup(context) {
2758
+ const {
2759
+ darkMode = true,
2760
+ defaultAppearance = "auto",
2761
+ primaryColor = "blue",
2762
+ prefixCls = "ant",
2763
+ cssVar = true,
2764
+ globalReset = true
2765
+ } = options;
2766
+ const { logger } = context;
2767
+ logger.info(`\u4E3B\u9898\u6A21\u5F0F: ${defaultAppearance}, \u4E3B\u8272: ${primaryColor}`);
2768
+ const hooks = {
2769
+ generateFiles(ctx) {
2770
+ return [
2771
+ {
2772
+ path: "theme.tsx",
2773
+ content: generateThemeProvider({
2774
+ darkMode,
2775
+ defaultAppearance,
2776
+ primaryColor,
2777
+ prefixCls,
2778
+ cssVar,
2779
+ globalReset
2780
+ })
2781
+ }
2782
+ ];
2783
+ },
2784
+ injectBootstrap(ctx) {
2785
+ return {
2786
+ imports: [
2787
+ `import { ThemeWrapper } from "./theme";`
2788
+ ]
2789
+ };
2790
+ }
2791
+ // Provider 由生成的 theme.tsx 文件在用户层使用
2792
+ // 用户可以在 src/app.config.ts 中通过 providers 引入 ThemeWrapper
2793
+ };
2794
+ return hooks;
2795
+ }
2796
+ }));
2797
+ function generateThemeProvider(opts) {
2798
+ const { darkMode, defaultAppearance, primaryColor, prefixCls, cssVar, globalReset } = opts;
2799
+ return `// \u6B64\u6587\u4EF6\u7531 @4399ywkf/plugin-theme \u81EA\u52A8\u751F\u6210
2800
+ import React, { useEffect, type ReactNode } from "react";
2801
+ import { ThemeProvider, createGlobalStyle } from "antd-style";
2802
+
2803
+ ${globalReset ? GLOBAL_RESET_CODE : ""}
2804
+
2805
+ const DEFAULT_APPEARANCE = "${defaultAppearance}" as const;
2806
+
2807
+ interface ThemeWrapperProps {
2808
+ children: ReactNode;
2809
+ }
2810
+
2811
+ /**
2812
+ * \u4E3B\u9898\u5305\u88F9\u7EC4\u4EF6
2813
+ * \u7531 themePlugin \u81EA\u52A8\u6CE8\u5165\u5230\u5E94\u7528\u542F\u52A8\u5C42
2814
+ */
2815
+ export function ThemeWrapper({ children }: ThemeWrapperProps) {
2816
+ ${darkMode ? DARK_MODE_EFFECT : ""}
2817
+
2818
+ return (
2819
+ <ThemeProvider
2820
+ prefixCls="${prefixCls}"
2821
+ ${defaultAppearance !== "auto" ? `appearance="${defaultAppearance}"` : ""}
2822
+ theme={{
2823
+ cssVar: ${cssVar},
2824
+ token: {
2825
+ colorPrimary: "${primaryColor}",
2826
+ },
2827
+ }}
2828
+ themeMode={DEFAULT_APPEARANCE}
2829
+ >
2830
+ ${globalReset ? "<GlobalReset />" : ""}
2831
+ {children}
2832
+ </ThemeProvider>
2833
+ );
2834
+ }
2835
+
2836
+ export default ThemeWrapper;
2837
+ `;
2838
+ }
2839
+ var GLOBAL_RESET_CODE = `
2840
+ const GlobalReset = createGlobalStyle\`
2841
+ *,
2842
+ *::before,
2843
+ *::after {
2844
+ box-sizing: border-box;
2845
+ }
2846
+
2847
+ html, body, #root, #app {
2848
+ height: 100%;
2849
+ margin: 0;
2850
+ padding: 0;
2851
+ }
2852
+
2853
+ body {
2854
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
2855
+ "Helvetica Neue", Arial, "Noto Sans", sans-serif;
2856
+ -webkit-font-smoothing: antialiased;
2857
+ -moz-osx-font-smoothing: grayscale;
2858
+ }
2859
+ \`;
2860
+ `;
2861
+ var DARK_MODE_EFFECT = `
2862
+ useEffect(() => {
2863
+ if (DEFAULT_APPEARANCE !== "auto") {
2864
+ document.documentElement.dataset.theme = DEFAULT_APPEARANCE;
2865
+ return;
2866
+ }
2867
+
2868
+ const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
2869
+ document.documentElement.dataset.theme = mediaQuery.matches ? "dark" : "light";
2870
+
2871
+ function handleChange(e: MediaQueryListEvent) {
2872
+ document.documentElement.dataset.theme = e.matches ? "dark" : "light";
2873
+ }
2874
+
2875
+ mediaQuery.addEventListener("change", handleChange);
2876
+ return () => mediaQuery.removeEventListener("change", handleChange);
2877
+ }, []);
2878
+ `;
2879
+
2880
+ // src/plugin/builtin/mock.ts
2881
+ import { resolve as resolve2, join as join9 } from "path";
2882
+ import { existsSync as existsSync9, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
2883
+ var mockPlugin = createPlugin((options = {}) => ({
2884
+ name: "@4399ywkf/plugin-mock",
2885
+ version: "1.0.0",
2886
+ description: "Mock \u6570\u636E\u63D2\u4EF6",
2887
+ setup(context) {
2888
+ const {
2889
+ mockDir = "mock",
2890
+ enableInProd = false,
2891
+ delay = 0,
2892
+ prefix = ""
2893
+ } = options;
2894
+ const { cwd, isDev, logger } = context;
2895
+ if (!isDev && !enableInProd) {
2896
+ logger.info("\u751F\u4EA7\u73AF\u5883\u5DF2\u7981\u7528 Mock");
2897
+ return {};
2898
+ }
2899
+ const mockPath = resolve2(cwd, mockDir);
2900
+ if (!existsSync9(mockPath)) {
2901
+ logger.warn(`Mock \u76EE\u5F55\u4E0D\u5B58\u5728: ${mockPath}`);
2902
+ return {};
2903
+ }
2904
+ const hooks = {
2905
+ modifyRspackConfig(rspackConfig) {
2906
+ if (isDev && rspackConfig.devServer) {
2907
+ const mockFiles = scanMockFiles(mockPath);
2908
+ logger.info(`\u627E\u5230 ${mockFiles.length} \u4E2A Mock \u6587\u4EF6`);
2909
+ rspackConfig.devServer.setupMiddlewares = (middlewares, devServer) => {
2910
+ middlewares.unshift({
2911
+ name: "mock-middleware",
2912
+ middleware: createMockMiddleware(mockPath, { delay, prefix, logger })
2913
+ });
2914
+ return middlewares;
2915
+ };
2916
+ }
2917
+ return rspackConfig;
2918
+ },
2919
+ beforeDevServer() {
2920
+ logger.info(`Mock \u5DF2\u542F\u7528\uFF0C\u76EE\u5F55: ${mockPath}`);
2921
+ if (delay > 0) {
2922
+ logger.info(`\u6A21\u62DF\u5EF6\u8FDF: ${delay}ms`);
2923
+ }
2924
+ }
2925
+ };
2926
+ return hooks;
2927
+ }
2928
+ }));
2929
+ function scanMockFiles(dir) {
2930
+ const files = [];
2931
+ if (!existsSync9(dir)) {
2932
+ return files;
2933
+ }
2934
+ const entries = readdirSync2(dir);
2935
+ for (const entry of entries) {
2936
+ const fullPath = join9(dir, entry);
2937
+ const stat = statSync2(fullPath);
2938
+ if (stat.isFile() && /\.(ts|js|mjs)$/.test(entry)) {
2939
+ files.push(fullPath);
2940
+ } else if (stat.isDirectory()) {
2941
+ files.push(...scanMockFiles(fullPath));
2942
+ }
2943
+ }
2944
+ return files;
2945
+ }
2946
+ function createMockMiddleware(mockPath, options) {
2947
+ const { delay } = options;
2948
+ scanMockFiles(mockPath);
2949
+ return async (req, res, next) => {
2950
+ if (delay > 0) {
2951
+ await new Promise((resolve4) => setTimeout(resolve4, delay));
2952
+ }
2953
+ next();
2954
+ };
2955
+ }
2956
+
2957
+ // src/plugin/builtin/analytics.ts
2958
+ var analyticsPlugin = createPlugin((options = {}) => ({
2959
+ name: "@4399ywkf/plugin-analytics",
2960
+ version: "1.0.0",
2961
+ description: "\u6784\u5EFA\u5206\u6790\u63D2\u4EF6",
2962
+ setup(context) {
2963
+ const {
2964
+ buildAnalysis = true,
2965
+ timing = true,
2966
+ bundleSize = true,
2967
+ sizeWarningThreshold = 500
2968
+ } = options;
2969
+ const { logger, isProd } = context;
2970
+ let buildStartTime;
2971
+ const hooks = {
2972
+ beforeBuild() {
2973
+ if (timing) {
2974
+ buildStartTime = Date.now();
2975
+ logger.info("\u5F00\u59CB\u6784\u5EFA...");
2976
+ }
2977
+ },
2978
+ afterBuild(_context, stats) {
2979
+ if (timing) {
2980
+ const duration = Date.now() - buildStartTime;
2981
+ logger.info(`\u6784\u5EFA\u5B8C\u6210\uFF0C\u8017\u65F6: ${(duration / 1e3).toFixed(2)}s`);
2982
+ }
2983
+ if (!stats.success && stats.errors) {
2984
+ logger.error(`\u6784\u5EFA\u5931\u8D25\uFF0C\u9519\u8BEF\u6570: ${stats.errors.length}`);
2985
+ }
2986
+ },
2987
+ modifyRspackConfig(config) {
2988
+ if (buildAnalysis && isProd) {
2989
+ logger.info("\u6784\u5EFA\u5206\u6790\u5DF2\u542F\u7528");
2990
+ }
2991
+ return config;
2992
+ }
2993
+ };
2994
+ return hooks;
2995
+ }
2996
+ }));
2997
+
2998
+ // src/plugin/builtin/react-query.ts
2999
+ var reactQueryPlugin = createPlugin((options = {}) => ({
3000
+ name: "@4399ywkf/plugin-react-query",
3001
+ version: "1.0.0",
3002
+ description: "React Query + Axios \u8BF7\u6C42\u5C42\u96C6\u6210",
3003
+ setup(context) {
3004
+ const {
3005
+ staleTime = 5 * 60 * 1e3,
3006
+ gcTime = 10 * 60 * 1e3,
3007
+ retry = 1,
3008
+ devtools = true,
3009
+ baseURL = "",
3010
+ timeout = 15e3
3011
+ } = options;
3012
+ const { logger, isDev } = context;
3013
+ const hooks = {
3014
+ generateFiles(ctx) {
3015
+ logger.info("React Query \u5DF2\u542F\u7528");
3016
+ const files = [
3017
+ {
3018
+ path: "query-client.ts",
3019
+ content: buildQueryClientFile({ staleTime, gcTime, retry, devtools, isDev })
3020
+ },
3021
+ {
3022
+ path: "request.ts",
3023
+ content: buildRequestFile({ baseURL, timeout })
3024
+ }
3025
+ ];
3026
+ return files;
3027
+ },
3028
+ injectBootstrap(ctx) {
3029
+ return {
3030
+ imports: [
3031
+ `import { QueryClientProvider } from "@tanstack/react-query";`,
3032
+ `import { queryClient } from "./query-client";`
3033
+ ],
3034
+ topLevel: [
3035
+ `// React Query Provider\uFF08\u7531 @4399ywkf/plugin-react-query \u6CE8\u5165\uFF09`
3036
+ ]
3037
+ };
3038
+ },
3039
+ modifyBootstrapCode(code) {
3040
+ const providerEntry = ` {
3041
+ component: QueryClientProvider as React.ComponentType<{ children: React.ReactNode }>,
3042
+ props: { client: queryClient },
3043
+ order: 20,
3044
+ }`;
3045
+ if (code.includes("providers: []")) {
3046
+ code = code.replace(
3047
+ "providers: []",
3048
+ `providers: [
3049
+ ${providerEntry},
3050
+ ]`
3051
+ );
3052
+ } else if (code.includes("providers: [")) {
3053
+ code = code.replace(
3054
+ "providers: [",
3055
+ `providers: [
3056
+ ${providerEntry},`
3057
+ );
3058
+ }
3059
+ if (!code.includes("import React")) {
3060
+ code = code.replace(
3061
+ `import { bootstrap`,
3062
+ `import React from "react";
3063
+ import { bootstrap`
3064
+ );
3065
+ }
3066
+ return code;
3067
+ }
3068
+ };
3069
+ return hooks;
3070
+ }
3071
+ }));
3072
+ function buildQueryClientFile(opts) {
3073
+ const { staleTime, gcTime, retry, devtools, isDev } = opts;
3074
+ return `// \u6B64\u6587\u4EF6\u7531 @4399ywkf/plugin-react-query \u81EA\u52A8\u751F\u6210
3075
+ import { QueryClient } from "@tanstack/react-query";
3076
+
3077
+ /**
3078
+ * \u5168\u5C40 QueryClient \u5B9E\u4F8B
3079
+ *
3080
+ * \u9ED8\u8BA4\u914D\u7F6E\u53EF\u5728 ywkf.config.ts \u7684 reactQueryPlugin \u9009\u9879\u4E2D\u4FEE\u6539\u3002
3081
+ * \u8FD0\u884C\u65F6\u81EA\u5B9A\u4E49\u53EF\u901A\u8FC7 src/app.config.ts \u8986\u76D6\u3002
3082
+ */
3083
+ export const queryClient = new QueryClient({
3084
+ defaultOptions: {
3085
+ queries: {
3086
+ staleTime: ${staleTime},
3087
+ gcTime: ${gcTime},
3088
+ retry: ${typeof retry === "boolean" ? retry : retry},
3089
+ refetchOnWindowFocus: false,
3090
+ },
3091
+ mutations: {
3092
+ retry: false,
3093
+ },
3094
+ },
30
3095
  });
31
- module.exports = __toCommonJS(src_exports);
32
- __reExport(src_exports, require("./config/config"), module.exports);
33
- __reExport(src_exports, require("./route/route"), module.exports);
34
- var import_generator = require("./service/generator");
35
- __reExport(src_exports, require("./service/pluginAPI"), module.exports);
36
- __reExport(src_exports, require("./service/service"), module.exports);
37
- var import_types = require("./types");
38
- // Annotate the CommonJS export names for ESM import in node:
39
- 0 && (module.exports = {
40
- Env,
41
- Generator,
42
- GeneratorType,
43
- IAdd,
44
- IEvent,
45
- IModify,
46
- IRoute,
47
- ...require("./config/config"),
48
- ...require("./route/route"),
49
- ...require("./service/pluginAPI"),
50
- ...require("./service/service")
3096
+
3097
+ export default queryClient;
3098
+ `;
3099
+ }
3100
+ function buildRequestFile(opts) {
3101
+ const { baseURL, timeout } = opts;
3102
+ return `// \u6B64\u6587\u4EF6\u7531 @4399ywkf/plugin-react-query \u81EA\u52A8\u751F\u6210
3103
+ import axios, { type AxiosInstance, type AxiosRequestConfig, type InternalAxiosRequestConfig, type AxiosResponse, type AxiosError } from "axios";
3104
+
3105
+ /**
3106
+ * Axios \u5B9E\u4F8B
3107
+ *
3108
+ * \u57FA\u7840\u914D\u7F6E\u7531\u63D2\u4EF6\u751F\u6210\uFF0C\u53EF\u5728 src/app.config.ts \u4E2D\u901A\u8FC7
3109
+ * \`configureRequest(request)\` \u81EA\u5B9A\u4E49\u62E6\u622A\u5668\u3002
3110
+ */
3111
+ export const request: AxiosInstance = axios.create({
3112
+ baseURL: "${baseURL}" || import.meta.env.VITE_API_BASE_URL || "",
3113
+ timeout: ${timeout},
3114
+ headers: {
3115
+ "Content-Type": "application/json",
3116
+ },
3117
+ });
3118
+
3119
+ // ============ \u8BF7\u6C42\u62E6\u622A\u5668 ============
3120
+
3121
+ request.interceptors.request.use(
3122
+ (config: InternalAxiosRequestConfig) => {
3123
+ // Token \u6CE8\u5165\uFF08\u4ECE localStorage \u8BFB\u53D6\uFF0C\u53EF\u6309\u9700\u66FF\u6362\uFF09
3124
+ const token = typeof localStorage !== "undefined"
3125
+ ? localStorage.getItem("token")
3126
+ : null;
3127
+
3128
+ if (token && config.headers) {
3129
+ config.headers.Authorization = \`Bearer \${token}\`;
3130
+ }
3131
+
3132
+ return config;
3133
+ },
3134
+ (error: AxiosError) => Promise.reject(error)
3135
+ );
3136
+
3137
+ // ============ \u54CD\u5E94\u62E6\u622A\u5668 ============
3138
+
3139
+ request.interceptors.response.use(
3140
+ (response: AxiosResponse) => {
3141
+ // \u76F4\u63A5\u8FD4\u56DE data \u5C42\uFF0C\u51CF\u5C11\u4E1A\u52A1\u4EE3\u7801\u89E3\u6784
3142
+ return response.data;
3143
+ },
3144
+ (error: AxiosError) => {
3145
+ const status = error.response?.status;
3146
+
3147
+ switch (status) {
3148
+ case 401:
3149
+ console.warn("[request] \u672A\u6388\u6743\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55");
3150
+ break;
3151
+ case 403:
3152
+ console.warn("[request] \u65E0\u8BBF\u95EE\u6743\u9650");
3153
+ break;
3154
+ case 404:
3155
+ console.warn("[request] \u8BF7\u6C42\u8D44\u6E90\u4E0D\u5B58\u5728");
3156
+ break;
3157
+ case 500:
3158
+ console.error("[request] \u670D\u52A1\u5668\u5185\u90E8\u9519\u8BEF");
3159
+ break;
3160
+ default:
3161
+ if (!error.response) {
3162
+ console.error("[request] \u7F51\u7EDC\u5F02\u5E38\uFF0C\u8BF7\u68C0\u67E5\u7F51\u7EDC\u8FDE\u63A5");
3163
+ }
3164
+ }
3165
+
3166
+ return Promise.reject(error);
3167
+ }
3168
+ );
3169
+
3170
+ export default request;
3171
+ `;
3172
+ }
3173
+
3174
+ // src/plugin/builtin/zustand.ts
3175
+ import { existsSync as existsSync10, mkdirSync as mkdirSync4, writeFileSync as writeFileSync5 } from "fs";
3176
+ import { join as join10 } from "path";
3177
+ var zustandPlugin = createPlugin((options = {}) => ({
3178
+ name: "@4399ywkf/plugin-zustand",
3179
+ version: "1.0.0",
3180
+ description: "Zustand \u72B6\u6001\u7BA1\u7406\u96C6\u6210",
3181
+ setup(context) {
3182
+ const { scaffold = true, storeDir = "store" } = options;
3183
+ const { cwd, logger } = context;
3184
+ const storePath = join10(cwd, storeDir);
3185
+ if (scaffold && !existsSync10(storePath)) {
3186
+ scaffoldStore(storePath, logger);
3187
+ }
3188
+ const hooks = {
3189
+ modifyRspackConfig(rspackConfig) {
3190
+ logger.info("Zustand \u5DF2\u542F\u7528");
3191
+ const resolve4 = rspackConfig.resolve || {};
3192
+ const alias = resolve4.alias || {};
3193
+ alias["@store"] = storePath;
3194
+ resolve4.alias = alias;
3195
+ rspackConfig.resolve = resolve4;
3196
+ return rspackConfig;
3197
+ },
3198
+ generateFiles(ctx) {
3199
+ return [
3200
+ {
3201
+ path: "store.ts",
3202
+ content: buildStoreHelperFile()
3203
+ }
3204
+ ];
3205
+ }
3206
+ };
3207
+ return hooks;
3208
+ }
3209
+ }));
3210
+ function scaffoldStore(storePath, logger) {
3211
+ const dirs = [
3212
+ storePath,
3213
+ join10(storePath, "middleware"),
3214
+ join10(storePath, "app"),
3215
+ join10(storePath, "app", "slices"),
3216
+ join10(storePath, "app", "slices", "counter")
3217
+ ];
3218
+ for (const dir of dirs) {
3219
+ if (!existsSync10(dir)) {
3220
+ mkdirSync4(dir, { recursive: true });
3221
+ }
3222
+ }
3223
+ writeFileSync5(
3224
+ join10(storePath, "middleware", "createDevtools.ts"),
3225
+ TPL_CREATE_DEVTOOLS,
3226
+ "utf-8"
3227
+ );
3228
+ writeFileSync5(
3229
+ join10(storePath, "app", "slices", "counter", "initialState.ts"),
3230
+ TPL_COUNTER_INITIAL_STATE,
3231
+ "utf-8"
3232
+ );
3233
+ writeFileSync5(
3234
+ join10(storePath, "app", "slices", "counter", "actions.ts"),
3235
+ TPL_COUNTER_ACTIONS,
3236
+ "utf-8"
3237
+ );
3238
+ writeFileSync5(
3239
+ join10(storePath, "app", "initialState.ts"),
3240
+ TPL_APP_INITIAL_STATE,
3241
+ "utf-8"
3242
+ );
3243
+ writeFileSync5(
3244
+ join10(storePath, "app", "store.ts"),
3245
+ TPL_APP_STORE,
3246
+ "utf-8"
3247
+ );
3248
+ writeFileSync5(
3249
+ join10(storePath, "app", "index.tsx"),
3250
+ TPL_APP_INDEX,
3251
+ "utf-8"
3252
+ );
3253
+ writeFileSync5(join10(storePath, "index.ts"), TPL_STORE_INDEX, "utf-8");
3254
+ logger.info("\u5DF2\u751F\u6210 store/ \u811A\u624B\u67B6\uFF08Agent/Slice \u67B6\u6784\uFF09");
3255
+ }
3256
+ var TPL_CREATE_DEVTOOLS = `import type { DevtoolsOptions } from "zustand/middleware";
3257
+ import { devtools as devtoolsMiddleware } from "zustand/middleware";
3258
+ import type { StateCreator, StoreMutatorIdentifier } from "zustand/vanilla";
3259
+
3260
+ /**
3261
+ * \u5C01\u88C5 zustand devtools \u4E2D\u95F4\u4EF6
3262
+ * \u751F\u4EA7\u73AF\u5883\u81EA\u52A8\u7981\u7528\uFF0C\u5F00\u53D1\u73AF\u5883\u542F\u7528 trace
3263
+ */
3264
+ export const createDevtools =
3265
+ (name: string, options?: DevtoolsOptions) =>
3266
+ <
3267
+ T,
3268
+ Mps extends [StoreMutatorIdentifier, unknown][] = [],
3269
+ Mcs extends [StoreMutatorIdentifier, unknown][] = [],
3270
+ >(
3271
+ initializer: StateCreator<T, [...Mps, ["zustand/devtools", never]], Mcs>,
3272
+ ) =>
3273
+ devtoolsMiddleware(initializer, {
3274
+ name,
3275
+ enabled: process.env.NODE_ENV === "development",
3276
+ trace: process.env.NODE_ENV === "development",
3277
+ ...options,
3278
+ });
3279
+ `;
3280
+ var TPL_COUNTER_INITIAL_STATE = `export interface CounterState {
3281
+ count: number;
3282
+ loading: boolean;
3283
+ error: string | null;
3284
+ }
3285
+
3286
+ export const initialCounterState: CounterState = {
3287
+ count: 0,
3288
+ loading: false,
3289
+ error: null,
3290
+ };
3291
+ `;
3292
+ var TPL_COUNTER_ACTIONS = `import type { StateCreator } from "zustand/vanilla";
3293
+ import type { AppStore } from "../../store";
3294
+
3295
+ export interface CounterAction {
3296
+ increment: () => void;
3297
+ decrement: () => void;
3298
+ reset: () => void;
3299
+ setLoading: (loading: boolean) => void;
3300
+ setError: (error: string | null) => void;
3301
+ fetchCount: () => Promise<void>;
3302
+ }
3303
+
3304
+ export const createCounterSlice: StateCreator<
3305
+ AppStore,
3306
+ [["zustand/devtools", never]],
3307
+ [],
3308
+ CounterAction
3309
+ > = (set, get) => ({
3310
+ increment: () => set((s) => ({ count: s.count + 1 })),
3311
+ decrement: () => set((s) => ({ count: s.count - 1 })),
3312
+ reset: () => set({ count: 0, error: null }),
3313
+ setLoading: (loading) => set({ loading }),
3314
+ setError: (error) => set({ error }),
3315
+
3316
+ fetchCount: async () => {
3317
+ set({ loading: true, error: null });
3318
+ try {
3319
+ // \u66FF\u6362\u4E3A\u5B9E\u9645 API \u8C03\u7528
3320
+ // import request from "@ywkf/request";
3321
+ // const res = await request.get("/api/count");
3322
+ // set({ count: res.data, loading: false });
3323
+ await new Promise((r) => setTimeout(r, 500));
3324
+ set({ count: 42, loading: false });
3325
+ } catch (err) {
3326
+ set({
3327
+ error: err instanceof Error ? err.message : "\u672A\u77E5\u9519\u8BEF",
3328
+ loading: false,
3329
+ });
3330
+ }
3331
+ },
51
3332
  });
3333
+ `;
3334
+ var TPL_APP_INITIAL_STATE = `import {
3335
+ type CounterState,
3336
+ initialCounterState,
3337
+ } from "./slices/counter/initialState";
3338
+
3339
+ // ============== \u805A\u5408\u6240\u6709 Slice \u72B6\u6001 ============== //
3340
+
3341
+ export type AppStoreState = CounterState;
3342
+
3343
+ export const initialState: AppStoreState = {
3344
+ ...initialCounterState,
3345
+ };
3346
+ `;
3347
+ var TPL_APP_STORE = `import { subscribeWithSelector } from "zustand/middleware";
3348
+ import { shallow } from "zustand/shallow";
3349
+ import { createWithEqualityFn } from "zustand/traditional";
3350
+ import type { StateCreator } from "zustand/vanilla";
3351
+
3352
+ import { createDevtools } from "../middleware/createDevtools";
3353
+ import { type AppStoreState, initialState } from "./initialState";
3354
+
3355
+ import {
3356
+ type CounterAction,
3357
+ createCounterSlice,
3358
+ } from "./slices/counter/actions";
3359
+
3360
+ // ============== \u805A\u5408 Store \u7C7B\u578B ============== //
3361
+
3362
+ export type AppStore = AppStoreState & CounterAction;
3363
+
3364
+ // ============== \u521B\u5EFA Store ============== //
3365
+
3366
+ const createStore: StateCreator<AppStore, [["zustand/devtools", never]]> = (
3367
+ ...parameters
3368
+ ) => ({
3369
+ ...initialState,
3370
+ ...createCounterSlice(...parameters),
3371
+ });
3372
+
3373
+ // ============== \u5B9E\u88C5 useStore ============== //
3374
+
3375
+ const devtools = createDevtools("app");
3376
+
3377
+ export const useAppStore = createWithEqualityFn<AppStore>()(
3378
+ subscribeWithSelector(devtools(createStore)),
3379
+ shallow,
3380
+ );
3381
+
3382
+ export const getAppStoreState = () => useAppStore.getState();
3383
+ `;
3384
+ var TPL_APP_INDEX = `export { useAppStore, getAppStoreState } from "./store";
3385
+ export type { AppStore } from "./store";
3386
+ export { initialState } from "./initialState";
3387
+ export type { AppStoreState } from "./initialState";
3388
+ `;
3389
+ var TPL_STORE_INDEX = `/**
3390
+ * Store \u805A\u5408\u5165\u53E3
3391
+ *
3392
+ * \u67B6\u6784\uFF1A
3393
+ * - store/middleware/ \u2014 \u4E2D\u95F4\u4EF6\uFF08devtools \u7B49\uFF09
3394
+ * - store/{domain}/ \u2014 \u6BCF\u4E2A\u57DF\u4EE3\u8868\u4E00\u4E2A\u4E1A\u52A1\u5B50\u7CFB\u7EDF
3395
+ * - store/{domain}/slices \u2014 \u6BCF\u4E2A slice \u62C6\u4E3A initialState + actions
3396
+ *
3397
+ * \u7EA6\u675F\uFF1A
3398
+ * - initialState\uFF1A\u7EAF\u6570\u636E\u5B9A\u4E49\uFF0C\u4E0D\u542B\u903B\u8F91
3399
+ * - actions\uFF1A\u540C\u6B65\u72B6\u6001\u53D8\u66F4 + \u5F02\u6B65\u526F\u4F5C\u7528
3400
+ * - slice \u4E4B\u95F4\u7981\u6B62\u76F4\u63A5\u4FEE\u6539\u5F7C\u6B64\u72B6\u6001
3401
+ * - \u57DF\u5C42\u8D1F\u8D23\u8DE8 slice \u534F\u8C03
3402
+ */
3403
+ export { useAppStore, getAppStoreState } from "./app";
3404
+ export type { AppStore, AppStoreState } from "./app";
3405
+ `;
3406
+ function buildStoreHelperFile() {
3407
+ return `// \u6B64\u6587\u4EF6\u7531 @4399ywkf/plugin-zustand \u81EA\u52A8\u751F\u6210
3408
+ // \u63D0\u4F9B Zustand \u5DE5\u5177\u51FD\u6570\u7684 re-export\uFF0C\u65B9\u4FBF\u4E1A\u52A1\u4EE3\u7801\u5F15\u7528
3409
+
3410
+ export { useShallow } from "zustand/react/shallow";
3411
+ export type { StateCreator, StoreApi } from "zustand";
3412
+ `;
3413
+ }
3414
+
3415
+ // src/cli/dev.ts
3416
+ import { rspack as rspack3 } from "@rspack/core";
3417
+ import { RspackDevServer } from "@rspack/dev-server";
3418
+ import chalk from "chalk";
3419
+ import ora from "ora";
3420
+
3421
+ // src/cli/env.ts
3422
+ import { existsSync as existsSync11, readFileSync as readFileSync4 } from "fs";
3423
+ import { resolve as resolve3 } from "path";
3424
+ import dotenv from "dotenv";
3425
+ function preloadEnv(cwd, mode) {
3426
+ process.env.NODE_ENV = mode;
3427
+ const defaultPaths = [
3428
+ resolve3(cwd, "config/env/.env.public"),
3429
+ resolve3(cwd, ".env.public"),
3430
+ resolve3(cwd, ".env")
3431
+ ];
3432
+ for (const envPath of defaultPaths) {
3433
+ if (existsSync11(envPath)) {
3434
+ dotenv.config({ path: envPath });
3435
+ break;
3436
+ }
3437
+ }
3438
+ const modeEnvPaths = [
3439
+ resolve3(cwd, `config/env/.env.${mode}`),
3440
+ resolve3(cwd, `.env.${mode}`)
3441
+ ];
3442
+ for (const envPath of modeEnvPaths) {
3443
+ if (existsSync11(envPath)) {
3444
+ const envContent = readFileSync4(envPath, "utf-8");
3445
+ const parsed = dotenv.parse(envContent);
3446
+ for (const key in parsed) {
3447
+ process.env[key] = parsed[key];
3448
+ }
3449
+ break;
3450
+ }
3451
+ }
3452
+ }
3453
+ function loadEnv(config, cwd, mode) {
3454
+ const { env } = config;
3455
+ const publicEnvPath = resolve3(cwd, env.publicEnvFile ?? "config/env/.env.public");
3456
+ if (existsSync11(publicEnvPath)) {
3457
+ dotenv.config({ path: publicEnvPath });
3458
+ }
3459
+ const modeEnvPath = resolve3(cwd, env.envDir ?? "config/env", `.env.${mode}`);
3460
+ if (existsSync11(modeEnvPath)) {
3461
+ const envContent = readFileSync4(modeEnvPath, "utf-8");
3462
+ const parsed = dotenv.parse(envContent);
3463
+ for (const key in parsed) {
3464
+ process.env[key] = parsed[key];
3465
+ }
3466
+ }
3467
+ process.env.NODE_ENV = mode;
3468
+ process.env.APP_NAME = process.env.APP_NAME || config.appName;
3469
+ process.env.APP_CNAME = process.env.APP_CNAME || config.appCName;
3470
+ process.env.OUTPUT_PATH = process.env.OUTPUT_PATH || config.output.path;
3471
+ process.env.PUBLIC_PATH = process.env.PUBLIC_PATH || config.output.publicPath;
3472
+ process.env.APP_HOST = process.env.APP_HOST || config.dev.host;
3473
+ process.env.APP_PORT = process.env.APP_PORT || String(config.dev.port);
3474
+ }
3475
+
3476
+ // src/cli/dev.ts
3477
+ async function dev(options = {}) {
3478
+ const cwd = options.cwd || process.cwd();
3479
+ const spinner = ora("\u6B63\u5728\u542F\u52A8\u5F00\u53D1\u670D\u52A1\u5668...").start();
3480
+ try {
3481
+ preloadEnv(cwd, "development");
3482
+ const { config, configPath } = await resolveConfig(cwd);
3483
+ if (configPath) {
3484
+ spinner.text = `\u5DF2\u52A0\u8F7D\u914D\u7F6E: ${configPath}`;
3485
+ }
3486
+ loadEnv(config, cwd, "development");
3487
+ const pluginManager = new PluginManager(config, cwd, true);
3488
+ if (config.plugins && config.plugins.length > 0) {
3489
+ spinner.text = "\u52A0\u8F7D\u63D2\u4EF6...";
3490
+ await pluginManager.loadPlugins(config.plugins);
3491
+ }
3492
+ await pluginManager.runBeforeDevServer();
3493
+ let rspackConfig = createRspackConfig(config, cwd, { isDev: true });
3494
+ rspackConfig = await pluginManager.applyRspackConfigHooks(rspackConfig);
3495
+ const compiler = rspack3(rspackConfig);
3496
+ const devServerOptions = rspackConfig.devServer || {};
3497
+ const server = new RspackDevServer(devServerOptions, compiler);
3498
+ const host = config.dev.host || "localhost";
3499
+ const port = config.dev.port || 3e3;
3500
+ await server.start();
3501
+ await pluginManager.runAfterDevServer({ host, port });
3502
+ spinner.succeed(chalk.green("\u5F00\u53D1\u670D\u52A1\u5668\u542F\u52A8\u6210\u529F!"));
3503
+ console.log();
3504
+ console.log(
3505
+ ` ${chalk.bold("Local:")} ${chalk.cyan(`http://${host}:${port}`)}`
3506
+ );
3507
+ const pluginNames = pluginManager.getPluginNames();
3508
+ if (pluginNames.length > 0) {
3509
+ console.log(` ${chalk.bold("\u63D2\u4EF6:")} ${chalk.dim(pluginNames.join(", "))}`);
3510
+ }
3511
+ console.log();
3512
+ const signals = ["SIGINT", "SIGTERM"];
3513
+ for (const signal of signals) {
3514
+ process.on(signal, async () => {
3515
+ await server.stop();
3516
+ process.exit(0);
3517
+ });
3518
+ }
3519
+ } catch (error) {
3520
+ spinner.fail(chalk.red("\u5F00\u53D1\u670D\u52A1\u5668\u542F\u52A8\u5931\u8D25"));
3521
+ console.error(error);
3522
+ process.exit(1);
3523
+ }
3524
+ }
3525
+
3526
+ // src/cli/build.ts
3527
+ import { rspack as rspack4 } from "@rspack/core";
3528
+ import chalk2 from "chalk";
3529
+ import ora2 from "ora";
3530
+ function formatSize(bytes) {
3531
+ if (bytes < 1024) return `${bytes} B`;
3532
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(2)} KB`;
3533
+ return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;
3534
+ }
3535
+ function printBuildResult(stats) {
3536
+ const info = stats.toJson({
3537
+ assets: true,
3538
+ errors: true,
3539
+ warnings: true
3540
+ });
3541
+ if (info.errors && info.errors.length > 0) {
3542
+ console.log(chalk2.red("\n\u6784\u5EFA\u9519\u8BEF:"));
3543
+ for (const error of info.errors) {
3544
+ console.log(chalk2.red(` ${error.message}`));
3545
+ }
3546
+ return;
3547
+ }
3548
+ if (info.warnings && info.warnings.length > 0) {
3549
+ console.log(chalk2.yellow("\n\u6784\u5EFA\u8B66\u544A:"));
3550
+ for (const warning of info.warnings) {
3551
+ console.log(chalk2.yellow(` ${warning.message}`));
3552
+ }
3553
+ }
3554
+ console.log(chalk2.bold("\n\u6784\u5EFA\u4EA7\u7269:"));
3555
+ console.log();
3556
+ const assets = info.assets || [];
3557
+ const sortedAssets = assets.filter((asset) => !asset.name.endsWith(".map")).sort((a, b) => b.size - a.size);
3558
+ for (const asset of sortedAssets.slice(0, 15)) {
3559
+ const sizeColor = asset.size > 500 * 1024 ? chalk2.yellow : chalk2.green;
3560
+ console.log(
3561
+ ` ${chalk2.dim(asset.name.padEnd(50))} ${sizeColor(formatSize(asset.size))}`
3562
+ );
3563
+ }
3564
+ if (sortedAssets.length > 15) {
3565
+ console.log(chalk2.dim(` ... \u8FD8\u6709 ${sortedAssets.length - 15} \u4E2A\u6587\u4EF6`));
3566
+ }
3567
+ console.log();
3568
+ console.log(
3569
+ chalk2.green(
3570
+ `\u2713 \u6784\u5EFA\u5B8C\u6210\uFF0C\u8017\u65F6 ${((info.time || 0) / 1e3).toFixed(2)}s`
3571
+ )
3572
+ );
3573
+ }
3574
+ async function build(options = {}) {
3575
+ const cwd = options.cwd || process.cwd();
3576
+ const spinner = ora2("\u6B63\u5728\u6784\u5EFA\u751F\u4EA7\u73AF\u5883...").start();
3577
+ try {
3578
+ preloadEnv(cwd, "production");
3579
+ const { config, configPath } = await resolveConfig(cwd);
3580
+ if (configPath) {
3581
+ spinner.text = `\u5DF2\u52A0\u8F7D\u914D\u7F6E: ${configPath}`;
3582
+ }
3583
+ loadEnv(config, cwd, "production");
3584
+ const pluginManager = new PluginManager(config, cwd, false);
3585
+ if (config.plugins && config.plugins.length > 0) {
3586
+ spinner.text = "\u52A0\u8F7D\u63D2\u4EF6...";
3587
+ await pluginManager.loadPlugins(config.plugins);
3588
+ }
3589
+ await pluginManager.runBeforeBuild();
3590
+ let rspackConfig = createRspackConfig(config, cwd, { isDev: false });
3591
+ rspackConfig = await pluginManager.applyRspackConfigHooks(rspackConfig);
3592
+ spinner.text = "\u6B63\u5728\u7F16\u8BD1...";
3593
+ const compiler = rspack4(rspackConfig);
3594
+ const stats = await new Promise((resolve4, reject) => {
3595
+ compiler.run((err, stats2) => {
3596
+ if (err) {
3597
+ reject(err);
3598
+ return;
3599
+ }
3600
+ if (!stats2) {
3601
+ reject(new Error("\u6784\u5EFA\u5931\u8D25: \u65E0\u6CD5\u83B7\u53D6\u7EDF\u8BA1\u4FE1\u606F"));
3602
+ return;
3603
+ }
3604
+ resolve4(stats2);
3605
+ });
3606
+ });
3607
+ await new Promise((resolve4, reject) => {
3608
+ compiler.close((err) => {
3609
+ if (err) reject(err);
3610
+ else resolve4();
3611
+ });
3612
+ });
3613
+ const hasErrors = stats.hasErrors();
3614
+ const statsInfo = stats.toJson({ errors: true });
3615
+ await pluginManager.runAfterBuild({
3616
+ success: !hasErrors,
3617
+ errors: statsInfo.errors?.map((e) => e.message)
3618
+ });
3619
+ if (hasErrors) {
3620
+ spinner.fail(chalk2.red("\u6784\u5EFA\u5931\u8D25"));
3621
+ printBuildResult(stats);
3622
+ process.exit(1);
3623
+ }
3624
+ spinner.succeed(chalk2.green("\u6784\u5EFA\u5B8C\u6210!"));
3625
+ printBuildResult(stats);
3626
+ } catch (error) {
3627
+ spinner.fail(chalk2.red("\u6784\u5EFA\u5931\u8D25"));
3628
+ console.error(error);
3629
+ process.exit(1);
3630
+ }
3631
+ }
3632
+ export {
3633
+ AppContext,
3634
+ AppContextProvider,
3635
+ ConventionalRouteGenerator,
3636
+ ConventionalRoutePlugin,
3637
+ ErrorBoundary,
3638
+ PluginManager,
3639
+ RootProvider,
3640
+ YwkfGenerator,
3641
+ YwkfGeneratorPlugin,
3642
+ analyticsPlugin,
3643
+ bootstrap,
3644
+ build,
3645
+ createBaseConfig,
3646
+ createDevConfig,
3647
+ createMicroApp,
3648
+ createPlugin,
3649
+ createProdConfig,
3650
+ createProvider,
3651
+ createRspackConfig,
3652
+ defaultConfig,
3653
+ defineConfig,
3654
+ definePlugin,
3655
+ dev,
3656
+ garfishPlugin,
3657
+ generateConventionalRoutes,
3658
+ getMicroAppPublicPath,
3659
+ i18nPlugin,
3660
+ isMicroAppEnv,
3661
+ mockPlugin,
3662
+ reactQueryPlugin,
3663
+ tailwindPlugin,
3664
+ themePlugin,
3665
+ unmount,
3666
+ useApp,
3667
+ useAppName,
3668
+ useBasename,
3669
+ useEnv,
3670
+ useIsDev,
3671
+ zustandPlugin
3672
+ };
3673
+ //# sourceMappingURL=index.js.map