@cuipengyu5/build-plugin-lowcode 0.0.1

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.
@@ -0,0 +1,5 @@
1
+
2
+ import Button from './components/button';
3
+
4
+ export const bizCssPrefix = 'bizpack';
5
+ export { Button };
@@ -0,0 +1,6 @@
1
+
2
+ import Button from './components/button';
3
+ import Input from './components/input';
4
+
5
+ export const bizCssPrefix = 'bizpack';
6
+ export { Button, Input };
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@cuipengyu5/build-plugin-lowcode",
3
+ "version": "0.0.1",
4
+ "description": "build plugin for component-to-lowcode",
5
+ "main": "src/index.js",
6
+ "keywords": [
7
+ "plugin"
8
+ ],
9
+ "scripts": {
10
+ "component:dev": "cd demo/component && npm start",
11
+ "setter:dev": "cd demo/setter && npm start",
12
+ "antdSetterMap:dev": "cd demo/antd-setter-map && npm start",
13
+ "pub": "npm publish",
14
+ "beta": "npm publish --tag=beta"
15
+ },
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "https://gitee.com/cuipengyu/cui-lowcode-tools.git",
19
+ "directory": "packages/build-plugin-lowcode"
20
+ },
21
+ "author": "",
22
+ "license": "MIT",
23
+ "dependencies": {
24
+ "@alilc/lowcode-material-parser": "^1.0.1",
25
+ "@alilc/lowcode-rax-renderer": "^1.0.2",
26
+ "@alilc/lowcode-react-renderer": "^1.0.1",
27
+ "@alilc/lowcode-types": "^1.0.1",
28
+ "@alilc/lowcode-utils": "^1.0.1",
29
+ "@babel/core": "^7.22.5",
30
+ "axios": "^0.21.4",
31
+ "build-plugin-component": "^1.12.0",
32
+ "build-scripts-config": "^3.0.3",
33
+ "chokidar": "^3.5.3",
34
+ "cross-spawn-promise": "^0.10.2",
35
+ "driver-universal": "^3.4.0",
36
+ "fs-extra": "^11.1.1",
37
+ "glob": "^7.1.7",
38
+ "handlebars": "^4.4.0",
39
+ "html-webpack-plugin": "^3.2.0",
40
+ "is-wsl": "^2.2.0",
41
+ "lodash": "^4.17.21",
42
+ "rax-babel-config": "^2.0.4",
43
+ "rpx-loader": "^1.0.1",
44
+ "style-loader": "^2.0.0",
45
+ "webpack": "^4.46.0"
46
+ }
47
+ }
package/src/index.js ADDED
@@ -0,0 +1,1322 @@
1
+ const path = require('path');
2
+ const glob = require('glob');
3
+ const axios = require('axios');
4
+ const fse = require('fs-extra');
5
+ const chokidar = require('chokidar');
6
+ const mergeWith = require('lodash/mergeWith');
7
+ const parser = require('@alilc/lowcode-material-parser');
8
+ const HtmlWebpackPlugin = require('html-webpack-plugin');
9
+ const { getWebpackConfig } = require('build-scripts-config');
10
+ const babelCompile = require('./compile/babel');
11
+ const metaCompile = require('./compile/meta');
12
+ const getDemoDir = require('./utils/getDemoDir');
13
+ const isWsl = require('is-wsl');
14
+
15
+ let INIT_STATE = false;
16
+ let PARSED_NPM_NAME;
17
+ const { debug } = console;
18
+
19
+ const UTILS = require('./utils');
20
+ const CONSTANTS = require('./constants');
21
+ const { installModule } = require('./utils/npm');
22
+ const userWebpackConfig = require('./config/user-config');
23
+
24
+ const {
25
+ parseProps,
26
+ parseNpmName,
27
+ generateEntry,
28
+ asyncDebounce,
29
+ camel2KebabComponentName,
30
+ kebab2CamelComponentName,
31
+ getUsedComponentMetas,
32
+ } = UTILS;
33
+
34
+ const {
35
+ COMMON_EXTERNALS,
36
+ COMMON_EXTERNALS_MAP,
37
+ DEFAULT_GROUPS,
38
+ DEFAULT_CATEGORIES,
39
+ STATIC_RESOURCES_MAP,
40
+ BASIC_LIBRARY_VERSION,
41
+ COMPONENT_PROPS,
42
+ UNPKG_BASE_URL_MAP,
43
+ META_TYPES,
44
+ } = CONSTANTS;
45
+
46
+ const debounceBuild = asyncDebounce(build, 300);
47
+ const debounceStart = asyncDebounce(start, 300);
48
+
49
+ const defaultEntryPaths = [
50
+ `./src/index.tsx`,
51
+ `./src/index.ts`,
52
+ `./src/index.js`,
53
+ `./src/index.jsx`,
54
+ `./index.js`,
55
+ `./lib/index.js`,
56
+ `./components/index.ts`,
57
+ `./components/index.tsx`,
58
+ ];
59
+
60
+ const defaultScssEntryPaths = [
61
+ `./src/index.scss`,
62
+ `./src/main.scss`,
63
+ `./index.scss`,
64
+ `./main.scss`,
65
+ `./components/index.scss`,
66
+ ];
67
+
68
+ function getEntry(rootDir, entryPath) {
69
+ if (entryPath && fse.existsSync(path.resolve(rootDir, entryPath))) {
70
+ return path.resolve(rootDir, entryPath).replace(/\\/g, '\\\\');
71
+ }
72
+ for (let i = 0; i < defaultEntryPaths.length; i++) {
73
+ const p = path.resolve(rootDir, defaultEntryPaths[i]);
74
+ if (fse.existsSync(p)) {
75
+ return p.replace(/\\/g, '\\\\');
76
+ // return p;
77
+ }
78
+ }
79
+ return '';
80
+ }
81
+
82
+ function getScssEntry(rootDir) {
83
+ for (let i = 0; i < defaultScssEntryPaths.length; i++) {
84
+ const p = path.resolve(rootDir, defaultScssEntryPaths[i]);
85
+ if (fse.existsSync(p)) {
86
+ return p.replace(/\\/g, '\\\\');
87
+ // return p;
88
+ }
89
+ }
90
+ return '';
91
+ }
92
+
93
+ function formatComponentSchema(schema) {
94
+ let { props } = schema;
95
+ const defaultProps = {};
96
+ let noStyleProp = true;
97
+ if (props && Array.isArray(props)) {
98
+ props.forEach((prop) => {
99
+ if (prop.defaultValue) {
100
+ defaultProps[prop.name] = prop.defaultValue;
101
+ }
102
+ if (noStyleProp && ['style'].includes(prop.name)) {
103
+ noStyleProp = false;
104
+ }
105
+ });
106
+ if (noStyleProp) {
107
+ props.push({
108
+ name: 'style',
109
+ propType: 'object',
110
+ });
111
+ }
112
+ } else {
113
+ props = [
114
+ {
115
+ name: 'style',
116
+ propType: 'object',
117
+ },
118
+ ];
119
+ }
120
+ schema.props = props;
121
+ const parsedSchema = parseProps(schema);
122
+ delete parsedSchema.props;
123
+ parsedSchema.snippets = [
124
+ {
125
+ title: schema.componentName,
126
+ screenshot: schema.screenshot,
127
+ schema: {
128
+ componentName: schema.componentName,
129
+ props: defaultProps,
130
+ },
131
+ },
132
+ ];
133
+ return parsedSchema;
134
+ }
135
+
136
+ function getUsedComponentViews(rootDir, targetDir = 'lowcode', components) {
137
+ let viewPaths = glob.sync(path.resolve(rootDir, `${targetDir}/**/view.@(js|ts|jsx|tsx)`));
138
+ if (viewPaths && viewPaths.length) {
139
+ viewPaths = viewPaths.map((item) => {
140
+ return item.slice(path.resolve(rootDir, targetDir).length + 1, item.lastIndexOf('view') - 1);
141
+ });
142
+ }
143
+ return components
144
+ ? components.filter((component) => {
145
+ return viewPaths.includes(camel2KebabComponentName(component));
146
+ })
147
+ : viewPaths.map((dir) => kebab2CamelComponentName(dir));
148
+ }
149
+
150
+ /**
151
+ * 将 css 打包到 js 文件中
152
+ * @param {object} config webpack chain 配置
153
+ */
154
+ function useStyleLoader(config) {
155
+ const cssRule = config.module.rule('css');
156
+ const scssRule = config.module.rule('scss');
157
+ const scssModuleRule = config.module.rule('scss-module');
158
+ const lessRule = config.module.rule('less');
159
+ const lessModuleRule = config.module.rule('less-module');
160
+ cssRule.uses.delete('MiniCssExtractPlugin.loader');
161
+ scssRule.uses.delete('MiniCssExtractPlugin.loader');
162
+ scssModuleRule.uses.delete('MiniCssExtractPlugin.loader');
163
+ lessRule.uses.delete('MiniCssExtractPlugin.loader');
164
+ lessModuleRule.uses.delete('MiniCssExtractPlugin.loader');
165
+ cssRule.use('style-loader').loader('style-loader').before('css-loader');
166
+ scssRule.use('style-loader').loader('style-loader').before('css-loader');
167
+ scssModuleRule.use('style-loader').loader('style-loader').before('css-loader');
168
+ lessRule.use('style-loader').loader('style-loader').before('css-loader');
169
+ lessModuleRule.use('style-loader').loader('style-loader').before('css-loader');
170
+ }
171
+
172
+ async function registerSetter(context, setterMap) {
173
+ return Promise.all(Object.values(setterMap).map((setter) => installModule(context, setter)));
174
+ }
175
+
176
+ module.exports = async (options, pluginOptions = {}) => {
177
+ const { registerUserConfig, registerCliOption } = options;
178
+ const { rootDir, command } = options.context;
179
+ if (!CONSTANTS.SUPPORTED_COMMAND.includes(command)) {
180
+ debug('Command %s not supported.', command);
181
+ return;
182
+ }
183
+ const cliOptions = ['watch', 'skip-demo', 'watch-dist', 'https', 'disable-open'];
184
+ registerCliOption(
185
+ cliOptions.map((name) => ({
186
+ name,
187
+ commands: ['start', 'build'],
188
+ })),
189
+ );
190
+ registerUserConfig(userWebpackConfig);
191
+
192
+ const mode = command === 'start' ? 'development' : 'production';
193
+ process.argv.forEach((val, index) => {
194
+ debug(`${index}: ${val}`);
195
+ });
196
+
197
+ const { setterMap, engineScope, npmClient } = pluginOptions;
198
+ if (setterMap) {
199
+ await registerSetter(
200
+ {
201
+ workDir: rootDir,
202
+ npmClient: npmClient || (engineScope === '@alilc' ? 'npm' : 'tnpm'),
203
+ },
204
+ setterMap,
205
+ );
206
+ }
207
+
208
+ if (mode === 'production') {
209
+ await debounceBuild(options, pluginOptions, true);
210
+ return;
211
+ }
212
+ await debounceStart(options, pluginOptions);
213
+ const watchPattern = path.resolve(rootDir, 'src/**/**');
214
+ const watcher = chokidar.watch(watchPattern);
215
+ ['add', 'change', 'unlink'].forEach((item) => {
216
+ watcher.on(item, async () => {
217
+ await debounceStart(options, pluginOptions);
218
+ });
219
+ });
220
+ };
221
+
222
+ function confirmMetaTypes(rootDir, lowcodeDir, metaTypes) {
223
+ return metaTypes.filter((item) => {
224
+ const metaFilename = item ? `meta.${item}` : 'meta';
225
+ const res = glob.sync(
226
+ path.resolve(rootDir, `${lowcodeDir}/**/${metaFilename}.@(js|ts|jsx|tsx)`),
227
+ );
228
+ return res.length;
229
+ });
230
+ }
231
+
232
+ function confirmRenderPlatforms(rootDir, platforms) {
233
+ const result = platforms.filter((item) => {
234
+ if (item === 'default') return false;
235
+ const viewPath = `src/${item}/components`;
236
+ const res = glob.sync(path.resolve(rootDir, `${viewPath}/**/view.@(js|ts|jsx|tsx)`));
237
+ return res.length;
238
+ });
239
+ result.unshift('default');
240
+ return result;
241
+ }
242
+
243
+ async function build(options, pluginOptions, execCompile) {
244
+ const webPackConfig = getWebpackConfig('production');
245
+ const { context, onHook } = options;
246
+ const { rootDir, pkg: package, userConfig = {}, commandArgs } = context;
247
+ const { alias = {} } = userConfig;
248
+ const {
249
+ components,
250
+ metaFormat,
251
+ noParse,
252
+ engineScope,
253
+ metaTypes = META_TYPES,
254
+ bundleEachComponentMeta,
255
+ lowcodeDir = 'lowcode',
256
+ entryPath,
257
+ platforms = [],
258
+ type,
259
+ componentsPath,
260
+ } = pluginOptions || {};
261
+ !noParse &&
262
+ (await initLowCodeSchema(
263
+ rootDir,
264
+ package,
265
+ alias['@'] || componentsPath, // componentsPath
266
+ metaFormat,
267
+ metaFormat,
268
+ components,
269
+ engineScope === '@alilc' ? 'npm' : 'tnpm',
270
+ lowcodeDir,
271
+ entryPath,
272
+ ));
273
+ if (execCompile) {
274
+ onHook('before.build.load', async () => {
275
+ await babelCompile({
276
+ source: lowcodeDir,
277
+ rootDir,
278
+ userOptions: userConfig,
279
+ })
280
+ await metaCompile({
281
+ rootDir,
282
+ userOptions: userConfig,
283
+ lowcodeDir,
284
+ package,
285
+ });
286
+ })
287
+ }
288
+ const confirmedMetaTypes = confirmMetaTypes(rootDir, lowcodeDir, metaTypes);
289
+ const metaPaths = await Promise.all(
290
+ confirmedMetaTypes.map((item) => {
291
+ return bundleMetaV2(options, pluginOptions, execCompile, item);
292
+ }),
293
+ );
294
+ const metaPathMap = {};
295
+ metaPaths.forEach((item) => {
296
+ metaPathMap[path.basename(item).replace(path.extname(item), '')] = item;
297
+ // metaPathMap[item.slice(item.lastIndexOf('/') + 1, item.lastIndexOf('.'))] = item;
298
+ });
299
+ const confirmedRenderPlatforms = confirmRenderPlatforms(rootDir, platforms);
300
+ const renderViewPathMap = {};
301
+ const renderViewPaths = await Promise.all(
302
+ confirmedRenderPlatforms.map(async (item) => {
303
+ return await bundleRenderView(options, pluginOptions, item, execCompile);
304
+ }),
305
+ );
306
+ renderViewPaths.forEach((item) => {
307
+ renderViewPathMap[path.basename(item).replace(path.extname(item), '')] = item;
308
+ // renderViewPathMap[item.slice(item.lastIndexOf('/') + 1, item.lastIndexOf('.'))] = item;
309
+ });
310
+ const result = {
311
+ metaPathMap,
312
+ renderViewPathMap,
313
+ platforms: confirmedRenderPlatforms,
314
+ viewPath: await bundleEditorView(
315
+ webPackConfig,
316
+ options,
317
+ pluginOptions,
318
+ metaPathMap,
319
+ confirmedRenderPlatforms,
320
+ execCompile,
321
+ ),
322
+ assetsPaths: await bundleAssets(
323
+ options,
324
+ pluginOptions,
325
+ confirmedMetaTypes,
326
+ confirmedRenderPlatforms,
327
+ execCompile,
328
+ ),
329
+ };
330
+ if (bundleEachComponentMeta) {
331
+ result.componentMetaPath = await bundleComponentMeta(
332
+ webPackConfig,
333
+ options,
334
+ pluginOptions,
335
+ execCompile,
336
+ );
337
+ }
338
+ return result;
339
+ }
340
+
341
+ async function start(options, pluginOptions) {
342
+ const { registerTask, getAllTask, onGetWebpackConfig } = options;
343
+ const { rootDir, pkg: package, commandArgs } = options.context;
344
+ const { https } = commandArgs;
345
+ if (!PARSED_NPM_NAME) {
346
+ PARSED_NPM_NAME = parseNpmName(package.name);
347
+ }
348
+ const {
349
+ package: packageName = package.name,
350
+ library = PARSED_NPM_NAME.uniqueName,
351
+ umdUrls,
352
+ renderUrls,
353
+ editUrls,
354
+ baseLibrary = 'react',
355
+ groups = DEFAULT_GROUPS,
356
+ categories = DEFAULT_CATEGORIES,
357
+ extraAssets = [],
358
+ builtinAssets = [],
359
+ ignoreComponents = {},
360
+ staticResources = {},
361
+ disableStyleLoader = false,
362
+ engineScope = '@ali',
363
+ externals = {},
364
+ setterMap = {},
365
+ fullbackMeta = 'default',
366
+ type = 'component',
367
+ setterName,
368
+ presetConfig = {},
369
+ customPlugins = [],
370
+ } = pluginOptions || {};
371
+ if (baseLibrary === 'rax' && Array.isArray(extraAssets)) {
372
+ extraAssets.push(
373
+ 'https://g.alicdn.com/code/npm/@alife/mobile-page/0.1.1/build/lowcode/assets-prod.json',
374
+ );
375
+ }
376
+ const metaExportName = `${PARSED_NPM_NAME.uniqueName}Meta`;
377
+ const { viewPath, metaPathMap, renderViewPathMap, platforms } = await debounceBuild(
378
+ options,
379
+ pluginOptions,
380
+ false,
381
+ );
382
+ const devViewUrls = !disableStyleLoader ? ['/view.js'] : ['/view.js', '/view.css'];
383
+ const advancedRenderUrls = {};
384
+ platforms.forEach((platform) => {
385
+ advancedRenderUrls[platform] = [`./${platform}.view.js`];
386
+ });
387
+
388
+ if (type === 'setter' && setterName) {
389
+ setterMap[setterName] = path.resolve(rootDir, 'src/index');
390
+ }
391
+
392
+ let _setterMap = '{';
393
+ const setterImportStr = Object.keys(setterMap || {})
394
+ .map((item) => {
395
+ _setterMap += `\n ${item},`;
396
+ const setterStr = setterMap[item];
397
+ const lastIndexOfAt = setterStr.lastIndexOf('@');
398
+ let npmName = setterStr;
399
+ if (lastIndexOfAt > 0) {
400
+ npmName = setterStr.slice(0, lastIndexOfAt);
401
+ }
402
+ return `import ${item} from '${npmName}';`;
403
+ })
404
+ .join('\n');
405
+ _setterMap += '\n}';
406
+ const indexJs = generateEntry({
407
+ template: 'index.jsx',
408
+ filename: 'index.jsx',
409
+ rootDir,
410
+ params: {
411
+ package: packageName,
412
+ version: package.version,
413
+ library,
414
+ urls: JSON.stringify(renderUrls || umdUrls || devViewUrls),
415
+ editUrls: JSON.stringify(editUrls || umdUrls || devViewUrls),
416
+ advancedRenderUrls: JSON.stringify(advancedRenderUrls),
417
+ devMode: true,
418
+ metaExportName,
419
+ baseLibrary,
420
+ groups: JSON.stringify(groups),
421
+ categories: JSON.stringify(categories),
422
+ extraAssets: JSON.stringify(extraAssets),
423
+ builtinAssets: JSON.stringify(builtinAssets),
424
+ ignoreComponents: JSON.stringify(ignoreComponents),
425
+ setterImportStr,
426
+ setterMap: _setterMap,
427
+ metaPathMap: JSON.stringify(metaPathMap),
428
+ fullbackMeta,
429
+ setterName: setterName || '',
430
+ type,
431
+ presetConfig: JSON.stringify(presetConfig),
432
+ customPlugins: JSON.stringify(customPlugins),
433
+ },
434
+ });
435
+ const previewJs = generateEntry({
436
+ template: 'preview.jsx',
437
+ filename: 'preview.jsx',
438
+ rootDir,
439
+ params: {
440
+ isRax: baseLibrary === 'rax',
441
+ },
442
+ });
443
+ if (getAllTask().includes('lowcode-dev')) return;
444
+ registerTask('lowcode-dev', getWebpackConfig('development'));
445
+ onGetWebpackConfig('lowcode-dev', (config) => {
446
+ const entry = {
447
+ index: indexJs,
448
+ preview: previewJs,
449
+ ...metaPathMap,
450
+ ...renderViewPathMap,
451
+ };
452
+ if (!editUrls && !umdUrls) {
453
+ entry.view = viewPath;
454
+ }
455
+
456
+ config.merge({
457
+ entry,
458
+ });
459
+ config.plugin('index').use(HtmlWebpackPlugin, [
460
+ {
461
+ inject: false,
462
+ templateParameters: {
463
+ ...STATIC_RESOURCES_MAP[engineScope],
464
+ ...staticResources,
465
+ },
466
+ template: require.resolve('./public/index.html'),
467
+ filename: 'index.html',
468
+ },
469
+ ]);
470
+ config.plugin('designer').use(HtmlWebpackPlugin, [
471
+ {
472
+ inject: false,
473
+ templateParameters: {
474
+ ...STATIC_RESOURCES_MAP[engineScope],
475
+ ...staticResources,
476
+ },
477
+ template: require.resolve('./public/designer.html'),
478
+ filename: 'designer.html',
479
+ },
480
+ ]);
481
+ config.plugin('preview').use(HtmlWebpackPlugin, [
482
+ {
483
+ inject: false,
484
+ templateParameters: {
485
+ previewCssUrl: '',
486
+ isRax: baseLibrary === 'rax',
487
+ ...STATIC_RESOURCES_MAP[engineScope],
488
+ },
489
+ template: require.resolve('./public/preview.html'),
490
+ filename: 'preview.html',
491
+ },
492
+ ]);
493
+ config.devServer.headers({ 'Access-Control-Allow-Origin': '*' });
494
+
495
+ config.devServer.https(Boolean(https));
496
+ config.devServer.set('transportMode', 'ws');
497
+ // WSL 环境下正常的文件 watch 失效,需切换为 poll 模式
498
+ if (isWsl) {
499
+ config.merge({
500
+ devServer: {
501
+ watchOptions: {
502
+ poll: 1000,
503
+ },
504
+ },
505
+ });
506
+ }
507
+ config.externals({ ...COMMON_EXTERNALS_MAP[engineScope], ...externals });
508
+ !disableStyleLoader && useStyleLoader(config);
509
+ if (baseLibrary === 'rax') {
510
+ config.module.rule('scss').use('rpx-loader').loader('rpx-loader').before('css-loader');
511
+ }
512
+ });
513
+ }
514
+
515
+ async function initLowCodeSchema(
516
+ rootDir,
517
+ package,
518
+ componentsPath,
519
+ devAlias,
520
+ metaFormat,
521
+ components,
522
+ npmClient = 'tnpm',
523
+ lowcodeDir = 'lowcode',
524
+ entryPath,
525
+ ) {
526
+ if (INIT_STATE) {
527
+ return;
528
+ }
529
+ INIT_STATE = true;
530
+ if (!PARSED_NPM_NAME) {
531
+ PARSED_NPM_NAME = parseNpmName(package.name);
532
+ }
533
+ const entry = getEntry(rootDir, entryPath);
534
+ const lowcodeDirExists = await fse.existsSync(path.resolve(rootDir, lowcodeDir));
535
+ if (lowcodeDirExists) {
536
+ const lowcodeDirs = await fse.readdir(path.resolve(rootDir, lowcodeDir));
537
+ const componentsDirs = await fse.readdir(
538
+ path.resolve(rootDir, componentsPath || 'src/components'),
539
+ );
540
+ const lowcodeDirMap = {};
541
+ lowcodeDirs.forEach((item) => {
542
+ lowcodeDirMap[item] = true;
543
+ });
544
+ const newComponentDir = componentsDirs.filter((dir) => !lowcodeDirMap[dir]);
545
+ if (!newComponentDir || !newComponentDir.length) {
546
+ return;
547
+ }
548
+ }
549
+ let result = await parser.default({ accesser: 'local', entry, npmClient });
550
+ if (!result) {
551
+ // 未解析出结果,默认生成结果
552
+ result = [
553
+ formatComponentSchema({
554
+ componentName: PARSED_NPM_NAME.uniqueName,
555
+ npm: {
556
+ package: package.name,
557
+ version: package.version,
558
+ exportName: 'default',
559
+ main: 'lib/index.js',
560
+ destructuring: false,
561
+ subName: '',
562
+ },
563
+ }),
564
+ ];
565
+ } else if (result.length === 1 && result[0].componentName === 'default') {
566
+ result[0].componentName = PARSED_NPM_NAME.uniqueName;
567
+ if (result[0].title === 'default') {
568
+ result[0].title = PARSED_NPM_NAME.uniqueName;
569
+ }
570
+ }
571
+ const metaDevSubfix = devAlias ? `.${devAlias}` : '';
572
+ const filteredComponents =
573
+ !components || !components.length
574
+ ? result
575
+ : result.filter((item) => item && components.includes(item.componentName));
576
+ filteredComponents.forEach((item) => {
577
+ const componentNameFolder = camel2KebabComponentName(item.componentName);
578
+ if (
579
+ !fse.existsSync(
580
+ path.resolve(
581
+ rootDir,
582
+ `${lowcodeDir}/${componentNameFolder}/meta${metaDevSubfix}.${metaFormat || 'ts'}`,
583
+ ),
584
+ ) &&
585
+ !fse.existsSync(
586
+ path.resolve(rootDir, `${lowcodeDir}/${componentNameFolder}/meta${metaDevSubfix}.js`),
587
+ )
588
+ ) {
589
+ const schema = formatComponentSchema(item);
590
+ if (schema.title === package.name) {
591
+ schema.title = schema.componentName;
592
+ }
593
+ const { snippets } = schema;
594
+ const componentDescription = schema;
595
+ delete componentDescription.snippets;
596
+ fse.outputFileSync(
597
+ path.resolve(
598
+ rootDir,
599
+ `${lowcodeDir}/${componentNameFolder}/meta${metaDevSubfix}.${metaFormat || 'ts'}`,
600
+ ),
601
+ `
602
+ import { IPublicTypeComponentMetadata, IPublicTypeSnippet } from '@alilc/lowcode-types';
603
+
604
+ const ${item.componentName}Meta: IPublicTypeComponentMetadata = ${JSON.stringify(
605
+ componentDescription,
606
+ null,
607
+ 2,
608
+ )};
609
+ const snippets: IPublicTypeSnippet[] = ${JSON.stringify(snippets, null, 2)};
610
+
611
+ export default {
612
+ ...${item.componentName}Meta,
613
+ snippets
614
+ };
615
+ `,
616
+ );
617
+ }
618
+ });
619
+ }
620
+
621
+ async function bundleMetaV2(options, pluginOptions, execCompile, metaType) {
622
+ const { registerTask, getAllTask, onGetWebpackConfig, context } = options;
623
+ const { rootDir, pkg: package, userConfig = {} } = context;
624
+ if (!PARSED_NPM_NAME) {
625
+ PARSED_NPM_NAME = parseNpmName(package.name);
626
+ }
627
+ const metaExportName = `${PARSED_NPM_NAME.uniqueName}Meta`;
628
+ let { components } = pluginOptions || {};
629
+ const {
630
+ categories = DEFAULT_CATEGORIES,
631
+ externals = {},
632
+ basicLibraryVersion: customBasicLibraryVersion,
633
+ buildTarget = 'build',
634
+ fullbackMeta = 'default',
635
+ lowcodeDir = 'lowcode',
636
+ engineScope = '@ali',
637
+ npmInfo = {},
638
+ } = pluginOptions || {};
639
+ if (components && !Array.isArray(components)) {
640
+ console.error('[@alifd/build-plugin-lowcode] components must be Array<ComponentName: string>');
641
+ components = null;
642
+ }
643
+ const metaSuffix = metaType ? `.${metaType}` : '';
644
+ const metaFilename = `meta${metaSuffix}`;
645
+ let fullbackComponents;
646
+ let fullbackMetaSuffix;
647
+ if (fullbackMeta) {
648
+ fullbackMetaSuffix = fullbackMeta === 'default' ? '' : `.${fullbackMeta}`;
649
+ fullbackComponents = getUsedComponentMetas(
650
+ rootDir,
651
+ lowcodeDir,
652
+ `meta${fullbackMetaSuffix}`,
653
+ components,
654
+ );
655
+ }
656
+ const usedComponents = getUsedComponentMetas(
657
+ rootDir,
658
+ lowcodeDir,
659
+ `meta${metaSuffix}`,
660
+ components,
661
+ );
662
+ const componentsImportStr = fullbackComponents
663
+ .map((component) => {
664
+ const componentNameFolder = camel2KebabComponentName(component);
665
+ let metaJsPath = path.resolve(
666
+ rootDir,
667
+ `${lowcodeDir}/${componentNameFolder}/${metaFilename}`,
668
+ );
669
+ if (!usedComponents.includes(component) && fullbackComponents.includes(component)) {
670
+ metaJsPath = path.resolve(
671
+ rootDir,
672
+ `${lowcodeDir}/${componentNameFolder}/meta${fullbackMetaSuffix}`,
673
+ );
674
+ usedComponents.push(component);
675
+ }
676
+ metaJsPath = metaJsPath.replace(/\\/g, '\\\\')
677
+ return `import ${
678
+ component.includes('.') ? component.replace(/\./g, '') : component
679
+ }Meta from '${metaJsPath}'`;
680
+ })
681
+ .join('\n');
682
+ const metaPath = generateEntry({
683
+ template: 'meta.js',
684
+ filename: `meta${metaSuffix}.js`,
685
+ rootDir,
686
+ params: {
687
+ componentsImportStr,
688
+ components: usedComponents.map(
689
+ (component) => `${component.includes('.') ? component.replace(/\./g, '') : component}Meta`,
690
+ ),
691
+ execCompile,
692
+ metaExportName,
693
+ categories: JSON.stringify(categories),
694
+ npmInfo: JSON.stringify(npmInfo || {}),
695
+ version: package.version,
696
+ packageName: package.name,
697
+ basicLibraryVersion: JSON.stringify(customBasicLibraryVersion || BASIC_LIBRARY_VERSION),
698
+ },
699
+ });
700
+ if (!execCompile || getAllTask().includes(`lowcode-meta-${metaType}`)) return metaPath;
701
+ registerTask(`lowcode-meta-${metaType}`, getWebpackConfig('production'));
702
+ onGetWebpackConfig(`lowcode-meta-${metaType}`, (config) => {
703
+ config.merge({
704
+ entry: {
705
+ [`meta${metaSuffix}`]: metaPath,
706
+ },
707
+ });
708
+ config.output.library(metaExportName).libraryTarget('umd');
709
+ config.output.path(path.resolve(rootDir, `${buildTarget}/${lowcodeDir}`));
710
+ config.externals({ ...COMMON_EXTERNALS_MAP[engineScope], ...externals });
711
+ useStyleLoader(config);
712
+ });
713
+ return metaPath;
714
+ }
715
+
716
+ async function bundleEditorView(
717
+ webPackConfig,
718
+ options,
719
+ pluginOptions,
720
+ metaPathMap,
721
+ platforms,
722
+ execCompile,
723
+ ) {
724
+ const { registerTask, getAllTask, onGetWebpackConfig } = options;
725
+ const { rootDir, pkg: package } = options.context;
726
+ if (!PARSED_NPM_NAME) {
727
+ PARSED_NPM_NAME = parseNpmName(package.name);
728
+ }
729
+ const {
730
+ package: packageName = package.name,
731
+ library = PARSED_NPM_NAME.uniqueName,
732
+ umdUrls,
733
+ renderUrls,
734
+ editUrls,
735
+ baseLibrary = 'react',
736
+ components,
737
+ groups = DEFAULT_GROUPS,
738
+ categories = DEFAULT_CATEGORIES,
739
+ staticResources = {},
740
+ singleComponent = false,
741
+ ignoreComponents = {},
742
+ engineScope = '@ali',
743
+ externals = {},
744
+ setterMap = {},
745
+ buildTarget = 'build',
746
+ fullbackMeta = 'default',
747
+ lowcodeDir = 'lowcode',
748
+ entryPath,
749
+ type = 'component',
750
+ setterName,
751
+ presetConfig = {},
752
+ customPlugins = [],
753
+ } = pluginOptions || {};
754
+ const metaExportName = `${PARSED_NPM_NAME.uniqueName}Meta`;
755
+ const advancedRenderUrls = {};
756
+ platforms.forEach((platform) => {
757
+ advancedRenderUrls[platform] = [
758
+ `./render/${platform}/view.js`,
759
+ `./render/${platform}/view.css`,
760
+ ];
761
+ });
762
+ let _setterMap = '{';
763
+ const setterImportStr = Object.keys(setterMap || {})
764
+ .map((item) => {
765
+ _setterMap += `\n ${item},`;
766
+ return `import ${item} from '${setterMap[item]}';`;
767
+ })
768
+ .join('\n');
769
+ _setterMap += '\n}';
770
+ const indexJsParams = {
771
+ package: packageName,
772
+ version: package.version,
773
+ library,
774
+ urls: JSON.stringify(
775
+ renderUrls ||
776
+ umdUrls || [
777
+ `${buildTarget}/${lowcodeDir}/view.js`,
778
+ `${buildTarget}/${lowcodeDir}/view.css`,
779
+ ],
780
+ ),
781
+ editUrls: JSON.stringify(
782
+ editUrls ||
783
+ umdUrls || [
784
+ `${buildTarget}/${lowcodeDir}/view.js`,
785
+ `${buildTarget}/${lowcodeDir}/view.css`,
786
+ ],
787
+ ),
788
+ advancedRenderUrls: JSON.stringify(advancedRenderUrls),
789
+ metaUrl: `${buildTarget}/${lowcodeDir}/meta.js`,
790
+ devMode: false,
791
+ metaExportName,
792
+ baseLibrary,
793
+ groups: JSON.stringify(groups),
794
+ categories: JSON.stringify(categories),
795
+ ignoreComponents: JSON.stringify(ignoreComponents),
796
+ extraAssets: 'false',
797
+ builtinAssets: 'false',
798
+ setterImportStr,
799
+ setterMap: _setterMap,
800
+ metaPathMap: JSON.stringify(metaPathMap),
801
+ fullbackMeta,
802
+ setterName: setterName || '',
803
+ type,
804
+ presetConfig: JSON.stringify(presetConfig),
805
+ customPlugins: JSON.stringify(customPlugins),
806
+ };
807
+ const indexJs = generateEntry({
808
+ template: 'index.jsx',
809
+ filename: 'index.jsx',
810
+ rootDir,
811
+ params: indexJsParams,
812
+ });
813
+ const previewJs = generateEntry({
814
+ template: 'preview.jsx',
815
+ filename: 'preview.jsx',
816
+ rootDir,
817
+ params: {
818
+ isRax: baseLibrary === 'rax',
819
+ },
820
+ });
821
+ let componentViews;
822
+ let componentViewsExportStr;
823
+ let componentViewsImportStr;
824
+ const lowcodeViewPath = path.resolve(rootDir, `${lowcodeDir}/view.tsx`);
825
+ if (singleComponent && fse.existsSync(lowcodeViewPath)) {
826
+ componentViewsImportStr = `import * as SingleComponentData from '${lowcodeViewPath}'`;
827
+ componentViews = `{
828
+ ...SingleComponentData
829
+ }`;
830
+ // default 不一定存在,export { default } 不安全可能会报错
831
+ componentViewsExportStr = `\nconst entryDefault = componentInstances.default;\nexport { entryDefault as default };\nexport * from '${lowcodeViewPath}';`;
832
+ } else {
833
+ const _componentViews = getUsedComponentViews(rootDir, lowcodeDir, components) || [];
834
+ componentViews = `{${_componentViews
835
+ .map((component) => {
836
+ return `${component}: ${component}`;
837
+ })
838
+ .join(',')}}`;
839
+ componentViewsExportStr = _componentViews
840
+ .map((component) => {
841
+ return `const ${component} = getRealComponent(${component}Data, '${component}');\nexport { ${component} };`;
842
+ })
843
+ .join('\n');
844
+ // default 不一定存在,export { default } 不安全可能会报错
845
+ componentViewsExportStr += `\nconst entryDefault = componentInstances.default;\nexport { entryDefault as default }`;
846
+ componentViewsImportStr = _componentViews
847
+ .map((component) => {
848
+ const componentNameFolder = camel2KebabComponentName(component);
849
+ const viewJsPath = path.resolve(rootDir, `${lowcodeDir}/${componentNameFolder}/view`).replace(/\\/g, '\\\\');
850
+ return `import * as ${component}Data from '${viewJsPath}';`;
851
+ })
852
+ .join('\n');
853
+ }
854
+ const scssEntry = getScssEntry(rootDir);
855
+ const viewPath = generateEntry({
856
+ template: 'view.js',
857
+ filename: 'view.js',
858
+ rootDir,
859
+ params: {
860
+ entryPath: getEntry(rootDir, entryPath),
861
+ scssImport: scssEntry ? `import '${scssEntry}'` : '',
862
+ componentViews,
863
+ componentViewsExportStr,
864
+ componentViewsImportStr,
865
+ library,
866
+ execCompile,
867
+ },
868
+ });
869
+ console.log('in render view: ', execCompile);
870
+ if (!execCompile || editUrls || umdUrls || getAllTask().includes('lowcode-editor-view'))
871
+ return viewPath;
872
+ registerTask('lowcode-editor-view', webPackConfig);
873
+ onGetWebpackConfig('lowcode-editor-view', (config) => {
874
+ debug('editor view build');
875
+ config.plugin('HtmlWebpackPlugin').use(HtmlWebpackPlugin, [
876
+ {
877
+ inject: false,
878
+ templateParameters: {
879
+ ...STATIC_RESOURCES_MAP[engineScope],
880
+ ...staticResources,
881
+ },
882
+ template: require.resolve('./public/index.html'),
883
+ filename: 'index.html',
884
+ },
885
+ ]);
886
+ config.plugin('designer').use(HtmlWebpackPlugin, [
887
+ {
888
+ inject: false,
889
+ templateParameters: {
890
+ ...STATIC_RESOURCES_MAP[engineScope],
891
+ ...staticResources,
892
+ },
893
+ template: require.resolve('./public/designer.html'),
894
+ filename: 'designer.html',
895
+ },
896
+ ]);
897
+ config.plugin('preview').use(HtmlWebpackPlugin, [
898
+ {
899
+ inject: false,
900
+ templateParameters: {
901
+ previewCssUrl: './preview.css',
902
+ isRax: baseLibrary === 'rax',
903
+ ...STATIC_RESOURCES_MAP[engineScope],
904
+ },
905
+ template: require.resolve('./public/preview.html'),
906
+ filename: 'preview.html',
907
+ },
908
+ ]);
909
+ config.merge({
910
+ entry: {
911
+ view: viewPath,
912
+ index: indexJs,
913
+ preview: previewJs,
914
+ },
915
+ });
916
+ config.output.library(library).libraryTarget('umd');
917
+ config.output.path(path.resolve(rootDir, `${buildTarget}/${lowcodeDir}`));
918
+ config.externals({ ...COMMON_EXTERNALS_MAP[engineScope], ...externals });
919
+ if (baseLibrary === 'rax') {
920
+ const scssRule = config.module.rule('scss');
921
+ scssRule.use('rpx-loader').loader('rpx-loader').before('css-loader');
922
+ }
923
+ });
924
+ return viewPath;
925
+ }
926
+
927
+ async function bundleRenderView(options, pluginOptions, platform, execCompile) {
928
+ const { registerTask, getAllTask, onGetWebpackConfig } = options;
929
+ const { rootDir, pkg: package } = options.context;
930
+ if (!PARSED_NPM_NAME) {
931
+ PARSED_NPM_NAME = parseNpmName(package.name);
932
+ }
933
+ const {
934
+ library = PARSED_NPM_NAME.uniqueName,
935
+ umdUrls,
936
+ editUrls,
937
+ baseLibrary = 'react',
938
+ components,
939
+ externals = {},
940
+ buildTarget = 'build',
941
+ lowcodeDir = 'lowcode',
942
+ engineScope = '@ali',
943
+ entryPath,
944
+ } = pluginOptions || {};
945
+ let componentViews;
946
+ let componentViewsExportStr;
947
+ let componentViewsImportStr;
948
+ const _componentViews =
949
+ getUsedComponentViews(rootDir, `src/${platform}/components`, components) || [];
950
+ console.log('_componentViews: ', _componentViews);
951
+ componentViews = `{${_componentViews
952
+ .map((component) => {
953
+ return `${component}: ${component}`;
954
+ })
955
+ .join(',')}}`;
956
+ componentViewsExportStr = _componentViews
957
+ .map((component) => {
958
+ return `const ${component} = getRealComponent(${component}Data, '${component}');\nexport { ${component} };`;
959
+ })
960
+ .join('\n');
961
+ const exportPath = `\nexport { default } from '${getEntry(rootDir, entryPath)}';`;
962
+ componentViewsExportStr += exportPath.includes('\\\\') ? exportPath : exportPath.replace(/\\/g, '\\\\');
963
+ componentViewsImportStr = _componentViews
964
+ .map((component) => {
965
+ const componentNameFolder = camel2KebabComponentName(component);
966
+ const viewJsPath = getEntry(
967
+ rootDir,
968
+ `src/${platform}/components/${componentNameFolder}/view`,
969
+ );
970
+ return `import * as ${component}Data from '${viewJsPath}'`;
971
+ })
972
+ .join('\n');
973
+ const scssEntry = getScssEntry(rootDir);
974
+ const viewPath = generateEntry({
975
+ template: 'view.js',
976
+ filename: `${platform}.view.js`,
977
+ rootDir,
978
+ params: {
979
+ entryPath: getEntry(rootDir, entryPath),
980
+ scssImport: scssEntry ? `import '${scssEntry}'` : '',
981
+ componentViews,
982
+ componentViewsExportStr,
983
+ componentViewsImportStr,
984
+ library,
985
+ execCompile,
986
+ },
987
+ });
988
+ if (!execCompile || editUrls || umdUrls || getAllTask().includes(`render-view-${platform}`))
989
+ return viewPath;
990
+ registerTask(`render-view-${platform}`, getWebpackConfig('production'));
991
+ onGetWebpackConfig(`render-view-${platform}`, (config) => {
992
+ debug('render view build: ', viewPath);
993
+ config.merge({
994
+ entry: {
995
+ view: viewPath,
996
+ },
997
+ });
998
+ config.output.library(library).libraryTarget('umd');
999
+ config.output.path(path.resolve(rootDir, `${buildTarget}/${lowcodeDir}/render/${platform}`));
1000
+ config.externals({ ...COMMON_EXTERNALS_MAP[engineScope], ...externals });
1001
+ if (baseLibrary === 'rax') {
1002
+ const scssRule = config.module.rule('scss');
1003
+ scssRule.use('rpx-loader').loader('rpx-loader').before('css-loader');
1004
+ }
1005
+ });
1006
+ return viewPath;
1007
+ }
1008
+
1009
+ async function bundleAssets(options, pluginOptions, metaTypes, renderTypes, execCompile) {
1010
+ const { onHook } = options;
1011
+ const { rootDir, pkg: package } = options.context;
1012
+ if (!PARSED_NPM_NAME) {
1013
+ PARSED_NPM_NAME = parseNpmName(package.name);
1014
+ }
1015
+ const metaExportName = `${PARSED_NPM_NAME.uniqueName}Meta`;
1016
+ const {
1017
+ package: packageName = package.name,
1018
+ baseUrl,
1019
+ library = PARSED_NPM_NAME.uniqueName,
1020
+ umdUrls,
1021
+ renderUrls,
1022
+ editUrls,
1023
+ groups = DEFAULT_GROUPS,
1024
+ categories = DEFAULT_CATEGORIES,
1025
+ builtinAssets = [],
1026
+ extraAssets = [],
1027
+ baseLibrary,
1028
+ ignoreComponents = {},
1029
+ buildTarget = 'build',
1030
+ engineScope = '@ali',
1031
+ lowcodeDir = 'lowcode',
1032
+ } = pluginOptions || {};
1033
+
1034
+ if (baseLibrary === 'rax' && Array.isArray(extraAssets)) {
1035
+ extraAssets.push(
1036
+ `https://g.alicdn.com/code/npm/@alife/mobile-page/0.1.1/build/lowcode/assets-prod.json`,
1037
+ );
1038
+ }
1039
+ const baseSchemas = await Promise.all(
1040
+ builtinAssets.map(async (url) => {
1041
+ if (typeof url === 'object') {
1042
+ return url;
1043
+ } else {
1044
+ try {
1045
+ return await axios(url).then(({ data }) => data);
1046
+ } catch (e) {
1047
+ console.error(
1048
+ `[@alifd/build-plugin-lowcode] get assets data from builtin assets ${url} failed: `,
1049
+ e,
1050
+ );
1051
+ return {};
1052
+ }
1053
+ }
1054
+ }),
1055
+ );
1056
+ const extraSchemas = await Promise.all(
1057
+ extraAssets.map(async (url) => {
1058
+ if (typeof url === 'object') {
1059
+ return url;
1060
+ } else {
1061
+ try {
1062
+ return await axios(url).then(({ data }) => data);
1063
+ } catch (e) {
1064
+ console.error(
1065
+ `[@alifd/build-plugin-lowcode] get assets data from builtin assets ${url} failed: `,
1066
+ e,
1067
+ );
1068
+ return {};
1069
+ }
1070
+ }
1071
+ }),
1072
+ );
1073
+ const assetsPaths = await Promise.all(
1074
+ ['daily', 'prod', 'dev'].map(async (item) => {
1075
+ const _baseUrl =
1076
+ (baseUrl && baseUrl[item]) ||
1077
+ `${UNPKG_BASE_URL_MAP[engineScope]}/${package.name}@${package.version}`;
1078
+ let urls;
1079
+ let metaUrl;
1080
+ const metaUrls = {};
1081
+ const advancedRenderUrls = {};
1082
+ const advancedEditUrls = {};
1083
+ const advancedMetaUrls = {};
1084
+ if (item === 'dev') {
1085
+ urls = JSON.stringify([`./view.js`, `./view.css`]);
1086
+ metaTypes.forEach((item) => {
1087
+ const _url = item ? `./meta.${item}.js` : './meta.js';
1088
+ if (!metaUrl) metaUrl = _url;
1089
+ metaUrls[item || 'default'] = _url;
1090
+ advancedMetaUrls[item || 'default'] = [_url];
1091
+ });
1092
+ renderTypes.forEach((renderType) => {
1093
+ advancedRenderUrls[renderType] = [
1094
+ `./render/${renderType}/view.js`,
1095
+ `./render/${renderType}/view.css`,
1096
+ ];
1097
+ });
1098
+ } else {
1099
+ urls = JSON.stringify([
1100
+ `${_baseUrl}/${buildTarget}/${lowcodeDir}/view.js`,
1101
+ `${_baseUrl}/${buildTarget}/${lowcodeDir}/view.css`,
1102
+ ]);
1103
+ metaTypes.forEach((item) => {
1104
+ const _url = item
1105
+ ? `${_baseUrl}/${buildTarget}/${lowcodeDir}/meta.${item}.js`
1106
+ : `${_baseUrl}/${buildTarget}/${lowcodeDir}/meta.js`;
1107
+ if (!metaUrl) metaUrl = _url;
1108
+ metaUrls[item || 'default'] = _url;
1109
+ advancedMetaUrls[item || 'default'] = [_url];
1110
+ });
1111
+ renderTypes.forEach((renderType) => {
1112
+ advancedRenderUrls[renderType] = [
1113
+ `${_baseUrl}/${buildTarget}/${lowcodeDir}/render/${renderType}/view.js`,
1114
+ `${_baseUrl}/${buildTarget}/${lowcodeDir}/render/${renderType}/view.css`,
1115
+ ];
1116
+ });
1117
+ }
1118
+ const _urls = advancedRenderUrls.default || renderUrls || umdUrls;
1119
+ const _editUrls = editUrls || umdUrls;
1120
+ const assetsPath = generateEntry({
1121
+ template: 'assets.json',
1122
+ filename: `assets-${item}.json`,
1123
+ rootDir,
1124
+ params: {
1125
+ package: packageName,
1126
+ version: package.version,
1127
+ library,
1128
+ urls: _urls ? JSON.stringify(_urls) : urls,
1129
+ editUrls: _editUrls ? JSON.stringify(_editUrls) : urls,
1130
+ metaUrl,
1131
+ metaUrls: JSON.stringify(metaUrls),
1132
+ metaExportName,
1133
+ groups: JSON.stringify(groups),
1134
+ categories: JSON.stringify(categories),
1135
+ ignoreComponents: JSON.stringify(ignoreComponents),
1136
+ advancedRenderUrls: JSON.stringify(advancedRenderUrls),
1137
+ advancedEditUrls: JSON.stringify(advancedEditUrls),
1138
+ advancedMetaUrls: JSON.stringify(advancedMetaUrls),
1139
+ },
1140
+ });
1141
+ let schemas = baseSchemas;
1142
+ if (item === 'dev') {
1143
+ schemas = [...extraSchemas, ...baseSchemas];
1144
+ }
1145
+ const assetsData = require(assetsPath);
1146
+ schemas.forEach((schemaItem) => {
1147
+ mergeWith(assetsData, schemaItem, (objValue, srcValue) => {
1148
+ if (Array.isArray(objValue) && Array.isArray(srcValue)) {
1149
+ if (typeof objValue[0] === 'string') {
1150
+ const tempMap = {};
1151
+ srcValue.forEach((srcItem) => {
1152
+ tempMap[srcItem] = true;
1153
+ });
1154
+ objValue.forEach((objItem) => {
1155
+ if (!tempMap[objItem]) {
1156
+ srcValue.push(objItem);
1157
+ }
1158
+ });
1159
+ return srcValue;
1160
+ } else {
1161
+ return srcValue.concat(objValue);
1162
+ }
1163
+ }
1164
+ });
1165
+ });
1166
+ const packageMap = {};
1167
+ assetsData.packages.forEach((packageItem) => {
1168
+ if (!packageMap[packageItem.package]) {
1169
+ packageMap[packageItem.package] = packageItem;
1170
+ }
1171
+ });
1172
+ assetsData.packages = Object.values(packageMap);
1173
+ fse.outputFileSync(assetsPath, JSON.stringify(assetsData, null, 2));
1174
+ return assetsPath;
1175
+ }),
1176
+ );
1177
+ if (!execCompile) return assetsPaths;
1178
+ onHook('after.build.compile', () => {
1179
+ ['dev', 'daily', 'prod'].forEach((item) => {
1180
+ const filename = `assets-${item}.json`;
1181
+ const targetPath = path.resolve(rootDir, `${buildTarget}/${lowcodeDir}/${filename}`);
1182
+ const originPath = path.resolve(rootDir, `.tmp/${filename}`);
1183
+ if (!fse.existsSync(originPath)) {
1184
+ return;
1185
+ }
1186
+ fse.outputFileSync(targetPath, JSON.stringify(require(originPath), null, 2));
1187
+ });
1188
+ updatePackage(rootDir, baseUrl, lowcodeDir, buildTarget, engineScope, package);
1189
+ });
1190
+ return assetsPaths;
1191
+ }
1192
+
1193
+ function updatePackage(
1194
+ rootDir,
1195
+ baseUrl,
1196
+ lowcodeDir = 'lowcode',
1197
+ buildTarget = 'build',
1198
+ engineScope = '@ali',
1199
+ package,
1200
+ ) {
1201
+ const packageData = package;
1202
+ let { componentConfig } = packageData;
1203
+ if (!componentConfig) {
1204
+ componentConfig = {};
1205
+ }
1206
+ const isBetaVersion = packageData.version.includes('-beta');
1207
+ const _baseUrl =
1208
+ (baseUrl && (isBetaVersion ? baseUrl.daily : baseUrl.prod)) ||
1209
+ `${UNPKG_BASE_URL_MAP[engineScope]}/${packageData.name}@${packageData.version}`;
1210
+ componentConfig.materialSchema = `${_baseUrl}/${buildTarget}/${lowcodeDir}/assets-${
1211
+ isBetaVersion ? 'daily' : 'prod'
1212
+ }.json`;
1213
+ packageData.componentConfig = componentConfig;
1214
+ packageData.lcMeta = {
1215
+ ...packageData.lcMeta,
1216
+ type: 'component',
1217
+ };
1218
+ if (!package.dependencies['@babel/runtime']) {
1219
+ package.dependencies['@babel/runtime'] = '^7.0.0';
1220
+ }
1221
+ const processMainFieldForExports = (entry) => {
1222
+ if (!entry) return entry;
1223
+ return `${entry.startsWith('./') ? '' : './'}${entry}${entry.endsWith('.js') ? '' : '.js'}`
1224
+ }
1225
+ packageData.exports['.'] = {
1226
+ import: processMainFieldForExports(packageData.module) || './es/index.js',
1227
+ require: processMainFieldForExports(packageData.main) || './lib/index.js',
1228
+ }
1229
+ fse.outputFileSync(path.resolve(rootDir, 'package.json'), JSON.stringify(packageData, null, 2));
1230
+ }
1231
+
1232
+ async function bundleComponentMeta(webPackConfig, options, pluginOptions, execCompile) {
1233
+ const { registerTask, getAllTask, onGetWebpackConfig, context, onHook } = options;
1234
+ const { rootDir, pkg: package } = context;
1235
+ let { components, engineScope = '@ali', } = pluginOptions || {};
1236
+ const {
1237
+ devAlias,
1238
+ externals = {},
1239
+ buildTarget = 'build',
1240
+ lowcodeDir = 'lowcode',
1241
+ } = pluginOptions || {};
1242
+ if (components && !Array.isArray(components)) {
1243
+ console.error('[@alifd/build-plugin-lowcode] components must be Array<ComponentName: string>');
1244
+ components = null;
1245
+ }
1246
+
1247
+ const metaDevSubfix = devAlias ? `.${devAlias}` : '';
1248
+ const metaFilename = `meta${metaDevSubfix}`;
1249
+ const usedDevComponents = getUsedComponentMetas(rootDir, `meta${metaDevSubfix}`, components);
1250
+
1251
+ const componentsMetaPath = usedDevComponents.map((component) => {
1252
+ const componentMetaExportName = `${component}Meta`;
1253
+ const componentNameFolder = camel2KebabComponentName(component);
1254
+ const componentJsPath = `${lowcodeDir}/${componentNameFolder}/${metaFilename}`;
1255
+ const metaJsPath = path.resolve(rootDir, componentJsPath);
1256
+ const componentMetaName = `${component}Meta`;
1257
+ const componentImportStr = `import ${componentMetaName} from '${metaJsPath}';`;
1258
+ const componentMetaPath = generateEntry({
1259
+ template: 'component-meta.js',
1260
+ filename: `${componentJsPath}.js`,
1261
+ rootDir,
1262
+ params: {
1263
+ componentProps: COMPONENT_PROPS,
1264
+ componentImportStr,
1265
+ component: componentMetaName,
1266
+ execCompile,
1267
+ componentMetaExportName,
1268
+ version: package.version,
1269
+ packageName: package.name,
1270
+ },
1271
+ });
1272
+ return componentMetaPath;
1273
+ });
1274
+
1275
+ usedDevComponents.forEach((component, idx) => {
1276
+ (function (comp, index) {
1277
+ const componentNameFolder = camel2KebabComponentName(comp);
1278
+ const taskName = `lowcode-${componentNameFolder}-meta`;
1279
+ if (!execCompile || getAllTask().includes(taskName)) return componentsMetaPath;
1280
+ registerTask(taskName, getWebpackConfig('production'));
1281
+ onGetWebpackConfig(taskName, (config) => {
1282
+ const componentMetaExportName = `${comp}Meta`;
1283
+ const componentJsPath = `${lowcodeDir}/${componentNameFolder}/${metaFilename}`;
1284
+ config.merge({
1285
+ entry: {
1286
+ [componentJsPath]: componentsMetaPath[index],
1287
+ },
1288
+ });
1289
+ config.output.library(componentMetaExportName).libraryTarget('umd');
1290
+ config.output.path(path.resolve(rootDir, `${buildTarget}/${lowcodeDir}`));
1291
+ config.externals({ ...COMMON_EXTERNALS_MAP[engineScope], ...externals });
1292
+ useStyleLoader(config);
1293
+ });
1294
+ })(component, idx);
1295
+ });
1296
+
1297
+ onHook('after.build.compile', () => {
1298
+ usedDevComponents.forEach((comp) => {
1299
+ const componentNameFolder = camel2KebabComponentName(comp);
1300
+ const componentJsPath = `${lowcodeDir}/${componentNameFolder}/${metaFilename}`;
1301
+ const originPath = path.resolve(
1302
+ rootDir,
1303
+ `${buildTarget}/${lowcodeDir}/${componentJsPath}.js`,
1304
+ );
1305
+
1306
+ // 把 meta.js 里面的 window 替换成 this
1307
+ const jsContent = fse.readFileSync(originPath, 'utf-8');
1308
+ const jsContentTarget = jsContent.replace('window', 'this');
1309
+ fse.outputFileSync(originPath, jsContentTarget);
1310
+
1311
+ try {
1312
+ const targetPath = path.resolve(
1313
+ rootDir,
1314
+ `${buildTarget}/${lowcodeDir}/${componentJsPath}.json`,
1315
+ );
1316
+ fse.outputFileSync(targetPath, JSON.stringify(require(originPath), null, 2));
1317
+ } catch (e) {}
1318
+ });
1319
+ });
1320
+
1321
+ return componentsMetaPath;
1322
+ }