xshell 1.3.80 → 1.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/antd.development.js +86194 -144895
- package/antd.production.js +82353 -118684
- package/builder.d.ts +61 -160
- package/builder.js +350 -661
- package/file.d.ts +4 -0
- package/file.js +5 -4
- package/net.d.ts +0 -3
- package/net.js +1 -2
- package/package.json +20 -29
- package/prototype.common.js +2 -1
- package/prototype.js +1 -1
- package/react.development.js +15560 -30856
- package/react.production.js +9953 -17459
- package/repl.js +8 -1
- package/server.js +2 -5
- package/tsconfig.json +3 -2
- package/i18n/scanner/checker.d.ts +0 -5
- package/i18n/scanner/checker.js +0 -64
package/builder.js
CHANGED
|
@@ -1,9 +1,227 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { not_empty } from './prototype.js';
|
|
1
|
+
import { mimes } from 'mrmime';
|
|
2
|
+
import { not_empty, to_upper_camel_case } from './prototype.js';
|
|
3
3
|
import { noprint } from './process.js';
|
|
4
|
-
import {
|
|
5
|
-
import { fcopy, fmkdir, fwrite, print_info,
|
|
4
|
+
import { check } from './utils.js';
|
|
5
|
+
import { fcopy, fmkdir, fwrite, print_info, fstat, fread, binary_noprint } from './file.js';
|
|
6
6
|
import { path } from './path.js';
|
|
7
|
+
/** 通过 rolldown 从入口文件打包所有依赖生成单个 index.{mjs,cjs} 文件
|
|
8
|
+
- target: 目标环境 nodejs | web
|
|
9
|
+
- fpd_root: 项目根目录
|
|
10
|
+
- fpd_out: 输出文件目录
|
|
11
|
+
- entries: 入口文件 Record<输出文件路径, 输入文件路径>
|
|
12
|
+
- options?:
|
|
13
|
+
- cjs?: `false`
|
|
14
|
+
- single_chunk?: `true` 对于 await import(), 或者多个 entry 公用的部分,
|
|
15
|
+
不要创建分块,总是打包到一个 .js 中
|
|
16
|
+
- dynamic_import?: `true` 设置为 false 时可以忽略打包这些依赖
|
|
17
|
+
- externals?: string[] 或 RegExp[] 哪些导入模块不打包
|
|
18
|
+
- globals?: Record<包名, 全局变量名>, 替换模块为 globalThis 上的变量,避免打包
|
|
19
|
+
- plugins?: rolldown 插件
|
|
20
|
+
- styles?: `false` 加上 styles_plugin 插件,支持 .sass, .css 等样式导入
|
|
21
|
+
- assets?: `false` 加上 inline_assets 插件,支持 .svg, .png, 等资源导入为 data url
|
|
22
|
+
- defines?: Record<string, string> 定义如 process.env.NODE_ENV 的值为常数
|
|
23
|
+
- production?: `true` 如果设置了 true / false,则会定义 process.env.NODE_ENV 为 'production' / 'development'
|
|
24
|
+
- analyze?: `false` 生成 stats.html 用于生成文件大小分析
|
|
25
|
+
- print?: `true` 打印生成的文件
|
|
26
|
+
@example await rolldown('web', 'D:/0/web/', 'T:/test/', { 'react.js': 'react.ts' }) */
|
|
27
|
+
export async function rolldown(target, fpd_root, fpd_out, entries, { cjs = false, single_chunk = true, dynamic_import = true, externals, globals, plugins, styles = false, assets = false, production = true, defines, analyze = false, print = true } = {}) {
|
|
28
|
+
if (production !== null)
|
|
29
|
+
defines = {
|
|
30
|
+
'process.env.NODE_ENV': (production ? 'production' : 'development').quote(),
|
|
31
|
+
...defines
|
|
32
|
+
};
|
|
33
|
+
check(fpd_out.isdir);
|
|
34
|
+
const fp_stats = analyze ? fpd_out + 'stats.html' : undefined;
|
|
35
|
+
// 先 rolldown.rolldown 创建 RolldownBuild,再多次调用 .build ,只有第一次会读取源代码文件,没什么用
|
|
36
|
+
// 不如直接一步构建了
|
|
37
|
+
await (await import('rolldown')).build({
|
|
38
|
+
// --- 输入选项 rolldown.rolldown({ ... })
|
|
39
|
+
cwd: fpd_root,
|
|
40
|
+
input: entries,
|
|
41
|
+
platform: target === 'nodejs' ? 'node' : 'browser',
|
|
42
|
+
logLevel: 'debug',
|
|
43
|
+
external: externals,
|
|
44
|
+
transform: {
|
|
45
|
+
define: defines,
|
|
46
|
+
jsx: 'react-jsx'
|
|
47
|
+
},
|
|
48
|
+
plugins: [
|
|
49
|
+
dynamic_import === false && {
|
|
50
|
+
name: 'ignore-dynamic-import',
|
|
51
|
+
resolveId: (source, importer, { kind }) => kind === 'dynamic-import' ? false : null
|
|
52
|
+
},
|
|
53
|
+
globals && {
|
|
54
|
+
name: 'external-modules',
|
|
55
|
+
resolveId: {
|
|
56
|
+
filter: { id: new RegExp('^' + Object.keys(globals).join('|').bracket() + '$') },
|
|
57
|
+
handler: (source, importer, options) => external_prefix + source
|
|
58
|
+
},
|
|
59
|
+
load: {
|
|
60
|
+
filter: { id: new RegExp('^' + external_prefix) },
|
|
61
|
+
handler: id => `module.exports = globalThis.${globals[id.strip_start(external_prefix)]}`
|
|
62
|
+
}
|
|
63
|
+
},
|
|
64
|
+
styles && styles_plugin(),
|
|
65
|
+
assets && inline_assets,
|
|
66
|
+
assets && svg(),
|
|
67
|
+
...(plugins || []),
|
|
68
|
+
print && {
|
|
69
|
+
name: 'my-stats',
|
|
70
|
+
writeBundle(output_options, bundle) {
|
|
71
|
+
Object.keys(bundle).map(async (fname) => {
|
|
72
|
+
const fp = fpd_out + fname;
|
|
73
|
+
const { size } = await fstat(fp);
|
|
74
|
+
console.log(`+ ${fp} `.green + size.to_fsize_str().yellow);
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
analyze && (await import('rollup-plugin-visualizer')).visualizer({
|
|
79
|
+
template: 'flamegraph',
|
|
80
|
+
filename: fp_stats
|
|
81
|
+
})
|
|
82
|
+
],
|
|
83
|
+
// treeshake: { },
|
|
84
|
+
// onLog (level, log, handler) {
|
|
85
|
+
//
|
|
86
|
+
// }
|
|
87
|
+
// resolve: {
|
|
88
|
+
// alias: {
|
|
89
|
+
//
|
|
90
|
+
// }
|
|
91
|
+
// }
|
|
92
|
+
// shimMissingExports: true
|
|
93
|
+
// --- 输出选项
|
|
94
|
+
// rolldown.write({ ... })
|
|
95
|
+
output: {
|
|
96
|
+
entryFileNames: '[name]',
|
|
97
|
+
chunkFileNames: '[name].js',
|
|
98
|
+
assetFileNames: '[name][extname]',
|
|
99
|
+
dir: fpd_out,
|
|
100
|
+
sourcemap: false,
|
|
101
|
+
sourcemapIgnoreList: false,
|
|
102
|
+
format: cjs ? 'cjs' : 'esm',
|
|
103
|
+
minify: false,
|
|
104
|
+
codeSplitting: !single_chunk,
|
|
105
|
+
cleanDir: false,
|
|
106
|
+
comments: !production
|
|
107
|
+
// globals: { jquery: '$' },
|
|
108
|
+
// paths
|
|
109
|
+
// plugins
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
async function styles_plugin() {
|
|
114
|
+
let sass = await import('sass');
|
|
115
|
+
let styles = [];
|
|
116
|
+
let fname;
|
|
117
|
+
return {
|
|
118
|
+
name: 'styles-plugin',
|
|
119
|
+
buildStart(options) {
|
|
120
|
+
styles.length = 0;
|
|
121
|
+
fname = Object.keys(options.input)[0].replace(/\.m?js$/, '.css');
|
|
122
|
+
},
|
|
123
|
+
transform: {
|
|
124
|
+
filter: {
|
|
125
|
+
id: {
|
|
126
|
+
include: /\.(css|sass|scss)$/,
|
|
127
|
+
exclude: /\/sites\.sass$/
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
handler(code, id, meta) {
|
|
131
|
+
id = id.fp;
|
|
132
|
+
const { fext } = id;
|
|
133
|
+
const css = fext === 'css' ?
|
|
134
|
+
code
|
|
135
|
+
:
|
|
136
|
+
sass.compileString(code, {
|
|
137
|
+
alertColor: true,
|
|
138
|
+
style: 'expanded',
|
|
139
|
+
syntax: fext === 'sass' ? 'indented' : 'scss',
|
|
140
|
+
url: new URL(`file://${id}`)
|
|
141
|
+
}).css
|
|
142
|
+
.split_lines()
|
|
143
|
+
.indent2to4()
|
|
144
|
+
.join_lines();
|
|
145
|
+
if (!id.endsWith('.text.sass'))
|
|
146
|
+
styles.push(css);
|
|
147
|
+
return {
|
|
148
|
+
moduleSideEffects: false,
|
|
149
|
+
code: `export default ${JSON.stringify(css)}`,
|
|
150
|
+
moduleType: 'js'
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
generateBundle(output_options, bundle, is_write) {
|
|
155
|
+
if (!styles.length)
|
|
156
|
+
return;
|
|
157
|
+
this.emitFile({
|
|
158
|
+
type: 'asset',
|
|
159
|
+
fileName: fname,
|
|
160
|
+
source: styles.join('\n\n'),
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
const external_prefix = 'external: ';
|
|
166
|
+
const inline_assets = {
|
|
167
|
+
name: 'inline-assets',
|
|
168
|
+
load: {
|
|
169
|
+
filter: {
|
|
170
|
+
id: {
|
|
171
|
+
include: /\.(png|jpg|ico|csv|txt|svg)$/,
|
|
172
|
+
exclude: /\.icon\.svg$/
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
// handler: async id => `export default '${id.fp}'`
|
|
176
|
+
handler: async ({ fp, fext }) => `export default 'data:${mimes[fext]};base64,${(await fread(fp, binary_noprint)).toString('base64')}'`
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
async function svg() {
|
|
180
|
+
const svgr = await import('@svgr/core');
|
|
181
|
+
const config = {
|
|
182
|
+
plugins: [
|
|
183
|
+
(await import('@svgr/plugin-svgo')).default,
|
|
184
|
+
(await import('@svgr/plugin-jsx')).default
|
|
185
|
+
],
|
|
186
|
+
jsxRuntime: 'automatic',
|
|
187
|
+
runtimeConfig: false,
|
|
188
|
+
prettier: false,
|
|
189
|
+
svgProps: { fill: 'currentColor' },
|
|
190
|
+
svgoConfig: {
|
|
191
|
+
js2svg: {
|
|
192
|
+
indent: 4,
|
|
193
|
+
pretty: true,
|
|
194
|
+
eol: 'lf'
|
|
195
|
+
},
|
|
196
|
+
plugins: [
|
|
197
|
+
{
|
|
198
|
+
name: 'preset-default',
|
|
199
|
+
params: {
|
|
200
|
+
overrides: {
|
|
201
|
+
removeViewBox: false,
|
|
202
|
+
mergePaths: false,
|
|
203
|
+
convertColors: false,
|
|
204
|
+
minifyStyles: false,
|
|
205
|
+
}
|
|
206
|
+
},
|
|
207
|
+
}
|
|
208
|
+
]
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
return {
|
|
212
|
+
name: 'svg',
|
|
213
|
+
transform: {
|
|
214
|
+
filter: { id: /\.icon\.svg$/ },
|
|
215
|
+
handler: async (code, id, meta) => ({
|
|
216
|
+
moduleSideEffects: false,
|
|
217
|
+
moduleType: 'jsx',
|
|
218
|
+
code: await svgr.transform(code, config, {
|
|
219
|
+
componentName: to_upper_camel_case(id.fname.strip_end('.icon.svg'))
|
|
220
|
+
})
|
|
221
|
+
})
|
|
222
|
+
}
|
|
223
|
+
};
|
|
224
|
+
}
|
|
7
225
|
const get_target = (production) => production ? 'production' : 'development';
|
|
8
226
|
function get_react_js(production, src, map) {
|
|
9
227
|
return `${src ? import.meta.dirname.fpd : 'vendors/react/'}react.${get_target(production)}.js${map ? '.map' : ''}`;
|
|
@@ -26,11 +244,7 @@ function get_antd_asset(production, map) {
|
|
|
26
244
|
const dependencies = {
|
|
27
245
|
react: {
|
|
28
246
|
productions: [get_react_asset(true, false)],
|
|
29
|
-
devs: [get_react_asset(false, false)]
|
|
30
|
-
maps: {
|
|
31
|
-
productions: [get_react_asset(true, true)],
|
|
32
|
-
devs: [get_react_asset(false, true)],
|
|
33
|
-
}
|
|
247
|
+
devs: [get_react_asset(false, false)]
|
|
34
248
|
},
|
|
35
249
|
lodash: {
|
|
36
250
|
productions: ['lodash/lodash.min.js'],
|
|
@@ -48,22 +262,12 @@ const dependencies = {
|
|
|
48
262
|
swiper: {
|
|
49
263
|
productions: ['swiper/swiper-bundle.min.js']
|
|
50
264
|
},
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
},
|
|
265
|
+
// 官方不支持 umd 了,需要自己先构建
|
|
266
|
+
// https://github.com/ant-design/ant-design/issues/57269
|
|
54
267
|
antd: {
|
|
55
|
-
dependencies: ['
|
|
268
|
+
dependencies: ['react'],
|
|
56
269
|
productions: [get_antd_asset(true, false)],
|
|
57
|
-
devs: [get_antd_asset(false, false)]
|
|
58
|
-
maps: {
|
|
59
|
-
productions: [get_antd_asset(true, true)],
|
|
60
|
-
devs: [get_antd_asset(false, true)],
|
|
61
|
-
}
|
|
62
|
-
},
|
|
63
|
-
'antd-icons': {
|
|
64
|
-
dependencies: ['antd'],
|
|
65
|
-
productions: ['@ant-design/icons/dist/index.umd.min.js'],
|
|
66
|
-
devs: ['@ant-design/icons/dist/index.umd.js']
|
|
270
|
+
devs: [get_antd_asset(false, false)]
|
|
67
271
|
},
|
|
68
272
|
'vscode-oniguruma': {
|
|
69
273
|
assets: {
|
|
@@ -97,9 +301,6 @@ const dependencies = {
|
|
|
97
301
|
maps: {
|
|
98
302
|
devs: ['echarts/dist/echarts.js.map']
|
|
99
303
|
}
|
|
100
|
-
},
|
|
101
|
-
plotly: {
|
|
102
|
-
productions: ['plotly.js-dist-min/plotly.min.js']
|
|
103
304
|
}
|
|
104
305
|
};
|
|
105
306
|
function get_asset_out(asset) {
|
|
@@ -112,646 +313,134 @@ function get_vendor_asset_out(asset) {
|
|
|
112
313
|
? `vendors/${asset}`
|
|
113
314
|
: asset.out || asset.src;
|
|
114
315
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
if (key.endsWith('/*') && value.endsWith('/*'))
|
|
150
|
-
return [
|
|
151
|
-
key.slice(0, -2),
|
|
152
|
-
fpd_root + value.slice(0, -2).strip_if_start('./')
|
|
153
|
-
];
|
|
154
|
-
else // 是某个具体文件
|
|
155
|
-
return [key, fpd_root + value.strip_if_start('./')];
|
|
156
|
-
}));
|
|
157
|
-
resolve_alias_cache.set(fpd_root, result);
|
|
158
|
-
return result;
|
|
159
|
-
}
|
|
160
|
-
export class Bundler {
|
|
161
|
-
name;
|
|
162
|
-
target;
|
|
163
|
-
fpd_root;
|
|
164
|
-
fpd_out;
|
|
165
|
-
fpdt_cache;
|
|
166
|
-
entry;
|
|
167
|
-
// --- BundlerOptions 开始
|
|
168
|
-
production = true;
|
|
169
|
-
dependencies = [];
|
|
170
|
-
source_map = true;
|
|
171
|
-
globals;
|
|
172
|
-
external_dayjs = false;
|
|
173
|
-
externals;
|
|
174
|
-
htmls;
|
|
175
|
-
assets;
|
|
176
|
-
assets_root = '/';
|
|
177
|
-
template = false;
|
|
178
|
-
single_js;
|
|
179
|
-
commonjs2 = false;
|
|
180
|
-
expose = false;
|
|
181
|
-
single_chunk = true;
|
|
182
|
-
dynamic_import = true;
|
|
183
|
-
resolve_alias;
|
|
184
|
-
resolve_fallback;
|
|
185
|
-
assets_stats = true;
|
|
186
|
-
analyzer = false;
|
|
187
|
-
dts = false;
|
|
188
|
-
exclude_modules;
|
|
189
|
-
cache_version;
|
|
190
|
-
plugins;
|
|
191
|
-
license;
|
|
192
|
-
polyfill_node_sea;
|
|
193
|
-
// --- BundlerOptions 结束
|
|
194
|
-
config;
|
|
195
|
-
lcompiler;
|
|
196
|
-
/** 通过 webpack 从入口文件打包所有依赖生成单个 index.{mjs,cjs} 文件
|
|
197
|
-
- name: 项目名称
|
|
198
|
-
- target: 目标环境 nodejs | web
|
|
199
|
-
- fpd_root: 项目根目录
|
|
200
|
-
- fpd_out: 输出文件目录
|
|
201
|
-
- fpdt_cache?: webpack 缓存目录,可以设置为 undefined 使用默认路径 node_modules/.cache/webpack/
|
|
202
|
-
- entry: 入口文件
|
|
203
|
-
- options?: 打包配置, 按常用顺序排列
|
|
204
|
-
- production?: `true` webpack mode 设置为 'production'
|
|
205
|
-
- dependencies?: DependencyId[], 决定 bundler 在 build_all (copy_files) 时需要复制到 fpd_out 的资源
|
|
206
|
-
- source_map?: `true` 启用源码映射 .map 文件
|
|
207
|
-
- globals?: 全局变量定义
|
|
208
|
-
- external_dayjs?: `false` 配置 dayjs 为 external 来配合 antd 使用, 减小一点体积
|
|
209
|
-
- externals?: 配置外部模块
|
|
210
|
-
- htmls?: 配置要生成的 html, 比如 { 'index.html', { title: '文件', ... } }
|
|
211
|
-
- assets?: 项目中需要直接复制到输出目录的资源,有 productions 但无 devs 时 (是同一套),
|
|
212
|
-
在 dev 模式下会用 productions 中的资源,如果不需要 productions 资源, devs 可以设置为 [ ],
|
|
213
|
-
每一项是 string 或者 { src: '...', out: '...' },路径相对于 fpd_root 和 fpd_out
|
|
214
|
-
- assets_root?: `'/'` 生成的 html 中替换 {root} 作为部署路径,以支持 browser router 路由能力
|
|
215
|
-
assets, html 中的 icon, scripts 路径直接在前面添加 assets_root 来生成最终 html href
|
|
216
|
-
未启用时使用相对 html 路径来生成最终 html href
|
|
217
|
-
- template?: `false` 除了生成对应的 html 之外,还生成所有路径为 `{root}/...` 的模板 html 文件, 方便后续 server 替换渲染
|
|
218
|
-
- single_js?: 设置生成的单个 js 入口文件,无其他依赖,通过 script module 作为入口加载,含有 import 加载其他 externals 和某个 entry,类似 htmls 配置要生成的 html
|
|
219
|
-
- js: js 入口文件名
|
|
220
|
-
- entry: 使用的 entry
|
|
221
|
-
- commonjs2?: `false` 打包为 commonjs2 (.cjs) 的文件
|
|
222
|
-
- expose?: `false` 入口模块所有导出的属性赋值到全局对象 globalThis 上
|
|
223
|
-
- single_chunk?: `true` 输出为单个文件,将依赖也打包到其中,不要生成多个 chunk
|
|
224
|
-
- dynamic_import?: `true` 对于 await import('...') 要不要打包外部模块到输出文件中
|
|
225
|
-
- resolve_alias?: 配置 resolve alias,会自动从项目 tsconfig.json 的 paths 中读取,用户配置作为覆盖
|
|
226
|
-
- resolve_fallback?: 配置 resolve fallback
|
|
227
|
-
- assets_stats?: `true` 打印输出的文件信息
|
|
228
|
-
- analyzer?: `false` 启用 WebpackBundleAnalyzer 插件分析构建产物大小
|
|
229
|
-
- dts?: `false` 生成 .d.ts 文件
|
|
230
|
-
- exclude_modules?: 传入正则表达式 ,匹配时使用 IgnorePlugin 强制不打包这个模块,但是一旦导入就会报错
|
|
231
|
-
- cache_version?: webpack cache version, 用于区分同一个 name 的不同版本
|
|
232
|
-
- plugins?: 可选传入的额外的 webpack 插件
|
|
233
|
-
- license?: 使用 license-webpack-plugin 构建 ThirdPartyNotice.txt
|
|
234
|
-
- polyfill_node_sea?: 避免依赖 node:sea 模块以兼容旧版本 node.js */
|
|
235
|
-
constructor(name, target, fpd_root, fpd_out, fpdt_cache, entry, options = {}) {
|
|
236
|
-
this.name = name;
|
|
237
|
-
this.target = target;
|
|
238
|
-
this.fpd_root = fpd_root;
|
|
239
|
-
this.fpd_out = fpd_out;
|
|
240
|
-
this.fpdt_cache = fpdt_cache;
|
|
241
|
-
this.entry = entry;
|
|
242
|
-
Object.assign(this, options);
|
|
243
|
-
if (options.dependencies?.length && target !== 'web')
|
|
244
|
-
throw new Error('仅 target === web 时才需要配置 dependencies');
|
|
245
|
-
if (this.expose && this.commonjs2)
|
|
246
|
-
throw new Error('expose 和 commonjs2 不能同时启用');
|
|
247
|
-
}
|
|
248
|
-
async build(print = true) {
|
|
249
|
-
const { fpd_root } = this;
|
|
250
|
-
if (!this.lcompiler)
|
|
251
|
-
await (this.lcompiler = new Lock()).request(async () => {
|
|
252
|
-
const { default: Webpack } = await import('webpack');
|
|
253
|
-
const output_module = !this.commonjs2 && !this.expose;
|
|
254
|
-
// let smp = new SpeedMeasurePlugin()
|
|
255
|
-
// const config: Webpack.Configuration = smp.wrap({
|
|
256
|
-
let resolve_cache = {};
|
|
257
|
-
const get_loader = (name) => resolve_cache[name] ??= fileURLToPath(import.meta.resolve(`${name}/package.json`)).fdir;
|
|
258
|
-
const sass = this.target === 'web' ? await import('sass') : null;
|
|
259
|
-
const sass_loader = this.target === 'web' ?
|
|
260
|
-
{
|
|
261
|
-
// https://webpack.js.org/loaders/sass-loader
|
|
262
|
-
loader: get_loader('sass-loader'),
|
|
263
|
-
options: {
|
|
264
|
-
api: 'modern-compiler',
|
|
265
|
-
sassOptions: {
|
|
266
|
-
style: 'expanded'
|
|
267
|
-
},
|
|
268
|
-
...sass ? {
|
|
269
|
-
implementation: sass
|
|
270
|
-
} : {},
|
|
271
|
-
// 解决 url(search.png) 打包出错的问题
|
|
272
|
-
webpackImporter: false
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
:
|
|
276
|
-
null;
|
|
277
|
-
this.lcompiler.resource = Webpack(this.config = {
|
|
278
|
-
name: this.name,
|
|
279
|
-
mode: get_target(this.production),
|
|
280
|
-
devtool: this.source_map ? 'source-map' : false,
|
|
281
|
-
context: fpd_root,
|
|
282
|
-
entry: this.entry,
|
|
283
|
-
experiments: {
|
|
284
|
-
outputModule: output_module,
|
|
285
|
-
},
|
|
286
|
-
output: {
|
|
287
|
-
path: this.fpd_out,
|
|
288
|
-
filename: '[name]',
|
|
289
|
-
publicPath: '/',
|
|
290
|
-
pathinfo: true,
|
|
291
|
-
globalObject: 'globalThis',
|
|
292
|
-
module: output_module,
|
|
293
|
-
// 在 bundle 中导出 entry 文件的 export
|
|
294
|
-
library: {
|
|
295
|
-
type: this.commonjs2 ? 'commonjs2' : this.expose ? 'global' : 'module',
|
|
296
|
-
},
|
|
297
|
-
...this.single_chunk ? {
|
|
298
|
-
chunkLoading: false
|
|
299
|
-
} : {},
|
|
300
|
-
},
|
|
301
|
-
target: [this.target === 'web' ? 'web' : 'node23', 'es2024'],
|
|
302
|
-
// 结合 output.globalObject, 会生成 globalThis['React'] 这样的引用
|
|
303
|
-
externalsType: this.target === 'nodejs' ? 'commonjs2' : 'global',
|
|
304
|
-
// 以 react: 'React', 为例,含义为
|
|
305
|
-
// 取全局变量 window.React 的值作为 import { useState } from 'react' 中 { ... } 这部分的结果,再解构里面的 useState 属性
|
|
306
|
-
externals: filter_values({
|
|
307
|
-
react: 'React',
|
|
308
|
-
'react/jsx-runtime': 'ReactJSX',
|
|
309
|
-
'react-dom': 'ReactDOM',
|
|
310
|
-
'react-dom/client': 'ReactDOMClient',
|
|
311
|
-
jquery: '$',
|
|
312
|
-
...this.target === 'web' ? {
|
|
313
|
-
lodash: '_',
|
|
314
|
-
} : {
|
|
315
|
-
vscode: 'commonjs2 vscode'
|
|
316
|
-
},
|
|
317
|
-
// import { Terminal } from 'xterm'
|
|
318
|
-
// 实际上 Terminal 直接暴露在了 window 上,而不是 window.Terminal.Terminal
|
|
319
|
-
'@xterm/xterm': 'window',
|
|
320
|
-
swiper: 'Swiper',
|
|
321
|
-
...this.external_dayjs ? { dayjs: 'dayjs' } : {},
|
|
322
|
-
antd: 'antd',
|
|
323
|
-
'@ant-design/icons': 'icons',
|
|
324
|
-
'@ant-design/plots': 'Plots',
|
|
325
|
-
echarts: 'echarts',
|
|
326
|
-
'plotly.js-dist-min': 'Plotly',
|
|
327
|
-
...this.externals
|
|
328
|
-
}),
|
|
329
|
-
resolve: {
|
|
330
|
-
symlinks: true,
|
|
331
|
-
extensions: ['.js'],
|
|
332
|
-
extensionAlias: {
|
|
333
|
-
'.js': ['.js', '.ts', '.tsx']
|
|
334
|
-
},
|
|
335
|
-
alias: filter_values({
|
|
336
|
-
...await get_resolve_alias(fpd_root),
|
|
337
|
-
...this.resolve_alias
|
|
338
|
-
}),
|
|
339
|
-
// modules: [
|
|
340
|
-
// '',
|
|
341
|
-
// ],
|
|
342
|
-
...this.resolve_fallback ? { fallback: this.resolve_fallback } : {},
|
|
343
|
-
// fallback: {
|
|
344
|
-
// os: false,
|
|
345
|
-
// }
|
|
346
|
-
},
|
|
347
|
-
module: {
|
|
348
|
-
...this.dynamic_import === false ? {
|
|
349
|
-
parser: {
|
|
350
|
-
javascript: {
|
|
351
|
-
// 保留 await import() 这样的引用
|
|
352
|
-
import: false,
|
|
353
|
-
// dynamicImportMode: 'weak',
|
|
354
|
-
}
|
|
355
|
-
},
|
|
356
|
-
} : {},
|
|
357
|
-
rules: [
|
|
358
|
-
...this.source_map ? [
|
|
359
|
-
{
|
|
360
|
-
test: /\.js$/,
|
|
361
|
-
enforce: 'pre',
|
|
362
|
-
use: [get_loader('source-map-loader')],
|
|
363
|
-
},
|
|
364
|
-
] : [],
|
|
365
|
-
{
|
|
366
|
-
test: this.target === 'nodejs' ? /\.ts$/ : /\.tsx?$/,
|
|
367
|
-
exclude: /node_modules/,
|
|
368
|
-
loader: get_loader('ts-loader'),
|
|
369
|
-
// https://github.com/TypeStrong/ts-loader
|
|
370
|
-
options: {
|
|
371
|
-
configFile: `${fpd_root}tsconfig.json`,
|
|
372
|
-
onlyCompileBundledFiles: true,
|
|
373
|
-
transpileOnly: !this.dts,
|
|
374
|
-
compilerOptions: {
|
|
375
|
-
module: 'esnext',
|
|
376
|
-
target: 'esnext',
|
|
377
|
-
moduleResolution: 'Bundler',
|
|
378
|
-
declaration: this.dts,
|
|
379
|
-
noEmit: false,
|
|
380
|
-
allowImportingTsExtensions: false,
|
|
381
|
-
...this.commonjs2 ? {
|
|
382
|
-
// 编译为 commonjs 后 import 的依赖是通过 require 引入的,所以需要 interop 去生成 default
|
|
383
|
-
// nodejs 默认的 import 会自动加上 default,所以不需要 interop
|
|
384
|
-
esModuleInterop: true
|
|
385
|
-
} : {},
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
},
|
|
389
|
-
...this.target === 'web' ? [
|
|
390
|
-
{
|
|
391
|
-
oneOf: [
|
|
392
|
-
{
|
|
393
|
-
test: /\.text\.s[ac]ss$/,
|
|
394
|
-
type: 'asset/source',
|
|
395
|
-
use: [sass_loader],
|
|
396
|
-
},
|
|
397
|
-
{
|
|
398
|
-
test: /\.s[ac]ss$/,
|
|
399
|
-
use: [
|
|
400
|
-
get_loader('style-loader'),
|
|
401
|
-
{
|
|
402
|
-
// https://github.com/webpack-contrib/css-loader
|
|
403
|
-
loader: get_loader('css-loader'),
|
|
404
|
-
options: { url: false }
|
|
405
|
-
},
|
|
406
|
-
sass_loader
|
|
407
|
-
]
|
|
408
|
-
}
|
|
409
|
-
]
|
|
410
|
-
},
|
|
411
|
-
{
|
|
412
|
-
test: /\.css$/,
|
|
413
|
-
use: [get_loader('style-loader'), get_loader('css-loader')]
|
|
414
|
-
},
|
|
415
|
-
{
|
|
416
|
-
oneOf: [
|
|
417
|
-
{
|
|
418
|
-
test: /\.icon\.svg$/,
|
|
419
|
-
issuer: /\.[jt]sx?$/,
|
|
420
|
-
loader: get_loader('@svgr/webpack'),
|
|
421
|
-
options: { icon: true }
|
|
422
|
-
},
|
|
423
|
-
{
|
|
424
|
-
test: /\.raw\.svg$/,
|
|
425
|
-
type: 'asset/source',
|
|
426
|
-
},
|
|
427
|
-
{
|
|
428
|
-
test: /\.(svg|ico|png|jpe?g|gif|woff2?|ttf|eot|otf|mp4|webm|ogg|mp3|wav|flac|aac)$/,
|
|
429
|
-
type: 'asset/inline',
|
|
430
|
-
},
|
|
431
|
-
]
|
|
432
|
-
},
|
|
433
|
-
] : [],
|
|
434
|
-
{
|
|
435
|
-
test: /\.(txt|csv|dos)$/,
|
|
436
|
-
type: 'asset/source',
|
|
437
|
-
}
|
|
438
|
-
]
|
|
439
|
-
},
|
|
440
|
-
...sass ? {
|
|
441
|
-
loader: {
|
|
442
|
-
sass
|
|
443
|
-
},
|
|
444
|
-
} : {},
|
|
445
|
-
optimization: {
|
|
446
|
-
minimize: false
|
|
447
|
-
},
|
|
448
|
-
ignoreWarnings: [
|
|
449
|
-
...this.source_map ? [/Failed to parse source map/] : [],
|
|
450
|
-
...this.license ? [
|
|
451
|
-
/** LicenseWebpackPlugin 会添加过时的 string 类型的 warning,无法被正则表达式的逻辑匹配,这里只能手动用函数过滤 */
|
|
452
|
-
(warning) => typeof warning === 'string' && warning.startsWith('license-webpack-plugin: could not find any license ')
|
|
453
|
-
] : [],
|
|
454
|
-
...this.target === 'nodejs' ? [
|
|
455
|
-
/Can't resolve '(bufferutil|utf-8-validate)'/,
|
|
456
|
-
// 打包 ali-oss 时可能的报错
|
|
457
|
-
(warning) => {
|
|
458
|
-
if (!warning)
|
|
459
|
-
return false;
|
|
460
|
-
const { message, module } = warning;
|
|
461
|
-
if (!message)
|
|
462
|
-
return false;
|
|
463
|
-
const fp = module?.context?.fp || '';
|
|
464
|
-
if (message.includes('the request of a dependency is an expression'))
|
|
465
|
-
return fp.endsWith('any-promise') ||
|
|
466
|
-
fp.includes('/@sqltools/base-driver/');
|
|
467
|
-
else if (message.includes('require function is used in a way in which dependencies cannot be statically extracted'))
|
|
468
|
-
return fp.includes('/vscode-languageserver-types/');
|
|
469
|
-
else
|
|
470
|
-
return false;
|
|
471
|
-
}
|
|
472
|
-
] : [],
|
|
473
|
-
...this.name === 'react' ? [/export '(createRoot|hydrateRoot)' \(imported as 'ReactDOM'\) was not found in 'react-dom'/] : []
|
|
474
|
-
],
|
|
475
|
-
performance: {
|
|
476
|
-
hints: false,
|
|
477
|
-
},
|
|
478
|
-
stats: {
|
|
479
|
-
colors: true,
|
|
480
|
-
context: fpd_root,
|
|
481
|
-
entrypoints: false,
|
|
482
|
-
errors: true,
|
|
483
|
-
errorDetails: true,
|
|
484
|
-
hash: false,
|
|
485
|
-
version: false,
|
|
486
|
-
timings: true,
|
|
487
|
-
children: true,
|
|
488
|
-
assets: this.assets_stats,
|
|
489
|
-
assetsSpace: 20,
|
|
490
|
-
modules: false,
|
|
491
|
-
modulesSpace: 20,
|
|
492
|
-
cachedAssets: false,
|
|
493
|
-
cachedModules: false,
|
|
494
|
-
chunks: false,
|
|
495
|
-
// logging: 'info',
|
|
496
|
-
},
|
|
497
|
-
plugins: [
|
|
498
|
-
...this.globals ? [
|
|
499
|
-
new Webpack.DefinePlugin({
|
|
500
|
-
...this.globals
|
|
501
|
-
// process: { env: { }, argv: [] }
|
|
502
|
-
})
|
|
503
|
-
] : [],
|
|
504
|
-
// 使用 IgnorePlugin 能够不打包,但是一旦导入就会报错
|
|
505
|
-
...this.exclude_modules ? [
|
|
506
|
-
new Webpack.IgnorePlugin({
|
|
507
|
-
resourceRegExp: this.exclude_modules,
|
|
508
|
-
// checkResource: (resource, context) =>
|
|
509
|
-
// resource.startsWith('./vendors/') && !context.fp.startsWith(fpd_node_modules) ,
|
|
510
|
-
})
|
|
511
|
-
] : [],
|
|
512
|
-
...this.analyzer ? await (async () => {
|
|
513
|
-
const { BundleAnalyzerPlugin } = await import('webpack-bundle-analyzer');
|
|
514
|
-
return [
|
|
515
|
-
new BundleAnalyzerPlugin({
|
|
516
|
-
analyzerMode: 'static',
|
|
517
|
-
openAnalyzer: false,
|
|
518
|
-
reportFilename: ramdisk ?
|
|
519
|
-
`T:/t/webpack-analysis/${this.name}.html`
|
|
520
|
-
:
|
|
521
|
-
'report.html'
|
|
522
|
-
})
|
|
523
|
-
];
|
|
524
|
-
})() : [],
|
|
525
|
-
...this.license ? await (async () => {
|
|
526
|
-
const { LicenseWebpackPlugin } = await import('license-webpack-plugin');
|
|
527
|
-
return [
|
|
528
|
-
new LicenseWebpackPlugin({
|
|
529
|
-
perChunkOutput: false,
|
|
530
|
-
outputFilename: 'ThirdPartyNotice.txt',
|
|
531
|
-
})
|
|
532
|
-
];
|
|
533
|
-
})() : [],
|
|
534
|
-
...this.polyfill_node_sea ? [{
|
|
535
|
-
apply(compiler) {
|
|
536
|
-
const external_polyfill_plugin_name = 'MyNodejsBuiltinModuleReplacementPlugin';
|
|
537
|
-
const builtin_module = 'node:sea';
|
|
538
|
-
const fp_polyfill = `${import.meta.dirname.fpd}node-sea.polyfill.js`;
|
|
539
|
-
compiler.hooks.normalModuleFactory.tap(external_polyfill_plugin_name, factory => {
|
|
540
|
-
factory.hooks.beforeResolve.tap(external_polyfill_plugin_name, data => {
|
|
541
|
-
if (data.request === builtin_module) {
|
|
542
|
-
data.request = fp_polyfill;
|
|
543
|
-
// 一定要改 dependencies,否则会创建 ExternalModule,不走 NormalModule 的 resolve 过程
|
|
544
|
-
data.dependencies.forEach(dep => {
|
|
545
|
-
if (dep.request === builtin_module) {
|
|
546
|
-
dep.request = fp_polyfill;
|
|
547
|
-
dep.userRequest = fp_polyfill;
|
|
548
|
-
}
|
|
549
|
-
});
|
|
550
|
-
}
|
|
551
|
-
});
|
|
552
|
-
});
|
|
553
|
-
}
|
|
554
|
-
}] : [],
|
|
555
|
-
...this.plugins || [],
|
|
556
|
-
]
|
|
557
|
-
});
|
|
558
|
-
});
|
|
559
|
-
const stats = await this.lcompiler.request(async (compiler) => new Promise((resolve, reject) => {
|
|
560
|
-
compiler.run((error, stats) => {
|
|
561
|
-
if (error)
|
|
562
|
-
reject(error);
|
|
563
|
-
else if (stats.hasErrors()) {
|
|
564
|
-
console.log(stats.toString(compiler.options.stats));
|
|
565
|
-
reject(new Error(`${this.name} 构建失败`));
|
|
566
|
-
}
|
|
567
|
-
else
|
|
568
|
-
resolve(stats);
|
|
569
|
-
});
|
|
570
|
-
}));
|
|
571
|
-
if (print) {
|
|
572
|
-
const statstr = stats.toString(this.config.stats)
|
|
573
|
-
.replace(new RegExp(`\\n\\s*.*${this.name}.* compiled .*successfully.* in (.*)`), '').trimEnd();
|
|
574
|
-
console.log((statstr ? `${statstr}\n` : '') +
|
|
575
|
-
`${this.name} 成功构建到 ${this.fpd_out}`.green);
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
|
-
async close() {
|
|
579
|
-
await this.lcompiler?.request(async (compiler) => new Promise((resolve, reject) => {
|
|
580
|
-
compiler.close(error => {
|
|
581
|
-
if (error)
|
|
582
|
-
reject(error);
|
|
583
|
-
else
|
|
584
|
-
resolve();
|
|
585
|
-
});
|
|
586
|
-
}));
|
|
587
|
-
}
|
|
588
|
-
async build_all(print = true) {
|
|
589
|
-
await Promise.all([
|
|
590
|
-
this.build(print),
|
|
591
|
-
this.copy_files({ print: { info: print, files: false } }),
|
|
592
|
-
this.target === 'web' && this.htmls && this.build_htmls({ info: print, files: false }),
|
|
593
|
-
this.target === 'web' && this.single_js && this.build_single_js({ info: print, files: false })
|
|
594
|
-
]);
|
|
595
|
-
}
|
|
596
|
-
/** 打包构建 js, 构建 html, 复制依赖文件 */
|
|
597
|
-
async build_all_and_close(print = true) {
|
|
316
|
+
export async function build_htmls(fpd_out, production, htmls, { print = print_info, assets_root = '/', template = false, css = true, } = {}) {
|
|
317
|
+
await Promise.all(Object.entries(htmls).map(async ([fp_html, { entry = fp_html.strip_end('.html') + '.js', device_viewport: device_width = false, icon, manifest, dependencies: _dependencies = [], title, scripts, notice = false, heads, }]) => {
|
|
318
|
+
const html_template = '<!doctype html>\n' +
|
|
319
|
+
'<html>\n' +
|
|
320
|
+
' <head>\n' +
|
|
321
|
+
` <title>${title}</title>\n` +
|
|
322
|
+
" <meta charset='utf-8' />\n" +
|
|
323
|
+
(heads ? heads.map(head => ` ${head}`).join_lines() : '') +
|
|
324
|
+
(device_width ? " <meta name='viewport' content='width=device-width, initial-scale=1.0' />\n" : '') +
|
|
325
|
+
(icon ? ` <link rel='icon' href='{root}${get_asset_out(icon)}' />\n` : '') +
|
|
326
|
+
(manifest ? ` <link rel='manifest' href='{root}${manifest}' />\n` : '') +
|
|
327
|
+
(css ? ` <link rel='stylesheet' href='{root}${entry.replace(/\.m?js$/, '.css')}' />\n` : '') +
|
|
328
|
+
resolve_dependency_assets(_dependencies, false, production).map(asset => ` <script src='{root}${get_vendor_asset_out(asset)}' type='module'></script>`).join_lines() +
|
|
329
|
+
(scripts?.before
|
|
330
|
+
? scripts.before.map(asset => ` <script src='{root}${get_asset_out(asset)}' type='module'></script>`).join_lines()
|
|
331
|
+
: '') +
|
|
332
|
+
` <script src='{root}${entry}' type='module'></script>\n` +
|
|
333
|
+
(scripts?.after
|
|
334
|
+
? scripts.after.map(asset => ` <script src='{root}${get_asset_out(asset)}' type='module'></script>`).join_lines()
|
|
335
|
+
: '') +
|
|
336
|
+
(scripts?.after_legacy
|
|
337
|
+
? scripts.after_legacy.map(asset => ` <script src='{root}${get_asset_out(asset)}' defer></script>`).join_lines()
|
|
338
|
+
: '') +
|
|
339
|
+
' </head>\n' +
|
|
340
|
+
' <body>\n' +
|
|
341
|
+
" <div class='root'>" +
|
|
342
|
+
(notice
|
|
343
|
+
? '\n <h2>正在加载 ·· (最多需要十秒钟)</h2>\n' +
|
|
344
|
+
' <h2>如果一直停留在此页面请按 f12 或右键 > 检查,打开开发者工具查看底部控制台报错,并尝试更换浏览器或将浏览器更新到最新版本,同时检查网络连接情况</h2>\n' +
|
|
345
|
+
' '
|
|
346
|
+
: '') +
|
|
347
|
+
'</div>\n' +
|
|
348
|
+
' </body>\n' +
|
|
349
|
+
'</html>\n';
|
|
598
350
|
await Promise.all([
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
this.target === 'web' && this.htmls && this.build_htmls({ info: print, files: false }),
|
|
602
|
-
this.target === 'web' && this.single_js && this.build_single_js({ info: print, files: false })
|
|
351
|
+
fwrite(`${fpd_out}${fp_html}`, html_template.replaceAll('{root}', assets_root), noprint),
|
|
352
|
+
template && fwrite(`${fpd_out}${fp_html.strip_end('.html', true)}.template.html`, html_template, noprint)
|
|
603
353
|
]);
|
|
604
|
-
}
|
|
605
|
-
/** 仅打包构建 js, 不复制依赖 */
|
|
606
|
-
async build_and_close(print = true) {
|
|
607
|
-
await this.build(print);
|
|
608
|
-
await this.close();
|
|
609
|
-
}
|
|
610
|
-
async build_htmls(print = print_info) {
|
|
611
|
-
await Promise.all(Object.entries(this.htmls).map(async ([fp_html, { entry = 'index.js', device_viewport: device_width = false, icon, manifest, dependencies: _dependencies = [], title, scripts, mscripts, notice = false, heads, }]) => {
|
|
612
|
-
const html_template = '<!doctype html>\n' +
|
|
613
|
-
'<html>\n' +
|
|
614
|
-
' <head>\n' +
|
|
615
|
-
` <title>${title}</title>\n` +
|
|
616
|
-
" <meta charset='utf-8' />\n" +
|
|
617
|
-
(heads ? heads.map(head => ` ${head}`).join_lines() : '') +
|
|
618
|
-
(device_width ? " <meta name='viewport' content='width=device-width, initial-scale=1.0' />\n" : '') +
|
|
619
|
-
(icon ? ` <link rel='icon' href='{root}${get_asset_out(icon)}' />\n` : '') +
|
|
620
|
-
(manifest ? ` <link rel='manifest' href='{root}${manifest}' />\n` : '') +
|
|
621
|
-
this.resolve_dependency_assets(_dependencies, false, { production: this.production }).map(asset => ` <script src='{root}${get_vendor_asset_out(asset)}' defer></script>`).join_lines() +
|
|
622
|
-
(scripts?.before
|
|
623
|
-
? scripts.before.map(asset => ` <script src='{root}${get_asset_out(asset)}' defer></script>`).join_lines()
|
|
624
|
-
: '') +
|
|
625
|
-
(mscripts
|
|
626
|
-
? mscripts.map(mscript => ` <script src='{root}${get_asset_out(mscript)}' type='module'></script>`).join_lines()
|
|
627
|
-
: '') +
|
|
628
|
-
` <script src='{root}${entry}' type='module'></script>\n` +
|
|
629
|
-
(scripts?.after
|
|
630
|
-
? scripts.after.map(asset => ` <script src='{root}${get_asset_out(asset)}' defer></script>`).join_lines()
|
|
631
|
-
: '') +
|
|
632
|
-
' </head>\n' +
|
|
633
|
-
' <body>\n' +
|
|
634
|
-
" <div class='root'>" +
|
|
635
|
-
(notice
|
|
636
|
-
? '\n <h2>正在加载 ··· (最多需要十秒钟)</h2>\n' +
|
|
637
|
-
' <h2>如果一直停留在此页面请按 f12 或右键 > 检查,打开开发者工具查看底部控制台报错,并尝试更换浏览器或将浏览器更新到最新版本,同时检查网络连接情况</h2>\n' +
|
|
638
|
-
' '
|
|
639
|
-
: '') +
|
|
640
|
-
'</div>\n' +
|
|
641
|
-
' </body>\n' +
|
|
642
|
-
'</html>\n';
|
|
643
|
-
await Promise.all([
|
|
644
|
-
fwrite(`${this.fpd_out}${fp_html}`, html_template.replaceAll('{root}', this.assets_root), noprint),
|
|
645
|
-
this.template && fwrite(`${this.fpd_out}${fp_html.strip_end('.html', true)}.template.html`, html_template, noprint)
|
|
646
|
-
]);
|
|
647
|
-
if (print.files)
|
|
648
|
-
console.log(`已构建 ${fp_html}`);
|
|
649
|
-
}));
|
|
650
354
|
if (print.files)
|
|
651
|
-
console.log(
|
|
652
|
-
}
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
const { dependencies: dependency_ids_ } = dependencies[id];
|
|
669
|
-
if (dependency_ids_)
|
|
670
|
-
this.resolve_dependencies(dependency_ids_, resolveds);
|
|
671
|
-
resolveds.add(id);
|
|
672
|
-
}
|
|
673
|
-
});
|
|
674
|
-
return resolveds;
|
|
675
|
-
}
|
|
676
|
-
/** 解析依赖的文件
|
|
677
|
-
- dependencies: 依赖 id
|
|
678
|
-
- assets: false 时只包括在 script 标签加载的文件; true 时包括 assets, maps 等 */
|
|
679
|
-
resolve_dependency_assets(_dependencies, assets, { production = this.production, source_map = this.source_map } = {}) {
|
|
680
|
-
return this.resolve_dependencies(_dependencies).map(id => {
|
|
681
|
-
const dependency = dependencies[id];
|
|
682
|
-
const { assets: _assets, maps } = dependency;
|
|
683
|
-
return [
|
|
684
|
-
...assets ? this.resolve_config(_assets, production) : [],
|
|
685
|
-
...assets && source_map ? this.resolve_config(maps, production) : [],
|
|
686
|
-
...this.resolve_config(dependency, production)
|
|
687
|
-
];
|
|
688
|
-
}).flat();
|
|
689
|
-
}
|
|
690
|
-
async copy_files({ dependencies: _dependencies = this.dependencies, production = this.production, assets = this.assets, fpd_root = this.fpd_root, fpd_out = this.fpd_out, print = print_info } = {}) {
|
|
691
|
-
if (print.files)
|
|
692
|
-
console.log(`复制 ${this.name} 的依赖文件到 ${this.fpd_out}`);
|
|
693
|
-
if (_dependencies.length)
|
|
694
|
-
await fmkdir(`${fpd_out}vendors/`, noprint);
|
|
695
|
-
// 输出路径 -> 原路径,用来保证只复制一次且是同样的映射
|
|
696
|
-
let records = new Map();
|
|
697
|
-
const { name } = this;
|
|
698
|
-
async function fcopy_asset(asset) {
|
|
699
|
-
let src, out;
|
|
700
|
-
if (typeof asset === 'string')
|
|
701
|
-
src = out = asset;
|
|
702
|
-
else {
|
|
703
|
-
({ src, out } = asset);
|
|
704
|
-
out ??= src;
|
|
705
|
-
}
|
|
706
|
-
await fcopy_record(path.resolve_with_slash(fpd_root, src), `${fpd_out}${out}`);
|
|
707
|
-
}
|
|
708
|
-
/** 保证同样的输出资源只被写入一次 */
|
|
709
|
-
async function fcopy_record(fp_src, fp_out) {
|
|
710
|
-
const fp_src_old = records.get(fp_out);
|
|
711
|
-
if (fp_src_old) {
|
|
712
|
-
if (fp_src_old !== fp_src)
|
|
713
|
-
throw new Error(`${name} 复制项目资源冲突, ${fp_src_old} 和 ${fp_src} 均复制到 ${fp_out}`);
|
|
714
|
-
}
|
|
715
|
-
else {
|
|
716
|
-
records.set(fp_out, fp_src);
|
|
717
|
-
await fcopy(fp_src, fp_out, { print: print.files });
|
|
718
|
-
}
|
|
355
|
+
console.log(`+ ${fp_html}`.green);
|
|
356
|
+
}));
|
|
357
|
+
}
|
|
358
|
+
export async function copy_assets(fpd_root, fpd_out, production, _dependencies, htmls, assets, source_map = false, print = print_info) {
|
|
359
|
+
if (print.info && !print.files)
|
|
360
|
+
console.log(`复制 assets -> ${fpd_out}`);
|
|
361
|
+
if (_dependencies.length)
|
|
362
|
+
await fmkdir(`${fpd_out}vendors/`, noprint);
|
|
363
|
+
// 输出路径 -> 原路径,用来保证只复制一次且是同样的映射
|
|
364
|
+
let records = new Map();
|
|
365
|
+
async function fcopy_asset(asset) {
|
|
366
|
+
let src, out;
|
|
367
|
+
if (typeof asset === 'string')
|
|
368
|
+
src = out = asset;
|
|
369
|
+
else {
|
|
370
|
+
({ src, out } = asset);
|
|
371
|
+
out ??= src;
|
|
719
372
|
}
|
|
720
|
-
await
|
|
721
|
-
...this.resolve_dependency_assets(_dependencies, true, { production })
|
|
722
|
-
.map(async (asset) => typeof asset === 'string'
|
|
723
|
-
? fcopy_record(`${fpd_root}node_modules/${asset}`, `${fpd_out}vendors/${asset}`)
|
|
724
|
-
: fcopy_record(path.resolve_with_slash(fpd_root, asset.src), path.resolve_with_slash(fpd_out, asset.out || asset.src))),
|
|
725
|
-
...this.resolve_config(assets, production)
|
|
726
|
-
.map(fcopy_asset),
|
|
727
|
-
...this.htmls
|
|
728
|
-
? Object.values(this.htmls).map(async ({ icon, manifest, scripts, mscripts }) => Promise.all([
|
|
729
|
-
icon,
|
|
730
|
-
manifest,
|
|
731
|
-
...(scripts?.before || []),
|
|
732
|
-
...(scripts?.after || []),
|
|
733
|
-
...(mscripts || [])
|
|
734
|
-
].filter(not_empty)
|
|
735
|
-
.map(fcopy_asset))) : []
|
|
736
|
-
]);
|
|
737
|
-
// antd 需要修复 this, 才能在 module 下正常加载
|
|
738
|
-
// if (this.single_js && (_dependencies.includes('antd') || _dependencies.includes('antd-icons'))) {
|
|
739
|
-
// const fp_out = `${fpd_out}vendors/${dependencies.antd[production ? 'productions' : 'devs'][0]}`
|
|
740
|
-
//
|
|
741
|
-
// await fwrite(
|
|
742
|
-
// fp_out,
|
|
743
|
-
// (await fread(fp_out, noprint))
|
|
744
|
-
// .replace(')(this,', ')(globalThis,'),
|
|
745
|
-
// noprint)
|
|
746
|
-
// }
|
|
373
|
+
await fcopy_record(path.resolve_with_slash(fpd_root, src), `${fpd_out}${out}`);
|
|
747
374
|
}
|
|
748
|
-
/**
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
375
|
+
/** 保证同样的输出资源只被写入一次 */
|
|
376
|
+
async function fcopy_record(fp_src, fp_out) {
|
|
377
|
+
const fp_src_old = records.get(fp_out);
|
|
378
|
+
if (fp_src_old) {
|
|
379
|
+
if (fp_src_old !== fp_src)
|
|
380
|
+
throw new Error(`${name} 复制项目资源冲突, ${fp_src_old} 和 ${fp_src} 均复制到 ${fp_out}`);
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
records.set(fp_out, fp_src);
|
|
384
|
+
await fcopy(fp_src, fp_out, { print: print.files });
|
|
755
385
|
}
|
|
386
|
+
await Promise.all([
|
|
387
|
+
...resolve_dependency_assets(_dependencies, true, production, source_map)
|
|
388
|
+
.map(asset => typeof asset === 'string'
|
|
389
|
+
? fcopy_record(`${fpd_root}node_modules/${asset}`, `${fpd_out}vendors/${asset}`)
|
|
390
|
+
: fcopy_record(path.resolve_with_slash(fpd_root, asset.src), path.resolve_with_slash(fpd_out, asset.out || asset.src))),
|
|
391
|
+
...resolve_config(assets, production)
|
|
392
|
+
.map(fcopy_asset),
|
|
393
|
+
...htmls
|
|
394
|
+
? Object.values(htmls).map(({ icon, manifest, scripts }) => Promise.all([
|
|
395
|
+
icon,
|
|
396
|
+
manifest,
|
|
397
|
+
...(scripts?.before || []),
|
|
398
|
+
...(scripts?.after || []),
|
|
399
|
+
...(scripts?.after_legacy || []),
|
|
400
|
+
].filter(not_empty)
|
|
401
|
+
.map(fcopy_asset))) : []
|
|
402
|
+
]);
|
|
403
|
+
// if (_dependencies.includes('monaco')) {
|
|
404
|
+
// const fpd = `${fpd_out}vendors/${dependencies.monaco.assets[production ? 'productions' : 'devs'][0]}`
|
|
405
|
+
//
|
|
406
|
+
// if (fexists(fpd + 'nls.messages.js.js', noprint))
|
|
407
|
+
// await Promise.all(
|
|
408
|
+
// ['nls.messages.js', 'nls.messages.zh-cn.js'].map(fname =>
|
|
409
|
+
// frename(fname + '.js', fname, { fpd })))
|
|
410
|
+
// }
|
|
411
|
+
}
|
|
412
|
+
/** 为空时返回空数组 */
|
|
413
|
+
function resolve_config(config, production) {
|
|
414
|
+
return config
|
|
415
|
+
? (production
|
|
416
|
+
? config.productions
|
|
417
|
+
: config.devs || config.productions) || []
|
|
418
|
+
: [];
|
|
419
|
+
}
|
|
420
|
+
function resolve_dependencies(dependency_ids, resolveds) {
|
|
421
|
+
dependency_ids.forEach(id => {
|
|
422
|
+
if (resolveds.has(id))
|
|
423
|
+
return;
|
|
424
|
+
const { dependencies: dependency_ids_ } = dependencies[id];
|
|
425
|
+
if (dependency_ids_)
|
|
426
|
+
resolve_dependencies(dependency_ids_, resolveds);
|
|
427
|
+
resolveds.add(id);
|
|
428
|
+
});
|
|
429
|
+
return resolveds;
|
|
430
|
+
}
|
|
431
|
+
/** 解析依赖的文件
|
|
432
|
+
- dependencies: 依赖 id
|
|
433
|
+
- assets: false 时只包括在 script 标签加载的文件; true 时包括 assets, maps 等 */
|
|
434
|
+
function resolve_dependency_assets(_dependencies, assets, production, source_map = false) {
|
|
435
|
+
return resolve_dependencies(_dependencies, new Set()).map(id => {
|
|
436
|
+
const dependency = dependencies[id];
|
|
437
|
+
const { assets: _assets, maps } = dependency;
|
|
438
|
+
return [
|
|
439
|
+
...assets ? resolve_config(_assets, production) : [],
|
|
440
|
+
...assets && source_map ? resolve_config(maps, production) : [],
|
|
441
|
+
...resolve_config(dependency, production)
|
|
442
|
+
];
|
|
443
|
+
}).flat();
|
|
756
444
|
}
|
|
445
|
+
//#endregion
|
|
757
446
|
//# sourceMappingURL=builder.js.map
|