@yannick-z/modulo 0.2.0 → 0.3.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 (55) hide show
  1. package/.vscode/extensions.json +3 -0
  2. package/README.md +57 -60
  3. package/bin/modulo.js +29 -19
  4. package/biome.json +34 -0
  5. package/package.json +35 -35
  6. package/rslib.config.ts +19 -19
  7. package/src/args/get-framework-name.ts +7 -7
  8. package/src/args/index.ts +16 -74
  9. package/src/args/preset.ts +16 -16
  10. package/src/cli/init.ts +10 -6
  11. package/src/cli/pack-code.ts +20 -9
  12. package/src/config/example/example-config.ts +50 -39
  13. package/src/config/example/example-externals.ts +21 -37
  14. package/src/config/index.ts +186 -16
  15. package/src/config/presets.ts +100 -0
  16. package/src/config/type.ts +34 -12
  17. package/src/index.ts +102 -10
  18. package/src/initiator/create-config-file.ts +52 -36
  19. package/src/initiator/create-project.ts +249 -0
  20. package/src/initiator/modify-scripts.ts +42 -42
  21. package/src/packer/auto-external-plugin.ts +110 -0
  22. package/src/packer/collect-modules.ts +58 -69
  23. package/src/packer/get-externals-and-tags.ts +78 -55
  24. package/src/packer/lib.ts +76 -69
  25. package/src/packer/page.ts +106 -82
  26. package/src/packer/prepare.ts +63 -57
  27. package/src/tools/cli.ts +21 -0
  28. package/src/tools/file.ts +84 -14
  29. package/src/tools/find-path-root.ts +52 -25
  30. package/src/tools/get-framework-name.ts +7 -7
  31. package/src/tools/get-ui-plugin.ts +27 -13
  32. package/src/tools/json.ts +63 -9
  33. package/src/tools/log.ts +58 -0
  34. package/src/tools/merge-user-config.ts +17 -17
  35. package/src/tools/omit-root-path.ts +17 -7
  36. package/src/tools/panic.ts +12 -8
  37. package/src/tools/string.ts +13 -2
  38. package/src/type/guard.ts +22 -3
  39. package/tsconfig.json +9 -9
  40. package/dist/index.js +0 -773
  41. package/src/args/cmd.ts +0 -16
  42. package/src/args/mode.ts +0 -38
  43. package/src/args/node_env.ts +0 -15
  44. package/src/args/target.ts +0 -44
  45. package/src/config/externals.ts +0 -70
  46. package/src/config/generate_config.ts +0 -105
  47. package/src/config/preset/alias.ts +0 -3
  48. package/src/config/preset/dev-server.ts +0 -6
  49. package/src/config/preset/dirs.ts +0 -12
  50. package/src/config/preset/html.ts +0 -19
  51. package/src/config/preset/index.ts +0 -23
  52. package/src/config/preset/libs.ts +0 -5
  53. package/src/config/preset/minify.ts +0 -24
  54. package/src/config/preset/url.ts +0 -4
  55. package/src/tools/debug-log.ts +0 -37
