@4399ywkf/core 4.0.84 → 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
@@ -0,0 +1,1574 @@
1
+ // src/rspack/index.ts
2
+ import { RsdoctorRspackPlugin } from "@rsdoctor/rspack-plugin";
3
+
4
+ // src/rspack/dev.ts
5
+ import { merge } from "webpack-merge";
6
+ import { createRequire as createRequire2 } from "module";
7
+
8
+ // src/config/loader.ts
9
+ import { existsSync } from "fs";
10
+ import { resolve, extname } from "path";
11
+ import { pathToFileURL } from "url";
12
+ import deepmerge from "deepmerge";
13
+ function createPathResolver(cwd) {
14
+ return {
15
+ resolveApp: (relativePath) => resolve(cwd, relativePath),
16
+ cwd
17
+ };
18
+ }
19
+
20
+ // src/rspack/base.ts
21
+ import { rspack } from "@rspack/core";
22
+ import { createRequire } from "module";
23
+ import { fileURLToPath } from "url";
24
+ import { dirname, join as join5 } from "path";
25
+
26
+ // src/generator/plugin.ts
27
+ import { watch, existsSync as existsSync5 } from "fs";
28
+ import { join as join4 } from "path";
29
+
30
+ // src/generator/generator.ts
31
+ import { existsSync as existsSync4, mkdirSync as mkdirSync2, writeFileSync as writeFileSync2, readFileSync as readFileSync2 } from "fs";
32
+ import { join as join3 } from "path";
33
+
34
+ // src/router/generator.ts
35
+ import { existsSync as existsSync2, readdirSync, statSync, mkdirSync, writeFileSync } from "fs";
36
+ import { join, relative } from "path";
37
+ var EXCLUDED_DIRS = /* @__PURE__ */ new Set([
38
+ "components",
39
+ "hooks",
40
+ "utils",
41
+ "services",
42
+ "models",
43
+ "assets",
44
+ "types",
45
+ "constants",
46
+ "styles"
47
+ ]);
48
+ var CONVENTION_FILES = {
49
+ page: /^page\.(tsx?|jsx?)$/,
50
+ layout: /^layout\.(tsx?|jsx?)$/,
51
+ error: /^error\.(tsx?|jsx?)$/,
52
+ loading: /^loading\.(tsx?|jsx?)$/,
53
+ catchAll: /^\$\.(tsx?|jsx?)$/
54
+ };
55
+ var ConventionalRouteGenerator = class {
56
+ options;
57
+ constructor(options) {
58
+ this.options = options;
59
+ }
60
+ generate() {
61
+ const { pagesDir } = this.options;
62
+ if (!existsSync2(pagesDir)) {
63
+ console.warn(`[ywkf] \u9875\u9762\u76EE\u5F55\u4E0D\u5B58\u5728: ${pagesDir}`);
64
+ return [];
65
+ }
66
+ return this.scanDirectory(pagesDir, "/");
67
+ }
68
+ /**
69
+ * 扫描目录,生成路由树
70
+ */
71
+ scanDirectory(dir, routePath) {
72
+ const entries = readdirSync(dir);
73
+ const layoutFile = entries.find((e) => CONVENTION_FILES.layout.test(e));
74
+ const pageFile = entries.find((e) => CONVENTION_FILES.page.test(e));
75
+ const errorFile = entries.find((e) => CONVENTION_FILES.error.test(e));
76
+ const loadingFile = entries.find((e) => CONVENTION_FILES.loading.test(e));
77
+ const catchAllFile = entries.find((e) => CONVENTION_FILES.catchAll.test(e));
78
+ const subDirs = entries.filter((e) => {
79
+ if (e.startsWith(".")) return false;
80
+ if (EXCLUDED_DIRS.has(e)) return false;
81
+ return statSync(join(dir, e)).isDirectory();
82
+ });
83
+ const childRoutes = [];
84
+ for (const subDir of subDirs) {
85
+ const subDirPath = join(dir, subDir);
86
+ if (subDir.startsWith("__")) {
87
+ const pathlessRoutes = this.scanDirectory(subDirPath, routePath);
88
+ const pathlessLayout = readdirSync(subDirPath).find(
89
+ (e) => CONVENTION_FILES.layout.test(e)
90
+ );
91
+ if (pathlessLayout) {
92
+ const pathlessChildren = this.scanDirectory(subDirPath, routePath);
93
+ childRoutes.push({
94
+ path: routePath,
95
+ name: this.generateRouteName(subDir.slice(2)),
96
+ layoutFile: relative(this.options.pagesDir, join(subDirPath, pathlessLayout)),
97
+ isLayout: true,
98
+ pathless: true,
99
+ children: pathlessChildren.filter(
100
+ (r) => r.layoutFile !== relative(this.options.pagesDir, join(subDirPath, pathlessLayout))
101
+ )
102
+ });
103
+ } else {
104
+ childRoutes.push(...pathlessRoutes);
105
+ }
106
+ continue;
107
+ }
108
+ const subRoutePath = this.resolveRoutePath(subDir, routePath);
109
+ childRoutes.push(...this.scanDirectory(subDirPath, subRoutePath));
110
+ }
111
+ const routeName = this.generateRouteName(routePath);
112
+ const relPath = (file) => relative(this.options.pagesDir, join(dir, file));
113
+ if (layoutFile) {
114
+ const layoutChildren = [];
115
+ if (pageFile) {
116
+ layoutChildren.push({
117
+ path: routePath,
118
+ file: relPath(pageFile),
119
+ name: routeName + "Index",
120
+ index: true
121
+ });
122
+ }
123
+ if (catchAllFile) {
124
+ layoutChildren.push({
125
+ path: "*",
126
+ file: relPath(catchAllFile),
127
+ name: routeName + "CatchAll"
128
+ });
129
+ }
130
+ layoutChildren.push(...childRoutes);
131
+ return [
132
+ {
133
+ path: routePath,
134
+ layoutFile: relPath(layoutFile),
135
+ errorFile: errorFile ? relPath(errorFile) : void 0,
136
+ loadingFile: loadingFile ? relPath(loadingFile) : void 0,
137
+ name: routeName,
138
+ isLayout: true,
139
+ children: layoutChildren
140
+ }
141
+ ];
142
+ }
143
+ const result = [];
144
+ if (pageFile) {
145
+ result.push({
146
+ path: routePath,
147
+ file: relPath(pageFile),
148
+ errorFile: errorFile ? relPath(errorFile) : void 0,
149
+ name: routeName
150
+ });
151
+ }
152
+ if (catchAllFile) {
153
+ result.push({
154
+ path: "*",
155
+ file: relPath(catchAllFile),
156
+ name: routeName + "CatchAll"
157
+ });
158
+ }
159
+ result.push(...childRoutes);
160
+ return result;
161
+ }
162
+ /**
163
+ * 解析目录名到路由路径
164
+ *
165
+ * - [id] → :id
166
+ * - [id$] → :id?
167
+ * - [...slug] → *
168
+ * - user.profile → user/profile
169
+ */
170
+ resolveRoutePath(dirName, parentPath) {
171
+ let segment;
172
+ if (dirName.match(/^\[\.\.\.(.+)\]$/)) {
173
+ segment = "*";
174
+ } else if (dirName.match(/^\[(.+)\$\]$/)) {
175
+ const param = dirName.slice(1, -2);
176
+ segment = `:${param}?`;
177
+ } else if (dirName.match(/^\[(.+)\]$/)) {
178
+ const param = dirName.slice(1, -1);
179
+ segment = `:${param}`;
180
+ } else if (dirName.includes(".")) {
181
+ segment = dirName.replace(/\./g, "/");
182
+ } else {
183
+ segment = dirName;
184
+ }
185
+ return parentPath === "/" ? `/${segment}` : `${parentPath}/${segment}`;
186
+ }
187
+ /**
188
+ * 生成有效的 JS 标识符名称
189
+ */
190
+ generateRouteName(path) {
191
+ const name = path.split("/").filter(Boolean).map(
192
+ (s) => s.replace(/^:/, "Param").replace(/\?$/, "Optional").replace(/^\*$/, "CatchAll")
193
+ ).map((s) => {
194
+ const cleaned = s.replace(/[^a-zA-Z0-9]/g, "");
195
+ if (!cleaned) return "";
196
+ return cleaned.charAt(0).toUpperCase() + cleaned.slice(1);
197
+ }).join("");
198
+ if (!name || /^\d/.test(name)) {
199
+ return "Page" + (name || "Root");
200
+ }
201
+ return name;
202
+ }
203
+ // ===== 代码生成 =====
204
+ generateCode() {
205
+ const routes = this.generate();
206
+ const lazyImports = [];
207
+ const errorImports = [];
208
+ const loadingImports = [];
209
+ this.collectImports(routes, lazyImports, errorImports, loadingImports);
210
+ return `// \u6B64\u6587\u4EF6\u7531 @4399ywkf/core \u81EA\u52A8\u751F\u6210\uFF0C\u8BF7\u52FF\u624B\u52A8\u4FEE\u6539
211
+ // Generated at: ${(/* @__PURE__ */ new Date()).toISOString()}
212
+
213
+ import React, { lazy, Suspense } from "react";
214
+ import { createBrowserRouter, type RouteObject } from "react-router";
215
+
216
+ // \u61D2\u52A0\u8F7D\u9875\u9762\u7EC4\u4EF6
217
+ ${lazyImports.join("\n")}
218
+ ${errorImports.length > 0 ? "\n// \u9519\u8BEF\u8FB9\u754C\u7EC4\u4EF6\n" + errorImports.join("\n") : ""}
219
+ ${loadingImports.length > 0 ? "\n// \u52A0\u8F7D\u72B6\u6001\u7EC4\u4EF6\n" + loadingImports.join("\n") : ""}
220
+
221
+ // \u9ED8\u8BA4\u52A0\u8F7D\u72B6\u6001
222
+ const DefaultLoading = () => <div style={{ padding: 24, textAlign: "center" }}>\u52A0\u8F7D\u4E2D...</div>;
223
+
224
+ // \u61D2\u52A0\u8F7D\u5305\u88C5
225
+ function LazyRoute({
226
+ Component,
227
+ Loading = DefaultLoading,
228
+ }: {
229
+ Component: React.LazyExoticComponent<React.ComponentType<unknown>>;
230
+ Loading?: React.ComponentType;
231
+ }) {
232
+ return (
233
+ <Suspense fallback={<Loading />}>
234
+ <Component />
235
+ </Suspense>
236
+ );
237
+ }
238
+
239
+ // \u8DEF\u7531\u914D\u7F6E
240
+ export const routes: RouteObject[] = ${this.emitRouteArray(routes)};
241
+
242
+ /**
243
+ * \u521B\u5EFA\u8DEF\u7531\u5B9E\u4F8B
244
+ */
245
+ export function createRouter(basename?: string) {
246
+ return createBrowserRouter(routes, { basename: basename || "/" });
247
+ }
248
+
249
+ export default routes;
250
+ `;
251
+ }
252
+ collectImports(routes, lazyImports, errorImports, loadingImports) {
253
+ for (const route of routes) {
254
+ const name = route.name;
255
+ const toImportPath = (f) => f.replace(/\.(tsx?|jsx?)$/, "");
256
+ if (route.isLayout && route.layoutFile) {
257
+ lazyImports.push(
258
+ `const ${name}Layout = lazy(() => import("@/pages/${toImportPath(route.layoutFile)}"));`
259
+ );
260
+ }
261
+ if (route.file) {
262
+ lazyImports.push(
263
+ `const ${name}Page = lazy(() => import("@/pages/${toImportPath(route.file)}"));`
264
+ );
265
+ }
266
+ if (route.errorFile) {
267
+ errorImports.push(
268
+ `const ${name}Error = lazy(() => import("@/pages/${toImportPath(route.errorFile)}"));`
269
+ );
270
+ }
271
+ if (route.loadingFile) {
272
+ loadingImports.push(
273
+ `const ${name}Loading = lazy(() => import("@/pages/${toImportPath(route.loadingFile)}"));`
274
+ );
275
+ }
276
+ if (route.children) {
277
+ this.collectImports(route.children, lazyImports, errorImports, loadingImports);
278
+ }
279
+ }
280
+ }
281
+ emitRouteArray(routes, parentPath) {
282
+ const items = routes.map((r) => this.emitRouteObject(r, parentPath));
283
+ return `[
284
+ ${items.join(",\n ")}
285
+ ]`;
286
+ }
287
+ emitRouteObject(route, parentPath) {
288
+ const parts = [];
289
+ const name = route.name;
290
+ if (route.index) {
291
+ parts.push("index: true");
292
+ } else if (route.pathless) {
293
+ } else if (route.path === "*") {
294
+ parts.push(`path: "*"`);
295
+ } else if (parentPath && route.path.startsWith(parentPath) && parentPath !== "/") {
296
+ const rel = route.path.slice(parentPath.length + 1);
297
+ parts.push(`path: "${rel || ""}"`);
298
+ } else {
299
+ parts.push(`path: "${route.path}"`);
300
+ }
301
+ if (route.isLayout && route.layoutFile) {
302
+ const loadingProp = route.loadingFile ? ` Loading={${name}Loading}` : "";
303
+ parts.push(`element: <LazyRoute Component={${name}Layout}${loadingProp} />`);
304
+ } else if (route.file) {
305
+ parts.push(`element: <LazyRoute Component={${name}Page} />`);
306
+ }
307
+ if (route.errorFile) {
308
+ parts.push(`errorElement: <LazyRoute Component={${name}Error} />`);
309
+ }
310
+ if (route.children && route.children.length > 0) {
311
+ const childParent = route.pathless ? parentPath : route.path;
312
+ parts.push(`children: ${this.emitRouteArray(route.children, childParent)}`);
313
+ }
314
+ return `{
315
+ ${parts.join(",\n ")}
316
+ }`;
317
+ }
318
+ /**
319
+ * 写入路由文件
320
+ */
321
+ write() {
322
+ const { outputDir } = this.options;
323
+ const code = this.generateCode();
324
+ if (!existsSync2(outputDir)) {
325
+ mkdirSync(outputDir, { recursive: true });
326
+ }
327
+ writeFileSync(join(outputDir, "routes.tsx"), code, "utf-8");
328
+ console.log(`[ywkf] \u7EA6\u5B9A\u5F0F\u8DEF\u7531\u5DF2\u751F\u6210`);
329
+ }
330
+ };
331
+
332
+ // src/generator/templates/entry.ts
333
+ function generateEntry(config, injections = {}) {
334
+ const imports = [
335
+ `import "@/index.css";`,
336
+ `import { runApp } from "./bootstrap";`,
337
+ ...injections.imports || []
338
+ ];
339
+ const topLevel = injections.topLevel || [];
340
+ const exports = injections.exports || [];
341
+ const hasPluginExports = exports.length > 0;
342
+ const startupCode = hasPluginExports ? `// \u72EC\u7ACB\u8FD0\u884C\u6A21\u5F0F
343
+ if (shouldRunIndependently !== false) {
344
+ runApp();
345
+ }` : `// \u542F\u52A8\u5E94\u7528
346
+ runApp();`;
347
+ return `// \u6B64\u6587\u4EF6\u7531 @4399ywkf/core \u81EA\u52A8\u751F\u6210\uFF0C\u8BF7\u52FF\u624B\u52A8\u4FEE\u6539
348
+ // Generated at: ${(/* @__PURE__ */ new Date()).toISOString()}
349
+
350
+ ${imports.join("\n")}
351
+
352
+ ${topLevel.length > 0 ? topLevel.join("\n") + "\n" : ""}${exports.length > 0 ? exports.join("\n") + "\n\n" : ""}${startupCode}
353
+ `;
354
+ }
355
+
356
+ // src/generator/templates/bootstrap.ts
357
+ function generateBootstrap(config, injections = {}) {
358
+ const { appName, router } = config;
359
+ const routerImport = router.conventional ? `import { createRouter } from "./routes";` : `import { createRouter } from "@/routes";`;
360
+ const imports = [
361
+ `import { bootstrap, type AppConfig } from "@4399ywkf/core/runtime";`,
362
+ routerImport,
363
+ ...injections.imports || []
364
+ ];
365
+ const topLevel = injections.topLevel || [];
366
+ const exports = injections.exports || [];
367
+ return `// \u6B64\u6587\u4EF6\u7531 @4399ywkf/core \u81EA\u52A8\u751F\u6210\uFF0C\u8BF7\u52FF\u624B\u52A8\u4FEE\u6539
368
+ // Generated at: ${(/* @__PURE__ */ new Date()).toISOString()}
369
+
370
+ ${imports.join("\n")}
371
+
372
+ /**
373
+ * \u5E94\u7528\u540D\u79F0
374
+ */
375
+ export const APP_NAME = "${appName}";
376
+
377
+ /**
378
+ * \u8DEF\u7531 basename
379
+ */
380
+ export const BASENAME = "${router.basename || "/"}";
381
+
382
+ /**
383
+ * \u83B7\u53D6\u7528\u6237\u81EA\u5B9A\u4E49\u914D\u7F6E\uFF08\u5982\u679C\u5B58\u5728\uFF09
384
+ * \u7528\u6237\u53EF\u5728 src/app.config.ts \u4E2D\u5BFC\u51FA\u914D\u7F6E\u6765\u8986\u76D6\u9ED8\u8BA4\u503C
385
+ */
386
+ async function getUserConfig(): Promise<Partial<AppConfig>> {
387
+ try {
388
+ // webpackIgnore \u6CE8\u91CA\u8BA9\u6253\u5305\u5668\u8DF3\u8FC7\u6A21\u5757\u5B58\u5728\u6027\u68C0\u67E5
389
+ const userConfigModule = await import(/* webpackIgnore: true */ "@/app.config");
390
+ return userConfigModule.default || {};
391
+ } catch {
392
+ // \u6587\u4EF6\u4E0D\u5B58\u5728\u65F6\u8FD4\u56DE\u7A7A\u914D\u7F6E
393
+ return {};
394
+ }
395
+ }
396
+
397
+ /**
398
+ * \u521B\u5EFA\u5E94\u7528\u914D\u7F6E
399
+ */
400
+ export function createAppConfig(userConfig: Partial<AppConfig> = {}): AppConfig {
401
+ const router = createRouter(BASENAME);
402
+
403
+ const defaultConfig: AppConfig = {
404
+ appName: APP_NAME,
405
+ router,
406
+ basename: BASENAME,
407
+ rootId: APP_NAME,
408
+ strictMode: true,
409
+ antd: {
410
+ enabled: true,
411
+ },
412
+ providers: [],
413
+ lifecycle: {
414
+ onMounted() {
415
+ console.log(\`[\${APP_NAME}] \u5E94\u7528\u5DF2\u6302\u8F7D\`);
416
+ },
417
+ onUnmount() {
418
+ console.log(\`[\${APP_NAME}] \u5E94\u7528\u5DF2\u5378\u8F7D\`);
419
+ },
420
+ onError(error) {
421
+ console.error(\`[\${APP_NAME}] \u5168\u5C40\u9519\u8BEF:\`, error);
422
+ },
423
+ },
424
+ };
425
+
426
+ // \u6DF1\u5EA6\u5408\u5E76\u7528\u6237\u914D\u7F6E
427
+ return {
428
+ ...defaultConfig,
429
+ ...userConfig,
430
+ antd: { ...defaultConfig.antd, ...userConfig.antd },
431
+ providers: [...(defaultConfig.providers || []), ...(userConfig.providers || [])],
432
+ lifecycle: { ...defaultConfig.lifecycle, ...userConfig.lifecycle },
433
+ };
434
+ }
435
+
436
+ /**
437
+ * \u542F\u52A8\u5E94\u7528
438
+ */
439
+ export async function runApp(): Promise<void> {
440
+ const userConfig = await getUserConfig();
441
+ await bootstrap(createAppConfig(userConfig));
442
+ }
443
+ ${topLevel.length > 0 ? "\n" + topLevel.join("\n") : ""}
444
+ ${exports.length > 0 ? "\n" + exports.join("\n") : ""}
445
+ `;
446
+ }
447
+
448
+ // src/generator/templates/env-types.ts
449
+ import { existsSync as existsSync3, readFileSync } from "fs";
450
+ import { join as join2 } from "path";
451
+ function generateEnvTypes(cwd, config) {
452
+ const envVars = collectEnvVars(cwd, config);
453
+ const envInterface = envVars.map((key) => ` readonly ${key}: string;`).join("\n");
454
+ return `// \u6B64\u6587\u4EF6\u7531 @4399ywkf/core \u81EA\u52A8\u751F\u6210\uFF0C\u8BF7\u52FF\u624B\u52A8\u4FEE\u6539
455
+ // Generated at: ${(/* @__PURE__ */ new Date()).toISOString()}
456
+
457
+ /// <reference types="react" />
458
+ /// <reference types="react-dom" />
459
+
460
+ declare namespace NodeJS {
461
+ interface ProcessEnv {
462
+ ${envInterface}
463
+ readonly NODE_ENV: "development" | "production" | "test";
464
+ }
465
+ }
466
+
467
+ declare module "*.svg" {
468
+ import * as React from "react";
469
+ const ReactComponent: React.FunctionComponent<
470
+ React.SVGProps<SVGSVGElement> & { title?: string }
471
+ >;
472
+ export default ReactComponent;
473
+ }
474
+
475
+ declare module "*.png" {
476
+ const src: string;
477
+ export default src;
478
+ }
479
+
480
+ declare module "*.jpg" {
481
+ const src: string;
482
+ export default src;
483
+ }
484
+
485
+ declare module "*.jpeg" {
486
+ const src: string;
487
+ export default src;
488
+ }
489
+
490
+ declare module "*.gif" {
491
+ const src: string;
492
+ export default src;
493
+ }
494
+
495
+ declare module "*.webp" {
496
+ const src: string;
497
+ export default src;
498
+ }
499
+
500
+ declare module "*.css" {
501
+ const classes: { readonly [key: string]: string };
502
+ export default classes;
503
+ }
504
+
505
+ declare module "*.less" {
506
+ const classes: { readonly [key: string]: string };
507
+ export default classes;
508
+ }
509
+
510
+ declare module "*.scss" {
511
+ const classes: { readonly [key: string]: string };
512
+ export default classes;
513
+ }
514
+
515
+ declare module "*.md" {
516
+ const content: string;
517
+ export default content;
518
+ }
519
+ `;
520
+ }
521
+ function collectEnvVars(cwd, config) {
522
+ const envVars = /* @__PURE__ */ new Set();
523
+ const publicEnvPath = join2(cwd, config.env.publicEnvFile || "config/env/.env.public");
524
+ if (existsSync3(publicEnvPath)) {
525
+ const content = readFileSync(publicEnvPath, "utf-8");
526
+ parseEnvFile(content, envVars);
527
+ }
528
+ const devEnvPath = join2(cwd, config.env.envDir || "config/env", ".env.development");
529
+ if (existsSync3(devEnvPath)) {
530
+ const content = readFileSync(devEnvPath, "utf-8");
531
+ parseEnvFile(content, envVars);
532
+ }
533
+ const prodEnvPath = join2(cwd, config.env.envDir || "config/env", ".env.production");
534
+ if (existsSync3(prodEnvPath)) {
535
+ const content = readFileSync(prodEnvPath, "utf-8");
536
+ parseEnvFile(content, envVars);
537
+ }
538
+ return Array.from(envVars).sort();
539
+ }
540
+ function parseEnvFile(content, envVars) {
541
+ const lines = content.split("\n");
542
+ for (const line of lines) {
543
+ const trimmed = line.trim();
544
+ if (!trimmed || trimmed.startsWith("#")) {
545
+ continue;
546
+ }
547
+ const match = trimmed.match(/^([A-Z_][A-Z0-9_]*)\s*=/);
548
+ if (match) {
549
+ envVars.add(match[1]);
550
+ }
551
+ }
552
+ }
553
+
554
+ // src/generator/templates/route-types.ts
555
+ function generateRouteTypes() {
556
+ return `// \u6B64\u6587\u4EF6\u7531 @4399ywkf/core \u81EA\u52A8\u751F\u6210\uFF0C\u8BF7\u52FF\u624B\u52A8\u4FEE\u6539
557
+ // Generated at: ${(/* @__PURE__ */ new Date()).toISOString()}
558
+
559
+ import type { RouteObject } from "react-router";
560
+
561
+ declare module "@ywkf/routes" {
562
+ export const routes: RouteObject[];
563
+ export function createRouter(basename?: string): ReturnType<typeof import("react-router").createBrowserRouter>;
564
+ export default routes;
565
+ }
566
+ `;
567
+ }
568
+
569
+ // src/generator/generator.ts
570
+ var YwkfGenerator = class {
571
+ context;
572
+ pluginHooks;
573
+ lastGeneratedContent = /* @__PURE__ */ new Map();
574
+ constructor(context, pluginHooks = []) {
575
+ this.context = {
576
+ ...context,
577
+ outputDir: context.outputDir || join3(context.cwd, ".ywkf")
578
+ };
579
+ this.pluginHooks = pluginHooks;
580
+ }
581
+ /**
582
+ * 生成所有文件
583
+ */
584
+ async generate() {
585
+ const { outputDir } = this.context;
586
+ this.ensureDir(outputDir);
587
+ this.ensureDir(join3(outputDir, "types"));
588
+ this.generateConfigSnapshot();
589
+ this.generateRoutes();
590
+ this.generateBootstrapFile();
591
+ this.generateEntryFile();
592
+ this.generateTypes();
593
+ await this.generatePluginFiles();
594
+ for (const hooks of this.pluginHooks) {
595
+ if (hooks.afterGenerate) {
596
+ await hooks.afterGenerate(this.context);
597
+ }
598
+ }
599
+ console.log(`[ywkf] \u5DF2\u751F\u6210 .ywkf \u76EE\u5F55`);
600
+ }
601
+ /**
602
+ * 生成配置快照
603
+ */
604
+ generateConfigSnapshot() {
605
+ const { outputDir, config } = this.context;
606
+ const configPath = join3(outputDir, "config.json");
607
+ const serializableConfig = JSON.parse(
608
+ JSON.stringify(config, (key, value) => {
609
+ if (typeof value === "function") {
610
+ return "[Function]";
611
+ }
612
+ return value;
613
+ })
614
+ );
615
+ this.writeFileIfChanged(
616
+ configPath,
617
+ JSON.stringify(serializableConfig, null, 2)
618
+ );
619
+ }
620
+ /**
621
+ * 生成约定式路由
622
+ */
623
+ generateRoutes() {
624
+ const { cwd, outputDir, config } = this.context;
625
+ if (!config.router.conventional) {
626
+ return;
627
+ }
628
+ const pagesDir = join3(cwd, config.router.pagesDir || "src/pages");
629
+ const generator = new ConventionalRouteGenerator({
630
+ pagesDir,
631
+ outputDir,
632
+ basename: config.router.basename
633
+ });
634
+ const content = generator.generateCode();
635
+ const routesPath = join3(outputDir, "routes.tsx");
636
+ this.writeFileIfChanged(routesPath, content);
637
+ }
638
+ /**
639
+ * 生成启动文件
640
+ */
641
+ generateBootstrapFile() {
642
+ const { outputDir, config } = this.context;
643
+ const injections = this.collectInjections("bootstrap");
644
+ let content = generateBootstrap(config, injections);
645
+ for (const hooks of this.pluginHooks) {
646
+ if (hooks.modifyBootstrapCode) {
647
+ const result = hooks.modifyBootstrapCode(content, this.context);
648
+ if (result) {
649
+ content = result;
650
+ }
651
+ }
652
+ }
653
+ const bootstrapPath = join3(outputDir, "bootstrap.tsx");
654
+ this.writeFileIfChanged(bootstrapPath, content);
655
+ }
656
+ /**
657
+ * 生成入口文件
658
+ */
659
+ generateEntryFile() {
660
+ const { outputDir, config } = this.context;
661
+ const injections = this.collectInjections("entry");
662
+ let content = generateEntry(config, injections);
663
+ for (const hooks of this.pluginHooks) {
664
+ if (hooks.modifyEntryCode) {
665
+ const result = hooks.modifyEntryCode(content, this.context);
666
+ if (result) {
667
+ content = result;
668
+ }
669
+ }
670
+ }
671
+ const entryPath = join3(outputDir, "index.tsx");
672
+ this.writeFileIfChanged(entryPath, content);
673
+ }
674
+ /**
675
+ * 收集插件代码注入
676
+ */
677
+ collectInjections(type) {
678
+ const result = {
679
+ imports: [],
680
+ topLevel: [],
681
+ exports: []
682
+ };
683
+ const hookName = type === "entry" ? "injectEntry" : "injectBootstrap";
684
+ for (const hooks of this.pluginHooks) {
685
+ const hook = hooks[hookName];
686
+ if (hook) {
687
+ const injection = hook(this.context);
688
+ if (injection) {
689
+ result.imports?.push(...injection.imports || []);
690
+ result.topLevel?.push(...injection.topLevel || []);
691
+ result.exports?.push(...injection.exports || []);
692
+ }
693
+ }
694
+ }
695
+ return result;
696
+ }
697
+ /**
698
+ * 生成插件附加文件
699
+ */
700
+ async generatePluginFiles() {
701
+ const { outputDir } = this.context;
702
+ for (const hooks of this.pluginHooks) {
703
+ if (hooks.generateFiles) {
704
+ const files = hooks.generateFiles(this.context);
705
+ if (files) {
706
+ for (const file of files) {
707
+ const filePath = join3(outputDir, file.path);
708
+ const dir = join3(filePath, "..");
709
+ this.ensureDir(dir);
710
+ this.writeFileIfChanged(filePath, file.content);
711
+ }
712
+ }
713
+ }
714
+ }
715
+ }
716
+ /**
717
+ * 生成类型定义
718
+ */
719
+ generateTypes() {
720
+ const { outputDir, config, cwd } = this.context;
721
+ const envTypesContent = generateEnvTypes(cwd, config);
722
+ this.writeFileIfChanged(
723
+ join3(outputDir, "types", "env.d.ts"),
724
+ envTypesContent
725
+ );
726
+ if (config.router.conventional) {
727
+ const routeTypesContent = generateRouteTypes();
728
+ this.writeFileIfChanged(
729
+ join3(outputDir, "types", "routes.d.ts"),
730
+ routeTypesContent
731
+ );
732
+ }
733
+ }
734
+ /**
735
+ * 确保目录存在
736
+ */
737
+ ensureDir(dir) {
738
+ if (!existsSync4(dir)) {
739
+ mkdirSync2(dir, { recursive: true });
740
+ }
741
+ }
742
+ /**
743
+ * 只在内容变化时写入文件(避免触发不必要的热更新)
744
+ */
745
+ writeFileIfChanged(filePath, content) {
746
+ const normalizedContent = this.normalizeContent(content);
747
+ const lastContent = this.lastGeneratedContent.get(filePath);
748
+ if (lastContent === normalizedContent) {
749
+ return;
750
+ }
751
+ if (existsSync4(filePath)) {
752
+ const existingContent = readFileSync2(filePath, "utf-8");
753
+ if (this.normalizeContent(existingContent) === normalizedContent) {
754
+ this.lastGeneratedContent.set(filePath, normalizedContent);
755
+ return;
756
+ }
757
+ }
758
+ writeFileSync2(filePath, content, "utf-8");
759
+ this.lastGeneratedContent.set(filePath, normalizedContent);
760
+ }
761
+ /**
762
+ * 标准化内容(去掉时间戳等动态部分)
763
+ */
764
+ normalizeContent(content) {
765
+ return content.replace(/\/\/ Generated at: .+/g, "").replace(/\/\*\* Generated at: .+ \*\//g, "");
766
+ }
767
+ };
768
+
769
+ // src/generator/plugin.ts
770
+ var YwkfGeneratorPlugin = class {
771
+ options;
772
+ hasGenerated = false;
773
+ isWatching = false;
774
+ generator = null;
775
+ pluginHooks = [];
776
+ initialized = false;
777
+ constructor(options) {
778
+ this.options = options;
779
+ }
780
+ /**
781
+ * 解析插件配置为插件实例
782
+ */
783
+ async resolvePlugin(pluginConfig) {
784
+ try {
785
+ let plugin;
786
+ let options = {};
787
+ if (typeof pluginConfig === "string") {
788
+ const module = await import(pluginConfig);
789
+ plugin = module.default || module;
790
+ } else if (Array.isArray(pluginConfig)) {
791
+ const [pluginOrName, pluginOptions] = pluginConfig;
792
+ options = pluginOptions;
793
+ if (typeof pluginOrName === "string") {
794
+ const module = await import(pluginOrName);
795
+ plugin = module.default || module;
796
+ } else {
797
+ plugin = pluginOrName;
798
+ }
799
+ } else {
800
+ plugin = pluginConfig;
801
+ }
802
+ if (typeof plugin === "function") {
803
+ plugin = plugin(options);
804
+ }
805
+ return plugin;
806
+ } catch (error) {
807
+ console.error(`[ywkf] \u89E3\u6790\u63D2\u4EF6\u5931\u8D25: ${error}`);
808
+ return null;
809
+ }
810
+ }
811
+ /**
812
+ * 初始化插件钩子
813
+ */
814
+ async initialize() {
815
+ if (this.initialized) {
816
+ return;
817
+ }
818
+ const { cwd, config, isDev, pluginConfigs = [] } = this.options;
819
+ const context = {
820
+ cwd,
821
+ isDev,
822
+ isProd: !isDev,
823
+ config,
824
+ logger: {
825
+ info: (msg) => console.log(`[ywkf] ${msg}`),
826
+ warn: (msg) => console.warn(`[ywkf] ${msg}`),
827
+ error: (msg) => console.error(`[ywkf] ${msg}`),
828
+ debug: (msg) => {
829
+ if (process.env.DEBUG) {
830
+ console.log(`[ywkf:debug] ${msg}`);
831
+ }
832
+ }
833
+ }
834
+ };
835
+ for (const pluginConfig of pluginConfigs) {
836
+ const plugin = await this.resolvePlugin(pluginConfig);
837
+ if (plugin) {
838
+ const hooks = await plugin.setup(context);
839
+ this.pluginHooks.push(hooks);
840
+ console.log(`[ywkf] \u63D2\u4EF6\u5DF2\u52A0\u8F7D: ${plugin.name}`);
841
+ }
842
+ }
843
+ this.generator = new YwkfGenerator(
844
+ {
845
+ cwd: this.options.cwd,
846
+ config: this.options.config,
847
+ outputDir: this.options.outputDir,
848
+ isDev: this.options.isDev
849
+ },
850
+ this.pluginHooks
851
+ );
852
+ this.initialized = true;
853
+ }
854
+ apply(compiler) {
855
+ const pluginName = "YwkfGeneratorPlugin";
856
+ compiler.hooks.beforeCompile.tapAsync(pluginName, async (params, callback) => {
857
+ try {
858
+ await this.initialize();
859
+ if (!this.hasGenerated && this.generator) {
860
+ await this.generator.generate();
861
+ this.hasGenerated = true;
862
+ }
863
+ callback();
864
+ } catch (error) {
865
+ callback(error);
866
+ }
867
+ });
868
+ if (this.options.isDev && !this.isWatching) {
869
+ this.watchPages();
870
+ }
871
+ }
872
+ /**
873
+ * 监听页面目录变化
874
+ */
875
+ watchPages() {
876
+ const { config, cwd } = this.options;
877
+ const pagesDir = join4(cwd, config.router.pagesDir || "src/pages");
878
+ if (!existsSync5(pagesDir)) {
879
+ return;
880
+ }
881
+ this.isWatching = true;
882
+ let debounceTimer = null;
883
+ const watcher = watch(
884
+ pagesDir,
885
+ { recursive: true },
886
+ (eventType, filename) => {
887
+ if (!filename?.match(/\.(tsx?|jsx?)$/)) {
888
+ return;
889
+ }
890
+ if (debounceTimer) {
891
+ clearTimeout(debounceTimer);
892
+ }
893
+ debounceTimer = setTimeout(async () => {
894
+ console.log(`[ywkf] \u68C0\u6D4B\u5230\u9875\u9762\u53D8\u5316: ${filename}`);
895
+ if (this.generator) {
896
+ await this.generator.generate();
897
+ }
898
+ }, 500);
899
+ }
900
+ );
901
+ process.on("exit", () => {
902
+ watcher.close();
903
+ });
904
+ }
905
+ };
906
+
907
+ // src/rspack/base.ts
908
+ var require2 = createRequire(import.meta.url);
909
+ var __dirname = dirname(fileURLToPath(import.meta.url));
910
+ var coreNodeModules = join5(__dirname, "../../node_modules");
911
+ function createBaseConfig(config, cwd) {
912
+ const { resolveApp } = createPathResolver(cwd);
913
+ const {
914
+ appName,
915
+ appCName,
916
+ output,
917
+ html,
918
+ alias: userAlias,
919
+ microFrontend,
920
+ router
921
+ } = config;
922
+ const ywkfOutputDir = resolveApp(".ywkf");
923
+ const defaultAlias = {
924
+ "@": resolveApp("src"),
925
+ "@config": resolveApp("config"),
926
+ "@store": resolveApp("store"),
927
+ "@locales": resolveApp("locales"),
928
+ "@public": resolveApp("public"),
929
+ // 约定式路由生成的文件
930
+ "@ywkf/routes": join5(ywkfOutputDir, "routes.tsx"),
931
+ // 请求层(由 reactQueryPlugin 生成)
932
+ "@ywkf/request": join5(ywkfOutputDir, "request.ts"),
933
+ // Store 工具(由 zustandPlugin 生成)
934
+ "@ywkf/store": join5(ywkfOutputDir, "store.ts")
935
+ };
936
+ const alias = { ...defaultAlias, ...userAlias };
937
+ return {
938
+ // 使用 .ywkf/index.tsx 作为入口(由框架生成)
939
+ entry: [join5(ywkfOutputDir, "index.tsx")],
940
+ resolve: {
941
+ extensions: [".ts", ".tsx", ".jsx", ".js", ".json", ".mjs"],
942
+ symlinks: false,
943
+ alias: {
944
+ ...alias,
945
+ "process/browser.js": require2.resolve("process/browser.js"),
946
+ "process/browser": require2.resolve("process/browser.js"),
947
+ // 确保 React 系列包从用户项目的 node_modules 解析
948
+ react: resolveApp("node_modules/react"),
949
+ "react-dom": resolveApp("node_modules/react-dom"),
950
+ "react-router": resolveApp("node_modules/react-router")
951
+ },
952
+ fallback: {
953
+ path: require2.resolve("path-browserify"),
954
+ process: require2.resolve("process/browser.js"),
955
+ buffer: require2.resolve("buffer/"),
956
+ util: require2.resolve("util/"),
957
+ stream: require2.resolve("stream-browserify"),
958
+ crypto: require2.resolve("crypto-browserify"),
959
+ zlib: require2.resolve("browserify-zlib"),
960
+ querystring: require2.resolve("querystring-es3"),
961
+ url: require2.resolve("url/"),
962
+ assert: require2.resolve("assert/"),
963
+ fs: false,
964
+ net: false,
965
+ tls: false,
966
+ os: false,
967
+ https: false,
968
+ http: false
969
+ }
970
+ },
971
+ resolveLoader: {
972
+ modules: [coreNodeModules, "node_modules"]
973
+ },
974
+ module: {
975
+ rules: [
976
+ {
977
+ test: /\.m?js$/,
978
+ resolve: {
979
+ fullySpecified: false
980
+ }
981
+ },
982
+ {
983
+ test: /\.[jt]sx?$/,
984
+ include: [
985
+ resolveApp("src"),
986
+ resolveApp("config"),
987
+ resolveApp("store"),
988
+ resolveApp("packages"),
989
+ ywkfOutputDir
990
+ // 约定式路由生成的文件
991
+ ],
992
+ exclude: [resolveApp("node_modules")],
993
+ use: [
994
+ {
995
+ loader: "builtin:swc-loader",
996
+ options: {
997
+ jsc: {
998
+ parser: {
999
+ syntax: "typescript",
1000
+ tsx: true,
1001
+ decorators: true
1002
+ },
1003
+ transform: {
1004
+ react: {
1005
+ runtime: "automatic"
1006
+ }
1007
+ },
1008
+ target: "es2015"
1009
+ },
1010
+ sourceMaps: true
1011
+ }
1012
+ }
1013
+ ]
1014
+ },
1015
+ {
1016
+ test: /\.(png|jpg|jpeg|gif|webp|m3u8|exr|hdr|json|woff2)$/,
1017
+ include: [resolveApp("public")],
1018
+ exclude: [resolveApp("src"), resolveApp("store")],
1019
+ type: "asset",
1020
+ parser: {
1021
+ dataUrlCondition: {
1022
+ maxSize: 10 * 1024
1023
+ }
1024
+ }
1025
+ },
1026
+ {
1027
+ test: /\.(md)$/,
1028
+ include: [resolveApp("src")],
1029
+ type: "asset/source"
1030
+ },
1031
+ {
1032
+ test: /\.svg$/,
1033
+ use: ["@svgr/webpack"]
1034
+ }
1035
+ ]
1036
+ },
1037
+ plugins: [
1038
+ new rspack.ProvidePlugin({
1039
+ process: "process/browser.js",
1040
+ Buffer: ["buffer", "Buffer"]
1041
+ }),
1042
+ new rspack.DefinePlugin({
1043
+ "process.env": JSON.stringify(process.env)
1044
+ }),
1045
+ new rspack.HtmlRspackPlugin({
1046
+ template: resolveApp(html.template ?? "public/index.html"),
1047
+ filename: "index.html",
1048
+ inject: "body",
1049
+ hash: true,
1050
+ minify: process.env.NODE_ENV === "production",
1051
+ favicon: resolveApp(html.favicon ?? "public/favicon.ico"),
1052
+ templateParameters: {
1053
+ title: html.title ?? appCName,
1054
+ mountRoot: html.mountRoot ?? appName
1055
+ }
1056
+ }),
1057
+ new rspack.CopyRspackPlugin({
1058
+ patterns: [
1059
+ {
1060
+ from: resolveApp("public/images"),
1061
+ to: "public/images",
1062
+ noErrorOnMissing: true
1063
+ }
1064
+ ]
1065
+ }),
1066
+ // .ywkf 目录生成插件(传递用户配置的插件列表)
1067
+ new YwkfGeneratorPlugin({
1068
+ cwd,
1069
+ config,
1070
+ outputDir: ywkfOutputDir,
1071
+ isDev: process.env.NODE_ENV !== "production",
1072
+ pluginConfigs: config.plugins
1073
+ })
1074
+ ].filter(Boolean),
1075
+ output: {
1076
+ assetModuleFilename: "images/[hash][ext]",
1077
+ library: microFrontend.enabled ? `${appCName}-[name]` : void 0,
1078
+ chunkFilename: "[name].[contenthash].js",
1079
+ libraryTarget: microFrontend.enabled ? "umd" : void 0,
1080
+ globalObject: microFrontend.enabled ? "window" : void 0,
1081
+ chunkLoadingGlobal: microFrontend.enabled ? `chunk_global_${appName}` : void 0,
1082
+ publicPath: output.publicPath ?? "/",
1083
+ path: resolveApp(output.path ?? "dist")
1084
+ },
1085
+ ignoreWarnings: [
1086
+ {
1087
+ module: /@testing-library\/react/,
1088
+ message: /export 'act'/
1089
+ }
1090
+ ],
1091
+ devtool: "source-map"
1092
+ };
1093
+ }
1094
+
1095
+ // src/rspack/dev.ts
1096
+ var require3 = createRequire2(import.meta.url);
1097
+ function convertProxyToArray(proxy) {
1098
+ if (!proxy || Object.keys(proxy).length === 0) {
1099
+ return void 0;
1100
+ }
1101
+ return Object.entries(proxy).map(([context, target]) => {
1102
+ if (typeof target === "string") {
1103
+ return {
1104
+ context: [context],
1105
+ target,
1106
+ changeOrigin: true,
1107
+ secure: false
1108
+ };
1109
+ }
1110
+ return {
1111
+ context: [context],
1112
+ changeOrigin: true,
1113
+ secure: false,
1114
+ ...target
1115
+ };
1116
+ });
1117
+ }
1118
+ function createDevConfig(config, cwd) {
1119
+ const baseConfig = createBaseConfig(config, cwd);
1120
+ const { resolveApp } = createPathResolver(cwd);
1121
+ const { dev, style } = config;
1122
+ const styleRules = {
1123
+ rules: [
1124
+ // Less - antd
1125
+ {
1126
+ test: /\.less$/,
1127
+ include: [
1128
+ /[\\/]node_modules[\\/].*antd/,
1129
+ /[\\/]node_modules[\\/]@4399ywkf[\\/]design/
1130
+ ],
1131
+ use: [
1132
+ { loader: "style-loader" },
1133
+ {
1134
+ loader: "css-loader",
1135
+ options: { sourceMap: true }
1136
+ },
1137
+ {
1138
+ loader: "less-loader",
1139
+ options: {
1140
+ sourceMap: true,
1141
+ lessOptions: {
1142
+ strictMath: false,
1143
+ math: "always",
1144
+ javascriptEnabled: true
1145
+ }
1146
+ }
1147
+ }
1148
+ ]
1149
+ },
1150
+ // Less - 项目文件
1151
+ ...style.less?.enabled !== false ? [
1152
+ {
1153
+ test: /\.less$/,
1154
+ include: [resolveApp("src")],
1155
+ exclude: [resolveApp("node_modules")],
1156
+ oneOf: [
1157
+ {
1158
+ test: /\.module\.less$/,
1159
+ use: [
1160
+ { loader: "style-loader" },
1161
+ {
1162
+ loader: "css-loader",
1163
+ options: {
1164
+ sourceMap: true,
1165
+ modules: {
1166
+ localIdentName: "[path][name]__[local]--[hash:base64:5]"
1167
+ },
1168
+ importLoaders: 2
1169
+ }
1170
+ },
1171
+ {
1172
+ loader: "less-loader",
1173
+ options: {
1174
+ sourceMap: true,
1175
+ lessOptions: {
1176
+ javascriptEnabled: true,
1177
+ math: "always",
1178
+ ...style.less?.lessOptions
1179
+ }
1180
+ }
1181
+ }
1182
+ ]
1183
+ },
1184
+ {
1185
+ use: [
1186
+ { loader: "style-loader" },
1187
+ {
1188
+ loader: "css-loader",
1189
+ options: { sourceMap: true }
1190
+ },
1191
+ {
1192
+ loader: "less-loader",
1193
+ options: {
1194
+ sourceMap: true,
1195
+ lessOptions: {
1196
+ javascriptEnabled: true,
1197
+ ...style.less?.lessOptions
1198
+ }
1199
+ }
1200
+ }
1201
+ ]
1202
+ }
1203
+ ]
1204
+ }
1205
+ ] : [],
1206
+ // Sass
1207
+ ...style.sass?.enabled !== false ? [
1208
+ {
1209
+ test: /\.s[ac]ss$/i,
1210
+ include: [resolveApp("src")],
1211
+ exclude: [resolveApp("node_modules")],
1212
+ oneOf: [
1213
+ {
1214
+ test: /\.module\.s[ac]ss$/,
1215
+ use: [
1216
+ { loader: "style-loader" },
1217
+ {
1218
+ loader: "css-loader",
1219
+ options: {
1220
+ sourceMap: true,
1221
+ modules: {
1222
+ localIdentName: "[path][name]__[local]--[hash:base64:5]"
1223
+ },
1224
+ importLoaders: 2
1225
+ }
1226
+ },
1227
+ {
1228
+ loader: "sass-loader",
1229
+ options: {
1230
+ sourceMap: true,
1231
+ sassOptions: {
1232
+ outputStyle: "compressed",
1233
+ ...style.sass?.sassOptions
1234
+ }
1235
+ }
1236
+ }
1237
+ ]
1238
+ },
1239
+ {
1240
+ use: [
1241
+ { loader: "style-loader" },
1242
+ {
1243
+ loader: "css-loader",
1244
+ options: { sourceMap: true }
1245
+ },
1246
+ {
1247
+ loader: "sass-loader",
1248
+ options: {
1249
+ sourceMap: true,
1250
+ sassOptions: {
1251
+ outputStyle: "compressed",
1252
+ ...style.sass?.sassOptions
1253
+ }
1254
+ }
1255
+ }
1256
+ ]
1257
+ }
1258
+ ]
1259
+ }
1260
+ ] : [],
1261
+ // TailwindCSS
1262
+ ...style.tailwindcss ? [
1263
+ {
1264
+ test: /\.css$/,
1265
+ include: [resolveApp("src/index.css")],
1266
+ use: [
1267
+ "style-loader",
1268
+ "css-loader",
1269
+ {
1270
+ loader: "postcss-loader",
1271
+ options: {
1272
+ postcssOptions: {
1273
+ config: resolveApp("postcss.config.js")
1274
+ }
1275
+ }
1276
+ }
1277
+ ]
1278
+ }
1279
+ ] : [],
1280
+ // 其他 CSS
1281
+ {
1282
+ test: /\.css$/,
1283
+ include: [resolveApp("src"), resolveApp("node_modules")],
1284
+ exclude: style.tailwindcss ? [resolveApp("src/index.css")] : [],
1285
+ use: [
1286
+ { loader: "style-loader" },
1287
+ {
1288
+ loader: "css-loader",
1289
+ options: { sourceMap: true }
1290
+ }
1291
+ ]
1292
+ }
1293
+ ]
1294
+ };
1295
+ const devConfig = {
1296
+ mode: "development",
1297
+ devtool: "inline-source-map",
1298
+ output: {
1299
+ filename: "[name].bundle.js",
1300
+ clean: false
1301
+ },
1302
+ stats: "errors-only",
1303
+ devServer: {
1304
+ host: dev.host,
1305
+ port: dev.port,
1306
+ compress: true,
1307
+ historyApiFallback: true,
1308
+ hot: true,
1309
+ allowedHosts: "all",
1310
+ client: {
1311
+ overlay: false,
1312
+ progress: true
1313
+ },
1314
+ proxy: convertProxyToArray(dev.proxy)
1315
+ },
1316
+ module: styleRules
1317
+ };
1318
+ return merge(baseConfig, devConfig);
1319
+ }
1320
+
1321
+ // src/rspack/prod.ts
1322
+ import { rspack as rspack2 } from "@rspack/core";
1323
+ import { merge as merge2 } from "webpack-merge";
1324
+ function createProdConfig(config, cwd) {
1325
+ const baseConfig = createBaseConfig(config, cwd);
1326
+ const { resolveApp } = createPathResolver(cwd);
1327
+ const { style, performance, output } = config;
1328
+ const styleRules = {
1329
+ rules: [
1330
+ // Less - antd
1331
+ {
1332
+ test: /\.less$/,
1333
+ include: [
1334
+ /[\\/]node_modules[\\/].*antd/,
1335
+ /[\\/]node_modules[\\/]@4399ywkf[\\/]design/
1336
+ ],
1337
+ use: [
1338
+ { loader: rspack2.CssExtractRspackPlugin.loader },
1339
+ {
1340
+ loader: "css-loader",
1341
+ options: { sourceMap: true }
1342
+ },
1343
+ {
1344
+ loader: "less-loader",
1345
+ options: {
1346
+ sourceMap: true,
1347
+ lessOptions: {
1348
+ strictMath: false,
1349
+ math: "always",
1350
+ javascriptEnabled: true
1351
+ }
1352
+ }
1353
+ }
1354
+ ]
1355
+ },
1356
+ // Less - 项目文件
1357
+ ...style.less?.enabled !== false ? [
1358
+ {
1359
+ test: /\.less$/,
1360
+ include: [resolveApp("src")],
1361
+ exclude: [resolveApp("node_modules")],
1362
+ oneOf: [
1363
+ {
1364
+ test: /\.module\.less$/,
1365
+ use: [
1366
+ { loader: rspack2.CssExtractRspackPlugin.loader },
1367
+ {
1368
+ loader: "css-loader",
1369
+ options: {
1370
+ sourceMap: true,
1371
+ modules: {
1372
+ localIdentName: "[path][name]__[local]--[hash:base64:5]"
1373
+ },
1374
+ importLoaders: 2
1375
+ }
1376
+ },
1377
+ {
1378
+ loader: "less-loader",
1379
+ options: {
1380
+ sourceMap: true,
1381
+ lessOptions: {
1382
+ javascriptEnabled: true,
1383
+ ...style.less?.lessOptions
1384
+ }
1385
+ }
1386
+ }
1387
+ ]
1388
+ },
1389
+ {
1390
+ use: [
1391
+ { loader: rspack2.CssExtractRspackPlugin.loader },
1392
+ {
1393
+ loader: "css-loader",
1394
+ options: { sourceMap: true }
1395
+ },
1396
+ {
1397
+ loader: "less-loader",
1398
+ options: {
1399
+ sourceMap: true,
1400
+ lessOptions: {
1401
+ javascriptEnabled: true,
1402
+ ...style.less?.lessOptions
1403
+ }
1404
+ }
1405
+ }
1406
+ ]
1407
+ }
1408
+ ]
1409
+ }
1410
+ ] : [],
1411
+ // Sass
1412
+ ...style.sass?.enabled !== false ? [
1413
+ {
1414
+ test: /\.s[ac]ss$/i,
1415
+ include: [resolveApp("src")],
1416
+ exclude: [resolveApp("node_modules")],
1417
+ oneOf: [
1418
+ {
1419
+ test: /\.module\.s[ac]ss$/,
1420
+ use: [
1421
+ { loader: rspack2.CssExtractRspackPlugin.loader },
1422
+ {
1423
+ loader: "css-loader",
1424
+ options: {
1425
+ sourceMap: true,
1426
+ modules: {
1427
+ localIdentName: "[path][name]__[local]--[hash:base64:5]"
1428
+ },
1429
+ importLoaders: 2
1430
+ }
1431
+ },
1432
+ {
1433
+ loader: "sass-loader",
1434
+ options: {
1435
+ sourceMap: true,
1436
+ sassOptions: {
1437
+ outputStyle: "compressed",
1438
+ ...style.sass?.sassOptions
1439
+ }
1440
+ }
1441
+ }
1442
+ ]
1443
+ },
1444
+ {
1445
+ use: [
1446
+ { loader: rspack2.CssExtractRspackPlugin.loader },
1447
+ {
1448
+ loader: "css-loader",
1449
+ options: { sourceMap: true }
1450
+ },
1451
+ {
1452
+ loader: "sass-loader",
1453
+ options: {
1454
+ sourceMap: true,
1455
+ sassOptions: {
1456
+ outputStyle: "compressed",
1457
+ ...style.sass?.sassOptions
1458
+ }
1459
+ }
1460
+ }
1461
+ ]
1462
+ }
1463
+ ]
1464
+ }
1465
+ ] : [],
1466
+ // TailwindCSS
1467
+ ...style.tailwindcss ? [
1468
+ {
1469
+ test: /\.css$/,
1470
+ include: [resolveApp("src/index.css")],
1471
+ use: [
1472
+ { loader: rspack2.CssExtractRspackPlugin.loader },
1473
+ "css-loader",
1474
+ {
1475
+ loader: "postcss-loader",
1476
+ options: {
1477
+ postcssOptions: {
1478
+ config: resolveApp("postcss.config.js")
1479
+ }
1480
+ }
1481
+ }
1482
+ ]
1483
+ }
1484
+ ] : [],
1485
+ // src 目录中的其他 CSS
1486
+ {
1487
+ test: /\.css$/,
1488
+ include: [resolveApp("src")],
1489
+ exclude: style.tailwindcss ? [resolveApp("src/index.css")] : [],
1490
+ use: [
1491
+ { loader: rspack2.CssExtractRspackPlugin.loader },
1492
+ {
1493
+ loader: "css-loader",
1494
+ options: { sourceMap: true }
1495
+ }
1496
+ ]
1497
+ },
1498
+ // node_modules CSS
1499
+ {
1500
+ test: /\.css$/,
1501
+ include: [resolveApp("node_modules")],
1502
+ use: [
1503
+ { loader: "style-loader" },
1504
+ {
1505
+ loader: "css-loader",
1506
+ options: { sourceMap: true }
1507
+ }
1508
+ ]
1509
+ }
1510
+ ]
1511
+ };
1512
+ const prodConfig = {
1513
+ mode: "production",
1514
+ devtool: "hidden-source-map",
1515
+ output: {
1516
+ filename: "[name].[contenthash].bundle.js",
1517
+ chunkFilename: "[name].[contenthash].chunk.js",
1518
+ clean: output.clean
1519
+ },
1520
+ module: styleRules,
1521
+ plugins: [
1522
+ new rspack2.CssExtractRspackPlugin({
1523
+ filename: "[name].[contenthash:8].css",
1524
+ chunkFilename: "[name].[contenthash:8].chunk.css"
1525
+ })
1526
+ ],
1527
+ optimization: {
1528
+ minimize: true,
1529
+ minimizer: [
1530
+ new rspack2.SwcJsMinimizerRspackPlugin({
1531
+ exclude: [resolveApp("node_modules")],
1532
+ minimizerOptions: {
1533
+ compress: {
1534
+ pure_funcs: performance.dropConsole ? ["console.log", "console.info", "console.debug", "console.warn"] : ["console.info", "console.debug"],
1535
+ drop_console: false,
1536
+ drop_debugger: true
1537
+ }
1538
+ }
1539
+ }),
1540
+ new rspack2.LightningCssMinimizerRspackPlugin()
1541
+ ]
1542
+ }
1543
+ };
1544
+ return merge2(baseConfig, prodConfig);
1545
+ }
1546
+
1547
+ // src/rspack/index.ts
1548
+ function createRspackConfig(config, cwd, options = {}) {
1549
+ const isDev = options.isDev ?? process.env.NODE_ENV !== "production";
1550
+ let rspackConfig = isDev ? createDevConfig(config, cwd) : createProdConfig(config, cwd);
1551
+ if (config.performance.rsdoctor) {
1552
+ rspackConfig.plugins = [
1553
+ ...rspackConfig.plugins || [],
1554
+ new RsdoctorRspackPlugin({})
1555
+ ];
1556
+ }
1557
+ if (config.tools.rspack) {
1558
+ const userConfig = config.tools.rspack(rspackConfig, {
1559
+ isDev,
1560
+ isProd: !isDev
1561
+ });
1562
+ if (userConfig) {
1563
+ rspackConfig = userConfig;
1564
+ }
1565
+ }
1566
+ return rspackConfig;
1567
+ }
1568
+ export {
1569
+ createBaseConfig,
1570
+ createDevConfig,
1571
+ createProdConfig,
1572
+ createRspackConfig
1573
+ };
1574
+ //# sourceMappingURL=index.js.map