package/dist/index.js DELETED
@@ -1,773 +0,0 @@
1
- import minimist from "minimist";
2
- import picocolors from "picocolors";
3
- import node_fs, { appendFileSync, existsSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
4
- import node_path, { dirname, join, resolve as external_node_path_resolve } from "node:path";
5
- import node_readline from "node:readline";
6
- import { cwd, exit } from "node:process";
7
- import { pluginLess } from "@rsbuild/plugin-less";
8
- import { build, defineConfig } from "@rslib/core";
9
- import { pluginReact } from "@rsbuild/plugin-react";
10
- import { pluginVue2 } from "@rsbuild/plugin-vue2";
11
- import { createRsbuild, defineConfig as core_defineConfig } from "@rsbuild/core";
12
- import { fileURLToPath } from "node:url";
13
- import { pluginUmd } from "@rsbuild/plugin-umd";
14
- const logFile = join(process.cwd(), "modulo.debug.log");
15
- let index = 0;
16
- let debug_log_function;
17
- function debug_log(_hint, ..._params) {
18
- if (!debug_log_function) debug_log_function = (hint, ...params)=>{
19
- if (argv_debug || argv_verbose) {
20
- const timestamp = new Date().toISOString();
21
- const sn = String(index++).padStart(3, "0");
22
- const logEntry = `--------------\n${sn} [${timestamp}] ${hint}\n${params.map((p)=>"object" == typeof p ? JSON.stringify(p, null, 2) : String(p)).join("\n")}\n---------------\n\n`;
23
- if (argv_verbose) console.log(logEntry);
24
- if (argv_debug) {
25
- console.log(picocolors.blue(`\ndebug log ${sn}`));
26
- appendFileSync(logFile, logEntry);
27
- }
28
- }
29
- };
30
- debug_log_function(_hint, ..._params);
31
- }
32
- function read_file(path, error_msg) {
33
- try {
34
- return readFileSync(path, 'utf8');
35
- } catch {
36
- console.log(picocolors.red(error_msg || `文件无法访问或者不存在: ${path}`));
37
- return '';
38
- }
39
- }
40
- function resolve_and_read(root, name) {
41
- const fullpath = external_node_path_resolve(root, name);
42
- debug_log(`resolve file: ${name}`, 'result is:', fullpath);
43
- return read_file(fullpath);
44
- }
45
- function jsonparse(input) {
46
- try {
47
- if (input) return JSON.parse(input);
48
- } catch (e) {
49
- console.error(picocolors.red(`JSON.parse failed\n${e}`));
50
- }
51
- }
52
- const panic_alert = '! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! !';
53
- function PANIC_IF(status = false, msg = "SOMETHING'S WRONG", halt = true) {
54
- if (status) {
55
- console.log(picocolors.bgRed(picocolors.white(`\n${panic_alert}\n\n${msg}\n\n${panic_alert}`)), '\n');
56
- halt && exit(1);
57
- }
58
- }
59
- function merge_user_config(target, input) {
60
- for(const key in input){
61
- const from = input[key];
62
- const to = target[key];
63
- if (typeof from === typeof to && key in target) if (Array.isArray(to)) {
64
- PANIC_IF(!Array.isArray(from));
65
- target[key] = [
66
- ...to,
67
- ...from
68
- ];
69
- } else if ("object" == typeof to) merge_user_config(to, from);
70
- else target[key] = from;
71
- else {
72
- target[key] = from;
73
- continue;
74
- }
75
- }
76
- }
77
- const preset_alias = {
78
- "@": "{input.src}"
79
- };
80
- const preset_dev_server_config = {
81
- open: false,
82
- port: 8080,
83
- proxy: {}
84
- };
85
- const preset_input_dirs = {
86
- src: "src",
87
- pages: "pages",
88
- modules: "modules"
89
- };
90
- const preset_output_dirs = {
91
- dist: "dist",
92
- pages: "",
93
- modules: "modules",
94
- filenameHash: true
95
- };
96
- const default_html_config = {
97
- meta: {},
98
- root: '',
99
- tags: [],
100
- template: '',
101
- title: ''
102
- };
103
- const preset_ui_libs = {
104
- react: '17.0.2',
105
- vue: '2.7.16'
106
- };
107
- const preset_minify_config = {
108
- js: true,
109
- jsOptions: {
110
- minimizerOptions: {
111
- compress: {
112
- dead_code: true,
113
- defaults: false,
114
- toplevel: true,
115
- unused: true
116
- },
117
- format: {
118
- comments: "some",
119
- ecma: 2015,
120
- preserve_annotations: true,
121
- safari10: true,
122
- semicolons: false
123
- },
124
- mangle: true,
125
- minify: true
126
- }
127
- }
128
- };
129
- const preset_url_config = {
130
- base: '/',
131
- cdn: ''
132
- };
133
- const preset_config = {
134
- analyze: false,
135
- define: {},
136
- dev_server: preset_dev_server_config,
137
- externals: {},
138
- html: default_html_config,
139
- input: preset_input_dirs,
140
- minify: preset_minify_config,
141
- output: preset_output_dirs,
142
- ui_lib: preset_ui_libs,
143
- url: preset_url_config,
144
- alias: preset_alias
145
- };
146
- const generate_config_root = cwd();
147
- let generate_config_global_config;
148
- function get_global_config(args) {
149
- if (!generate_config_global_config) {
150
- const user_config = jsonparse(resolve_and_read(generate_config_root, args.pack.config));
151
- PANIC_IF(!user_config, "根目录下没有配置文件");
152
- debug_log("input user config", user_config);
153
- merge_user_config(preset_config, user_config);
154
- const _config = preset_config;
155
- const src = external_node_path_resolve(generate_config_root, _config.input.src);
156
- const input = {
157
- modules: external_node_path_resolve(src, _config.input.modules),
158
- pages: external_node_path_resolve(src, _config.input.pages),
159
- src: src
160
- };
161
- const dist = external_node_path_resolve(generate_config_root, _config.output.dist);
162
- const output = {
163
- ..._config.output,
164
- dist: dist,
165
- modules: external_node_path_resolve(dist, _config.output.modules),
166
- pages: external_node_path_resolve(dist, _config.output.pages)
167
- };
168
- const html = _config.html?.template ? {
169
- ..._config.html,
170
- template: external_node_path_resolve(generate_config_root, _config.html.template)
171
- } : _config.html;
172
- const define = Object.fromEntries(Object.entries({
173
- ..._config.define,
174
- "process.env.NODE_ENV": process.env.NODE_ENV,
175
- "import.meta.env.MOUNT_ID": _config.html.root
176
- }).map(([k, v])=>[
177
- k,
178
- JSON.stringify(v)
179
- ]));
180
- debug_log("当前模式", process.env.NODE_ENV);
181
- const minify = true === _config.minify ? preset_minify_config : _config.minify;
182
- const alias = Object.fromEntries(Object.entries(_config.alias).map(([k, v])=>[
183
- k,
184
- v.replace("{input.src}", input.src)
185
- ]));
186
- generate_config_global_config = {
187
- ..._config,
188
- define,
189
- html,
190
- input,
191
- minify,
192
- output,
193
- alias
194
- };
195
- debug_log("global config", generate_config_global_config);
196
- }
197
- return generate_config_global_config;
198
- }
199
- let config_packagejson = null;
200
- function get_packagejson() {
201
- if (!config_packagejson) {
202
- config_packagejson = jsonparse(resolve_and_read(generate_config_root, "package.json"));
203
- PANIC_IF(!config_packagejson, "根目录下没有package.json");
204
- PANIC_IF(!config_packagejson.name, "package.json缺少name字段");
205
- }
206
- return config_packagejson;
207
- }
208
- const star_line = "**********************";
209
- async function modify_scripts() {
210
- const packagejson = get_packagejson();
211
- const new_scripts = {
212
- ...packagejson.scripts || {},
213
- "build:page": "modulo build page",
214
- "build:module": "modulo build module",
215
- "build:all": "modulo build all",
216
- build: "modulo build all",
217
- "dev:page": "modulo dev page",
218
- "dev:module": "modulo dev module",
219
- "watch:page": "modulo build page --watch=true",
220
- "watch:module": "modulo build module --watch=true"
221
- };
222
- console.log(picocolors.magentaBright(`\n${star_line}修改package.json中的scripts\n新的内容修改后如下:\n${JSON.stringify(new_scripts, null, 2)}\n${star_line}`));
223
- const rl = node_readline.createInterface({
224
- input: process.stdin,
225
- output: process.stdout
226
- });
227
- const answer = await new Promise((resolve)=>{
228
- rl.question("\n确定修改吗?请输入(Y/N) ", (answer)=>{
229
- rl.close();
230
- resolve(answer);
231
- });
232
- });
233
- if ("y" !== answer.toLowerCase()) return void console.log("取消修改");
234
- packagejson.scripts = new_scripts;
235
- const new_packagejson = JSON.stringify(packagejson, null, 2);
236
- writeFileSync(external_node_path_resolve(process.cwd(), "package.json"), new_packagejson);
237
- console.log(picocolors.green(`\npackage.json修改成功`));
238
- }
239
- const vue_example_externals = {
240
- vue: {
241
- importName: [
242
- "vue",
243
- "Vue"
244
- ],
245
- url: {
246
- umd: "https://cdn.jsdelivr.net/npm/vue@2.7.16/dist/vue.min.js",
247
- esm: "https://cdn.jsdelivr.net/npm/vue@2.7.16/+esm"
248
- }
249
- }
250
- };
251
- const react_example_externals = {
252
- react: {
253
- importName: [
254
- "react",
255
- "React"
256
- ],
257
- url: {
258
- umd: "https://cdn.jsdelivr.net/npm/react@17.0.2/umd/react.production.min.js",
259
- esm: "https://cdn.jsdelivr.net/npm/react@17.0.2/+esm"
260
- }
261
- },
262
- "react-dom": {
263
- umd: "/packages/common/js/react-17.0.2/umd/react-dom.production.min.js",
264
- esm: "https://cdn.jsdelivr.net/npm/react-dom@17.0.2/+esm"
265
- },
266
- "react/jsx-runtime": {
267
- umd: "/packages/common/js/react-17.0.2/umd/react-jsx-runtime.js",
268
- esm: "/packages/common/js/react-17.0.2/esm/react-jsx-runtime.js"
269
- }
270
- };
271
- const common_example_externals = {
272
- jquery: "https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js",
273
- rxjs: {
274
- umd: "https://cdn.jsdelivr.net/npm/rxjs@7.8.2/dist/bundles/rxjs.umd.min.js",
275
- esm: "https://cdn.jsdelivr.net/npm/rxjs@7.8.2/+esm"
276
- }
277
- };
278
- const presets = {
279
- vue: {
280
- ...vue_example_externals,
281
- ...common_example_externals
282
- },
283
- react: {
284
- ...react_example_externals,
285
- ...common_example_externals
286
- }
287
- };
288
- function get_example_config(preset) {
289
- console.log(picocolors.magenta(`\n${star_line}\n默认配置文件中的externals内容为推荐内容\n请注意手动替换配置文件中externals的url,以保证符合项目需求\n如果不需要externals部分依赖,也可以将他们从列表中删除\n${star_line}\n`));
290
- return {
291
- input: preset_config.input,
292
- output: {
293
- filenameHash: true
294
- },
295
- url: {
296
- base: "/"
297
- },
298
- alias: preset_alias,
299
- html: {
300
- root: "app",
301
- title: "Modulo Page",
302
- meta: {},
303
- tags: [
304
- {
305
- tag: "script",
306
- attrs: {
307
- src: "/packages/webhost/dist/webhost.system.js"
308
- },
309
- append: false,
310
- publicPath: false
311
- }
312
- ]
313
- },
314
- dev_server: {
315
- proxy: preset_config.dev_server.proxy
316
- },
317
- externals: preset ? presets[preset] : common_example_externals
318
- };
319
- }
320
- const default_config_file_name = "modulo.config.json";
321
- function get_cmd(argv) {
322
- const cmd_list = [
323
- "build",
324
- "dev",
325
- "init"
326
- ];
327
- const cmd = argv._[0];
328
- PANIC_IF(!cmd_list.includes(cmd), `modulo必须执行 ${cmd_list.join(" 或 ")} 命令`);
329
- return cmd;
330
- }
331
- const mode_list = [
332
- "dev",
333
- "development",
334
- "prd",
335
- "production"
336
- ];
337
- function get_env(argv, cmd) {
338
- let env = "";
339
- if (argv.env) {
340
- if ("dev" === argv.env || "development" === argv.env) env = "dev";
341
- else if ("prd" === argv.env || "production" === argv.env) env = "prd";
342
- else PANIC_IF(true, `env参数只能为 ${mode_list.join(" 或 ")}`);
343
- console.log(picocolors.blue(`env = ${env}`));
344
- } else if ("build" === cmd || "dev" === cmd) if (process.env.NODE_ENV) {
345
- env = "production" === process.env.NODE_ENV ? "prd" : "dev";
346
- console.log(picocolors.yellow("\n未设置env,将根据process.env.NODE_ENV自动设置\n"), picocolors.yellow(`process.env.NODE_ENV = ${process.env.NODE_ENV}, env = ${env}`));
347
- } else {
348
- env = "build" === cmd ? "prd" : "dev";
349
- console.log(picocolors.yellow("\n未设置env,将根据build或dev命令自动设置\n"), picocolors.yellow(`cmd = ${cmd}, env = ${env}`));
350
- }
351
- return env;
352
- }
353
- function set_node_env(mode) {
354
- const _node_env = 'dev' === mode ? 'development' : 'production';
355
- if (process.env.NODE_ENV !== _node_env) {
356
- console.log(picocolors.yellow('\nprocess.env.NODE_ENV 与 mode 不一致, 将被强制设置为与mode匹配的值\n'), picocolors.yellow(`mode = ${mode}, process.env.NODE_ENV = ${_node_env}\n`));
357
- process.env.NODE_ENV = _node_env;
358
- }
359
- }
360
- let get_framework_name_framework_name;
361
- function get_framework_name() {
362
- if (!get_framework_name_framework_name) {
363
- const { dependencies } = get_packagejson();
364
- PANIC_IF(!('vue' in dependencies || 'react' in dependencies), 'package.json中未识别到支持的ui库信息, 当前只支持vue和react');
365
- get_framework_name_framework_name = 'vue' in dependencies ? 'vue' : 'react';
366
- }
367
- return get_framework_name_framework_name;
368
- }
369
- function get_preset_for_init(argv) {
370
- let preset = argv.preset;
371
- if (!preset) {
372
- preset = get_framework_name();
373
- console.log(picocolors.blue("未输入preset,但是根据package.json中的依赖自动识别到preset为: " + preset));
374
- }
375
- preset && PANIC_IF("react" !== preset && "vue" !== preset, "目前只支持react和vue");
376
- return preset;
377
- }
378
- const pack_options = {
379
- page: "构建页面",
380
- module: "构建模块",
381
- all: "页面和模块"
382
- };
383
- const init_options = {
384
- config: "modulo的配置文件",
385
- script: "package.json中modulo的启动命令"
386
- };
387
- const target_options = {
388
- build: pack_options,
389
- dev: {
390
- page: pack_options.page,
391
- module: pack_options.module
392
- },
393
- init: init_options
394
- };
395
- function get_cmd_target(argv, cmd) {
396
- const target = argv._[1];
397
- const target_list = target_options[cmd];
398
- PANIC_IF(!(target in target_list), `modulo ${cmd} 命令必须执行 ${Object.entries(target_list).map(([k, v])=>`\n${k} - ${v}`)} 几种目标`);
399
- return target;
400
- }
401
- let args_args;
402
- const args_argv = minimist(process.argv.slice(2));
403
- const argv_debug = "true" === args_argv.debug;
404
- const argv_verbose = "true" === args_argv.verbose || args_argv.v;
405
- function get_args() {
406
- if (!args_args) {
407
- const cmd = get_cmd(args_argv);
408
- if ("build" === cmd || "dev" === cmd) {
409
- const target = get_cmd_target(args_argv, cmd);
410
- const watch = "all" === target ? false : "true" === args_argv.watch || args_argv.w;
411
- args_args = {
412
- cmd,
413
- target,
414
- pack: {
415
- config: args_argv.config || default_config_file_name,
416
- env: "build" === cmd || "dev" === cmd ? get_env(args_argv, cmd) : "prd",
417
- watch,
418
- esm: "esm" === args_argv.format || "esm" === args_argv.f
419
- }
420
- };
421
- args_args.pack.env && set_node_env(args_args.pack.env);
422
- } else args_args = {
423
- cmd,
424
- target: get_cmd_target(args_argv, cmd),
425
- init: {
426
- path: args_argv.path,
427
- force: "true" === args_argv.force || args_argv.f,
428
- preset: get_preset_for_init(args_argv)
429
- }
430
- };
431
- if (argv_verbose) console.log("args: ", args_args);
432
- }
433
- return args_args;
434
- }
435
- async function create_config_file(args) {
436
- const path = args.init.path || default_config_file_name;
437
- console.log(picocolors.blue("即将创建配置文件"), path);
438
- const filepath = external_node_path_resolve(process.cwd(), path);
439
- if (existsSync(filepath)) if (args.init.force) console.log(picocolors.bgRed(picocolors.white("配置文件已存在,将覆盖")));
440
- else {
441
- console.log(picocolors.red("配置文件已存在,是否覆盖?"));
442
- const rl = node_readline.createInterface({
443
- input: process.stdin,
444
- output: process.stdout
445
- });
446
- const answer = await new Promise((resolve)=>{
447
- rl.question("\n请输入(Y/N) ", (answer)=>{
448
- rl.close();
449
- resolve(answer);
450
- });
451
- });
452
- if ("y" !== answer.toLowerCase()) return void console.log("取消创建");
453
- }
454
- writeFileSync(filepath, JSON.stringify(get_example_config(args.init.preset), null, 2));
455
- console.log(picocolors.green("创建成功"), filepath);
456
- }
457
- function init_tool(args) {
458
- if ("config" === args.target) create_config_file(args);
459
- if ("script" === args.target) modify_scripts();
460
- }
461
- function framework_plugin(options) {
462
- const { dependencies } = get_packagejson();
463
- const framework_name = get_framework_name();
464
- const version = dependencies[framework_name];
465
- const global_config = get_global_config();
466
- PANIC_IF(global_config.ui_lib[framework_name] !== version, "package.json中只允许使用固定版本号, 并且只支持vue-2.7.16和react-17.0.2");
467
- return "vue" === framework_name ? pluginVue2(options) : pluginReact(options);
468
- }
469
- function collect_modules(args, kind) {
470
- const global_config = get_global_config(args);
471
- const framework_name = get_framework_name();
472
- const module_path = global_config.input[`${kind}s`];
473
- const exist = existsSync(module_path);
474
- debug_log(picocolors.blue("check module_path"), module_path, exist ? "exists" : "NOT exists");
475
- const module_entries = exist ? readdirSync(module_path, {
476
- withFileTypes: true
477
- }).filter((item)=>{
478
- debug_log("checking module is directory", item.name, item.isDirectory());
479
- return item.isDirectory();
480
- }).map((dirent)=>{
481
- const dir_path = external_node_path_resolve(module_path, dirent.name);
482
- const entry_file_path = [
483
- external_node_path_resolve(dir_path, "index.ts"),
484
- external_node_path_resolve(dir_path, "index.tsx"),
485
- external_node_path_resolve(dir_path, "index.js"),
486
- external_node_path_resolve(dir_path, "index.jsx"),
487
- external_node_path_resolve(dir_path, "main.ts"),
488
- external_node_path_resolve(dir_path, "main.tsx"),
489
- external_node_path_resolve(dir_path, "main.js"),
490
- external_node_path_resolve(dir_path, "main.jsx"),
491
- ..."vue" === framework_name ? [
492
- external_node_path_resolve(dir_path, "index.vue"),
493
- external_node_path_resolve(dir_path, "main.vue"),
494
- external_node_path_resolve(dir_path, `${dirent.name}.vue`)
495
- ] : [],
496
- external_node_path_resolve(dir_path, `${dirent.name}.ts`),
497
- external_node_path_resolve(dir_path, `${dirent.name}.tsx`),
498
- external_node_path_resolve(dir_path, `${dirent.name}.js`),
499
- external_node_path_resolve(dir_path, `${dirent.name}.jsx`)
500
- ].find((path)=>{
501
- const exists = existsSync(path);
502
- debug_log("checking entry candidate", `${path} ${picocolors[exists ? "green" : "red"](`exists - ${exists}`)}`);
503
- return exists;
504
- });
505
- debug_log("found entry", entry_file_path);
506
- return [
507
- dirent.name,
508
- entry_file_path
509
- ];
510
- }).filter((entry)=>!!entry[1]) : [];
511
- return module_entries.length > 0 ? Object.fromEntries(module_entries) : void 0;
512
- }
513
- const root_path = process.cwd();
514
- function omit_root_path(path) {
515
- return path.replace(root_path, "");
516
- }
517
- function omit_root_path_for_entries(entries) {
518
- return Object.fromEntries(Object.entries(entries).map(([key, value])=>[
519
- key,
520
- omit_root_path(value)
521
- ]));
522
- }
523
- function guard_is_string(data) {
524
- return "string" == typeof data;
525
- }
526
- function guard_is_record(data) {
527
- return !!data && "object" == typeof data;
528
- }
529
- function is_umd_url(data) {
530
- return guard_is_record(data) && guard_is_string(data.umd);
531
- }
532
- function is_esm_url(data) {
533
- return guard_is_record(data) && guard_is_string(data.esm);
534
- }
535
- function is_module_typed_external_url(data) {
536
- return is_umd_url(data) || is_esm_url(data);
537
- }
538
- function is_env_external(data) {
539
- return guard_is_record(data) && (guard_is_string(data.dev) || is_module_typed_external_url(data.dev)) && (guard_is_string(data.prd) || is_module_typed_external_url(data.prd));
540
- }
541
- function get_external_url(args, url) {
542
- let _url = url;
543
- while(!guard_is_string(_url))if (is_env_external(_url)) _url = _url[args.pack.env];
544
- else {
545
- const mode = args.pack.esm ? "esm" : "umd";
546
- _url = mode in _url ? _url[mode] : void 0;
547
- }
548
- return _url;
549
- }
550
- function get_externals_importmaps(args, external_list) {
551
- return Object.entries(external_list).reduce(({ externals, importmaps }, [lib_name, data])=>{
552
- const _data = is_env_external(data) ? data[args.pack.env] : data;
553
- const external_lib = "string" == typeof _data ? {
554
- url: {
555
- esm: _data,
556
- umd: _data
557
- }
558
- } : is_module_typed_external_url(_data) ? {
559
- url: _data
560
- } : _data;
561
- const _importName = external_lib.importName || lib_name;
562
- (Array.isArray(_importName) ? _importName : [
563
- _importName
564
- ]).forEach((name)=>externals[name] = lib_name);
565
- const url = get_external_url(args, external_lib.url);
566
- if (url) importmaps[lib_name] = url;
567
- return {
568
- externals,
569
- importmaps
570
- };
571
- }, {
572
- externals: {},
573
- importmaps: {}
574
- });
575
- }
576
- let printed = false;
577
- function prepare_config(args, kind, config) {
578
- const { externals, importmaps } = get_externals_importmaps(args, config.externals);
579
- printed || console.log(`${picocolors.blue("\nexternals:")}\n${JSON.stringify(externals, null, 2)}\n`);
580
- if ("page" === kind) console.log(`${picocolors.blue("html_tags:")}\n${JSON.stringify(config.html.tags, null, 2)}\n`);
581
- const importmaps_tag = {
582
- append: false,
583
- head: true,
584
- tag: "script",
585
- attrs: {
586
- type: args.pack.esm ? "importmap" : "systemjs-importmap"
587
- },
588
- children: `{
589
- "imports": ${JSON.stringify(importmaps, null, 2)}
590
- }`
591
- };
592
- printed || console.log(`${picocolors.blue("\nimportmaps:")}\n${JSON.stringify(importmaps, null, 2)}\n`);
593
- printed = true;
594
- console.log(picocolors.blueBright(`\n**** 开始构建 【${kind}】 ****`));
595
- const entries = collect_modules(args, kind);
596
- if (entries) console.log(`${picocolors.blue(`\n${kind} entries:`)}\n${JSON.stringify(omit_root_path_for_entries(entries), null, 2)}\n`);
597
- else console.log(picocolors.red(`\n没有要构建的${kind},跳过\n`));
598
- return {
599
- entries,
600
- externals,
601
- importmaps_tag
602
- };
603
- }
604
- async function lib_pack(args) {
605
- const config = get_global_config(args);
606
- const packagejson = get_packagejson();
607
- const { entries, externals } = prepare_config(args, "module", config);
608
- if (!entries) return;
609
- const rslibConfig = defineConfig({
610
- source: {
611
- define: config.define,
612
- entry: entries
613
- },
614
- plugins: [
615
- framework_plugin(),
616
- pluginLess()
617
- ],
618
- resolve: {
619
- alias: config.alias
620
- },
621
- lib: [
622
- {
623
- format: "esm",
624
- syntax: "esnext",
625
- dts: false,
626
- output: {
627
- assetPrefix: `${config.url.base}/modules`,
628
- externals,
629
- distPath: {
630
- root: config.output.modules,
631
- js: "esm",
632
- jsAsync: "esm",
633
- css: "css"
634
- },
635
- minify: config.minify
636
- }
637
- },
638
- {
639
- format: "umd",
640
- output: {
641
- assetPrefix: `${config.url.base}/modules`,
642
- externals,
643
- distPath: {
644
- root: config.output.modules,
645
- js: "umd",
646
- jsAsync: "umd",
647
- css: "css"
648
- },
649
- minify: config.minify,
650
- injectStyles: true
651
- },
652
- syntax: "es6",
653
- umdName: `${packagejson.name}-modules-[name]`
654
- }
655
- ],
656
- output: {
657
- legalComments: "none",
658
- target: "web"
659
- },
660
- performance: {
661
- bundleAnalyze: config.analyze ? {
662
- analyzerMode: "disabled",
663
- generateStatsFile: true
664
- } : void 0,
665
- chunkSplit: {
666
- strategy: "all-in-one"
667
- }
668
- }
669
- });
670
- await build(rslibConfig, {
671
- watch: "build" === args.cmd && args.pack.watch
672
- });
673
- if ("build" === args.cmd) console.log(picocolors.green("\n**** 构建【module】完成 ****\n"));
674
- }
675
- let packageRoot = '';
676
- function get_package_root() {
677
- if (!packageRoot) {
678
- const __filename = fileURLToPath(import.meta.url);
679
- const __dirname = dirname(__filename);
680
- let currentDir = node_path.resolve(__dirname);
681
- const root = node_path.parse(currentDir).root;
682
- while(currentDir !== root){
683
- const potentialPkgJson = node_path.join(currentDir, 'package.json');
684
- if (node_fs.existsSync(potentialPkgJson)) break;
685
- currentDir = node_path.dirname(currentDir);
686
- }
687
- debug_log('packageRoot', currentDir);
688
- packageRoot = currentDir;
689
- }
690
- return packageRoot;
691
- }
692
- async function page_pack(args) {
693
- const config = get_global_config(args);
694
- const { entries, externals, importmaps_tag } = prepare_config(args, "page", config);
695
- if (!entries) return;
696
- const rsbuildConfig = core_defineConfig({
697
- source: {
698
- define: config.define,
699
- entry: entries
700
- },
701
- plugins: [
702
- framework_plugin(),
703
- pluginLess(),
704
- pluginUmd({
705
- name: "modulo-page"
706
- })
707
- ],
708
- tools: {
709
- rspack: {
710
- experiments: {
711
- outputModule: args.pack.esm
712
- }
713
- },
714
- htmlPlugin: true
715
- },
716
- output: {
717
- assetPrefix: config.url.cdn || config.url.base,
718
- distPath: {
719
- root: config.output.dist
720
- },
721
- externals,
722
- filenameHash: config.output.filenameHash,
723
- legalComments: "none",
724
- minify: config.minify
725
- },
726
- html: {
727
- meta: config.html.meta,
728
- mountId: config.html.root,
729
- scriptLoading: args.pack.esm ? "module" : "defer",
730
- tags: [
731
- importmaps_tag,
732
- ...config.html.tags
733
- ],
734
- template: config.html.template || external_node_path_resolve(get_package_root(), "template/index.html"),
735
- templateParameters: {
736
- base_prefix: config.url.base
737
- },
738
- title: config.html.title
739
- },
740
- resolve: {
741
- alias: config.alias
742
- },
743
- server: {
744
- base: config.url.base,
745
- open: config.dev_server.open ? config.dev_server.open.map((name)=>config.url.base + (name.endsWith("html") ? `/${name}` : `/${name}.html`)) : false,
746
- port: config.dev_server.port,
747
- proxy: config.dev_server.proxy
748
- },
749
- performance: {
750
- chunkSplit: {
751
- strategy: "split-by-experience"
752
- }
753
- }
754
- });
755
- const rsbuild = await createRsbuild({
756
- rsbuildConfig
757
- });
758
- await rsbuild["dev" === args.cmd ? "startDevServer" : "build"]({
759
- watch: "build" === args.cmd && args.pack.watch
760
- });
761
- if ("build" === args.cmd) console.log(picocolors.green("\n**** 构建【page】完成 ****"));
762
- }
763
- async function pack_code(args) {
764
- const { target } = args;
765
- if ("page" === target || "all" === target) await page_pack(args);
766
- if ("module" === target || "all" === target) await lib_pack(args);
767
- }
768
- function exec() {
769
- const args = get_args();
770
- if ("init" === args.cmd) init_tool(args);
771
- else if ("build" === args.cmd || "dev" === args.cmd) pack_code(args);
772
- }
773
- export { exec };