@shijiu/jsview 2.2.201 → 2.2.426-test.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 (33) hide show
  1. package/dom/bin/DroidSansFallback.ttf +0 -0
  2. package/dom/bin/NotoColorEmoji.ttf +0 -0
  3. package/dom/bin/jsview-dom-browser-engine-core.min.js +2 -0
  4. package/dom/bin/jsview-dom-browser-engine-modules.min.js +2 -0
  5. package/dom/bin/jsview-dom-browser-forge.1385.f80e.wasm +0 -0
  6. package/dom/bin/jsview-dom-browser-forge.min.js +1 -0
  7. package/dom/bin/jsview-dom-browser-forge.worker.min.js +1 -0
  8. package/dom/bin/jsview-dom-browser.min.js +1 -1
  9. package/dom/bin/jsview-dom-native.min.js +1 -1
  10. package/dom/bin/jsview-engine-js-browser.min.js +1 -22
  11. package/dom/bin/jsview-engine-js-native.min.js +2 -0
  12. package/dom/bin/jsview-forge-define.min.js +1 -1
  13. package/dom/index.mjs +38 -14
  14. package/dom/target_core_revision.mjs +10 -5
  15. package/loader/jsv-core-api/jsview-core-api-glue.js +74 -0
  16. package/loader/jsv-core-api/wasm/backgroundtask.js +66 -0
  17. package/loader/jsv-core-api/wasm/core-api.js +206 -0
  18. package/loader/jsview-config.js +22 -0
  19. package/loader/jsview-loader.js +74 -85
  20. package/loader/jsview-main.mjs +8 -14
  21. package/loader/jsview.config.default.js +2 -2
  22. package/package.json +1 -1
  23. package/patches/node_modules/vite/dist/node/jsview-vite-extension.js +67 -6
  24. package/shijiu-jsview-0.0.0.tgz +0 -0
  25. package/tools/https-server-config/cert.pem +61 -0
  26. package/tools/https-server-config/key.pem +27 -0
  27. package/tools/https-server-config/serve.config.json +16 -0
  28. package/tools/jsview-common.mjs +87 -3
  29. package/tools/jsview-post-build.mjs +248 -70
  30. package/tools/jsview-post-install.mjs +7 -4
  31. package/tools/jsview-retrieve-sourcemap.mjs +64 -49
  32. package/tools/jsview-run-tool.mjs +53 -3
  33. package/tools/jsview-vue-devtools.mjs +2 -0
@@ -179,6 +179,7 @@ function parseArguments(requiredUsages = {},
179
179
  /**************************************************
180
180
  * jsview-test-project
181
181
  * ├── dist
182
+ * │   ├── assets
182
183
  * │   ├── debug
183
184
  * │   │   └── map
184
185
  * │   └── js
@@ -209,6 +210,7 @@ function getOptions(framework)
209
210
  options.modulesDir = path.resolve(options.projectDir, 'node_modules');
210
211
  options.jsviewDir = path.resolve(options.modulesDir, '@shijiu', 'jsview');
211
212
  options.jsviewDomDir = path.resolve(options.jsviewDir, 'dom');
213
+ options.jsviewDomBinDir = path.resolve(options.jsviewDomDir, 'bin');
212
214
  options.jsviewPatchesDir = path.resolve(options.jsviewDir, 'patches');
213
215
  options.jsviewPatchModulesDir = path.resolve(options.jsviewPatchesDir, 'node_modules');
214
216
  options.jsviewToolsDir = path.resolve(options.jsviewDir, 'tools');
@@ -225,6 +227,7 @@ function getOptions(framework)
225
227
  options.appJsviewConfigFile = path.resolve(options.appConfigDir, 'jsview.config.mjs');
226
228
  options.appPrivKeyFile = path.resolve(options.appConfigDir, 'app_sign_private_key.crt');
227
229
  options.appPubKeyFile = path.resolve(options.appConfigDir, 'app_sign_public_key.pem');
230
+ options.appConfigSVKeysDir = path.resolve(options.appConfigDir, 'signVerifyKeys');
228
231
 
229
232
  options.distDir = path.resolve(options.projectDir, 'dist');
230
233
  if (framework == 'vue') {
@@ -240,6 +243,7 @@ function getOptions(framework)
240
243
  options.distJsvListFile = path.resolve(options.distDir, 'jsv-list.json');
241
244
  options.distJsvInfoFile = path.resolve(options.distDir, 'jsv-info.json');
242
245
  options.distJsIndexFile = path.resolve(options.distDir, 'index.html');
246
+ options.distAssetsDir = path.resolve(options.distDir, 'assets');
243
247
  options.distJsDir = path.resolve(options.distDir, 'js');
244
248
  options.distDebugDir = path.resolve(options.distDir, 'debug');
245
249
  options.distDebugMapDir = path.resolve(options.distDebugDir, 'map');
@@ -325,6 +329,18 @@ function symlinkSync(workDir, targetPath, toPath)
325
329
  fs.symlinkSync(relativePath, toPath, 'junction');
326
330
  }
327
331
 
332
+ function isCommandAvailable(command) {
333
+ const isWindows = process.platform === 'win32';
334
+ const cmd = isWindows ? 'where' : 'which';
335
+
336
+ const result = childProcess.spawnSync(cmd, [command], {
337
+ stdio: 'ignore',
338
+ shell: true
339
+ });
340
+
341
+ return result.status === 0;
342
+ }
343
+
328
344
  function isSymlinkSync(filePath)
329
345
  {
330
346
  const stats = fs.lstatSync(filePath);
@@ -362,6 +378,54 @@ function execCommandAsync(cmdline)
362
378
  });
363
379
  }
364
380
 
381
+ function execCommandPromise(cmdline)
382
+ {
383
+ let log = '';
384
+
385
+ const promise = new Promise((resolve, reject) => {
386
+ const child = childProcess.spawn(cmdline, null, { shell: true });
387
+ child.stdout.on('data', (data) => {
388
+ log += data;
389
+ });
390
+ child.stderr.on('data', (data) => {
391
+ log += data;
392
+ });
393
+ child.on('close', (code) => {
394
+ if (code !== 0) {
395
+ reject(log);
396
+ } else {
397
+ resolve(log);
398
+ }
399
+ });
400
+ });
401
+
402
+ return promise;
403
+ }
404
+
405
+ function execCommandWithLiveLog(cmdline)
406
+ {
407
+ Logger.Info('Run [' + cmdline + ']... ');
408
+ const promise = new Promise((resolve, reject) => {
409
+ const child = childProcess.spawn(cmdline, null, { shell: true });
410
+ child.stdout.on('data', (data) => {
411
+ process.stdout.write(data);
412
+ });
413
+ child.stderr.on('data', (data) => {
414
+ process.stderr.write(data);
415
+ });
416
+ child.on('close', (code) => {
417
+ if (code !== 0) {
418
+ process.exit(code);
419
+ }
420
+
421
+ resolve();
422
+ });
423
+ });
424
+
425
+ return promise;
426
+ }
427
+
428
+
365
429
  function checkNodeVersion(minMajorVersion = 16)
366
430
  {
367
431
  const versions = process.version.replace('v', '').split('.');
@@ -463,7 +527,7 @@ function downloadFileAsync(url, localPath, workDir)
463
527
 
464
528
  function unzipFile(zipFilePath, toDir, workDir)
465
529
  {
466
- var relativePath = path.relative(workDir, toDir);
530
+ let relativePath = path.relative(workDir, toDir);
467
531
  if(!relativePath) {
468
532
  relativePath = './'
469
533
  }
@@ -473,6 +537,21 @@ function unzipFile(zipFilePath, toDir, workDir)
473
537
  execCommand(cmdline);
474
538
  }
475
539
 
540
+ function getExportPrefix()
541
+ {
542
+ let exportPrefix = 'export';
543
+ if(process.platform == 'win32') {
544
+ exportPrefix = 'set'
545
+ }
546
+
547
+ return exportPrefix;
548
+ }
549
+
550
+ function getJsViewBurdenDefaultBaseUrl()
551
+ {
552
+ return 'https://cdn.release.qcast.cn/JsViewTest/wasm/resources';
553
+ }
554
+
476
555
  function getNpmRegistry()
477
556
  {
478
557
  return 'https://nexus.cluster.qcast.cn/repository/npm-public';
@@ -484,8 +563,8 @@ function getNetworkIpv4Addresses() {
484
563
  for (const devName in interfaces) {
485
564
  const iface = interfaces[devName];
486
565
 
487
- for (var idx = 0; idx < iface.length; idx++) {
488
- var alias = iface[idx];
566
+ for (let idx = 0; idx < iface.length; idx++) {
567
+ let alias = iface[idx];
489
568
  if (alias.family === 'IPv4' && alias.address !== '127.0.0.1' && !alias.internal) {
490
569
  addresses.push(alias.address);
491
570
  }
@@ -503,9 +582,14 @@ export {
503
582
  downloadFileAsync,
504
583
  execCommand,
505
584
  execCommandAsync,
585
+ execCommandPromise,
586
+ execCommandWithLiveLog,
587
+ getExportPrefix,
588
+ getJsViewBurdenDefaultBaseUrl,
506
589
  getNetworkIpv4Addresses,
507
590
  getNpmRegistry,
508
591
  getOptions,
592
+ isCommandAvailable,
509
593
  isSymlinkSync,
510
594
  loadPackageObject,
511
595
  makeZip,
@@ -7,11 +7,13 @@ import path from 'node:path';
7
7
  import url from 'node:url'
8
8
  import {
9
9
  checkNodeVersion,
10
+ getJsViewBurdenDefaultBaseUrl,
10
11
  getOptions,
11
12
  loadPackageObject,
12
13
  parseArguments,
13
14
  Logger,
14
15
  } from './jsview-common.mjs';
16
+ import { assert } from 'node:console';
15
17
 
16
18
  // npm run build 时检查jsview-dom是否处于Debug模式。
17
19
  async function checkDomDebugDisabled(options) {
@@ -24,15 +26,52 @@ async function checkDomDebugDisabled(options) {
24
26
  }
25
27
  }
26
28
 
27
- // main.js处理AppData信息
28
- async function prepareMainAppData(options, fileMd5)
29
+ function getEntryFilePath(options)
30
+ {
31
+ let jsEntryFilePath;
32
+ const jsFileNames = fs.readdirSync(options.distJsDir);
33
+ for(const fileName of jsFileNames) {
34
+ if (fileName.startsWith('main.jsv') && fileName.endsWith('.js')) {
35
+ jsEntryFilePath = path.resolve(options.distJsDir, fileName);
36
+ break;
37
+ }
38
+ };
39
+
40
+ return jsEntryFilePath;
41
+ }
42
+
43
+ function getEncryptBase64(appPrivKey, appPubKey, plainText)
44
+ {
45
+ // 编码md5值
46
+ const encryptBase64 = crypto.privateEncrypt({
47
+ key: appPrivKey,
48
+ padding: crypto.constants.RSA_PKCS1_PADDING
49
+ },
50
+ Buffer.from(plainText)
51
+ ).toString('base64');
52
+
53
+ // 校验publicKey是否是配对的
54
+ const decryptText = crypto.publicDecrypt({
55
+ key: appPubKey,
56
+ padding: crypto.constants.RSA_PKCS1_PADDING
57
+ },
58
+ Buffer.from(encryptBase64, 'base64')
59
+ ).toString();
60
+ if (decryptText !== plainText) {
61
+ Logger.ErrorAndExit('public key dismath to private key!');
62
+ }
63
+
64
+ return encryptBase64;
65
+ }
66
+
67
+ function updateOptions(options)
29
68
  {
30
69
  // 加载私钥文件
31
70
  if (!fs.existsSync(options.appPrivKeyFile)) {
32
71
  Logger.ErrorAndExit('Failed to open private key file from ' + options.appPrivKeyFile);
33
72
  }
34
- const privateKeyText = fs.readFileSync(options.appPrivKeyFile);
35
- if (privateKeyText.indexOf('-----BEGIN PRIVATE KEY-----') < 0) {
73
+ const privKey = fs.readFileSync(options.appPrivKeyFile);
74
+ if (privKey.indexOf('-----BEGIN PRIVATE KEY-----') < 0) {
36
75
  Logger.ErrorAndExit('Get private from src/appConfig/app_sign_private_key.crt failed.');
37
76
  }
38
77
 
@@ -40,40 +79,62 @@ async function prepareMainAppData(options, fileMd5)
40
79
  if (!fs.existsSync(options.appPubKeyFile)) {
41
80
  Logger.ErrorAndExit('Failed to open public key file from ' + options.appPubKeyFile);
42
81
  }
43
- const publicKeyText = fs.readFileSync(options.appPubKeyFile);
44
- if (publicKeyText.indexOf('-----BEGIN PUBLIC KEY-----') < 0) {
82
+ const pubKey = fs.readFileSync(options.appPubKeyFile);
83
+ if (pubKey.indexOf('-----BEGIN PUBLIC KEY-----') < 0) {
45
84
  Logger.ErrorAndExit('Get private from src/appConfig/app_sign_public_key.pem failed.');
46
85
  }
47
- // 公钥格式转化pem -> der,因为java中的解码处理只识别der格式
48
- let publicKeyDerText = publicKeyText.toString();
49
- if (publicKeyDerText.indexOf('\r') >= 0) {
50
- publicKeyDerText = publicKeyDerText.replace(/\r/g, '');
51
- }
52
- if (publicKeyDerText.indexOf('\n') >= 0) {
53
- publicKeyDerText = publicKeyDerText.replace(/\n/g, '');
54
- }
55
- publicKeyDerText = publicKeyDerText.replace('-----BEGIN PUBLIC KEY-----', '');
56
- publicKeyDerText = publicKeyDerText.replace('-----END PUBLIC KEY-----', '');
57
-
58
- // 编码md5值
59
- const encryptCodeBase64 = crypto.privateEncrypt({
60
- key: privateKeyText,
61
- padding: crypto.constants.RSA_PKCS1_PADDING
62
- },
63
- Buffer.from(fileMd5)
64
- ).toString('base64');
65
86
 
66
87
  // 校验publicKey是否是配对的
67
- const decryptCode = crypto.publicDecrypt({
68
- key: publicKeyText,
69
- padding: crypto.constants.RSA_PKCS1_PADDING
70
- },
71
- Buffer.from(encryptCodeBase64, 'base64')
72
- ).toString();
73
- if (decryptCode !== fileMd5) {
74
- Logger.ErrorAndExit('public key dismath to private key!');
88
+ const encryptBase64 = getEncryptBase64(privKey, pubKey, 'crypto-test');
89
+ assert(encryptBase64)
90
+
91
+ const appEntryFilePath = getEntryFilePath(options);
92
+ const appEntryContent = fs.readFileSync(appEntryFilePath, 'utf8');
93
+ const appEntryMd5 = crypto.createHash('md5').update(appEntryContent).digest('hex');
94
+
95
+ options.appPrivKey = privKey;
96
+ options.appPubKey = pubKey;
97
+ options.appEntryMd5 = appEntryMd5;
98
+ }
99
+
100
+ function getOtherSignVerifyKeys(options)
101
+ {
102
+ const signVerifyKeys = {};
103
+ const signVerifyKeyFiles = fs.readdirSync(options.appConfigSVKeysDir);
104
+ for (const keyName of signVerifyKeyFiles) {
105
+ const filePath = path.resolve(options.appConfigSVKeysDir, keyName);
106
+ if (keyName == '.gitkeep') {
107
+ continue;
108
+ } else if (!keyName.endsWith('.pem')) {
109
+ Logger.Warn(`Ignore to append invalid signature verification key: ${filePath}`);
110
+ continue;
111
+ }
112
+
113
+ const keyValue = fs.readFileSync(filePath, 'utf8');
114
+ signVerifyKeys[keyName] = keyValue;
75
115
  }
76
116
 
117
+ return signVerifyKeys;
118
+ }
119
+
120
+ function publicPemToDer(pubKeyPem)
121
+ {
122
+ let pubKeyDer = pubKeyPem.toString();
123
+ if (pubKeyDer.indexOf('\r') >= 0) {
124
+ pubKeyDer = pubKeyDer.replace(/\r/g, '');
125
+ }
126
+ if (pubKeyDer.indexOf('\n') >= 0) {
127
+ pubKeyDer = pubKeyDer.replace(/\n/g, '');
128
+ }
129
+ pubKeyDer = pubKeyDer.replace('-----BEGIN PUBLIC KEY-----', '');
130
+ pubKeyDer = pubKeyDer.replace('-----END PUBLIC KEY-----', '');
131
+
132
+ return pubKeyDer;
133
+ }
134
+
135
+ // main.js处理AppData信息
136
+ async function prepareMainAppData(options)
137
+ {
77
138
  // 获取AppData信息
78
139
  const appConfigFilePath = path.resolve(options.appConfigDir, 'app.config.mjs');
79
140
  if (!fs.existsSync(appConfigFilePath)) {
@@ -82,29 +143,47 @@ async function prepareMainAppData(options, fileMd5)
82
143
  const appConfigFileUrl = url.pathToFileURL(appConfigFilePath);
83
144
  const { default: appConfig } = await import(appConfigFileUrl);
84
145
 
85
- // 获取 chunk.jsv的map
86
- const chunkHash = {};
146
+ // 获取PublickKey数组
147
+ const publicKeys = [publicPemToDer(options.appPubKey)];
148
+ // TODO: 验签PubKey的安全性尚需考虑
149
+ // const signVerifyKeys = getOtherSignVerifyKeys(options);
150
+ // for(const [keyName, keyValue] of Object.entries(signVerifyKeys)) {
151
+ // Logger.Info(` -> Append ${keyName} to jsvapp.`)
152
+ // publicKeys.push(publicPemToDer(keyValue));
153
+ // }
154
+
155
+ // 获取密文
156
+ const encryptBase64 = getEncryptBase64(options.appPrivKey, options.appPubKey, options.appEntryMd5);
157
+
158
+ // 获取 预加载的文件名
159
+ const filterKeys = [
160
+ 'domNativePath',
161
+ 'NativePlatformDomBridge',
162
+ 'ForgeExtension',
163
+ 'CodeRevision',
164
+ '__vue_app__',
165
+ 'mount("#app")',
166
+ ];
167
+ const preloadChunks = [];
87
168
  const jsFileNames = fs.readdirSync(options.distJsDir);
88
169
  for(const fileName of jsFileNames) {
89
170
  if (!fileName.startsWith('chunk.jsv') || !fileName.endsWith('.js')) {
90
171
  continue;
91
172
  }
92
173
 
93
- const hash = fileName.replace(/.*chunk\.jsv.([a-fA-F0-9].*).js/, '$1');
94
-
95
174
  const filePath = path.resolve(options.distJsDir, fileName);
96
175
  const sourceContent = fs.readFileSync(filePath, 'utf8');
97
- const md5 = sourceContent.replace(/\n/g, '').replace(/.*\/\*jsvmd5:([a-fA-F0-9]{8})[a-fA-F0-9]*\*\/.*/, '$1');
176
+ if(filterKeys.some(it => sourceContent.includes(it)) == false) {
177
+ continue;
178
+ }
98
179
 
99
- chunkHash[hash] = md5;
180
+ preloadChunks.push(fileName);
100
181
  }
101
182
 
102
183
  // 组装AppData
103
- appConfig.PublicKeys = [publicKeyDerText]; // 使用签名数组,支持后续追加签名
104
- appConfig.EncryptCodes = [encryptCodeBase64]; // 同样使用数组,支持后续追加
105
- appConfig.ChunkHash = chunkHash;
106
-
107
-
184
+ appConfig.PublicKeys = publicKeys; // 使用签名数组,支持后续追加签名
185
+ appConfig.EncryptCodes = [encryptBase64]; // 同样使用数组,支持后续追加
186
+ appConfig.PreloadChunks = preloadChunks;
108
187
 
109
188
  return JSON.stringify(appConfig);
110
189
  }
@@ -146,24 +225,94 @@ async function signApp(options)
146
225
 
147
226
  var sourceContent = fs.readFileSync(filePath, 'utf8');
148
227
 
149
- sourceContent += '\n'; // 把\n归入算进md5计算中
228
+ const jsvMd5 = crypto.createHash('md5').update(sourceContent).digest('hex');
229
+
230
+ // 获取签名并验签
231
+ const cryptoSigner = crypto.createSign('sha256').update(jsvMd5).end();
232
+ const cryptoVerifier = crypto.createVerify('sha256').update(jsvMd5).end();
233
+ const jsvSign = cryptoSigner.sign(options.appPrivKey, 'hex');
234
+ const verified = cryptoVerifier.verify(options.appPubKey, jsvSign, 'hex');
235
+ if(!verified) {
236
+ Logger.ErrorAndExit('Failed to create signature verification.');
237
+ }
150
238
 
151
- const jsvAppMd5 = crypto.createHash('md5').update(sourceContent).digest('hex');
152
239
  let appDataInfo = '';
153
240
  if (fileName.indexOf('main.jsv.') >= 0) {
154
241
  // 对main文件加入应用头信息
155
- appDataInfo = await prepareMainAppData(options, jsvAppMd5);
242
+ appDataInfo = await prepareMainAppData(options, jsvMd5);
156
243
 
157
244
  // 格式化jsvapp信息 /*jsvapp:内容长度:{内容}*/
158
245
  // 使用TextEncoder解决中文长度问题
159
246
  const infoLen = new TextEncoder().encode(appDataInfo).length;
160
247
  appDataInfo = '/*jsvapp:' + infoLen + ':' + appDataInfo + ':' + infoLen + ':jsvapp*/';
161
248
  }
162
- sourceContent = sourceContent + appDataInfo + '/*jsvmd5:' + jsvAppMd5 + '*/';
249
+ sourceContent = sourceContent + appDataInfo;
250
+
251
+ sourceContent = sourceContent + '/*jsvsign:' + jsvSign + '*/';
252
+
163
253
  fs.writeFileSync(filePath, sourceContent, 'utf8');
164
254
  }
165
255
  }
166
256
 
257
+ function redirectBurdenResource(options)
258
+ {
259
+ if(process.env['JSVIEW_BURDEN_LOCAL']) {
260
+ return;
261
+ }
262
+
263
+ let burdenBaseUrl = process.env['JSVIEW_BURDEN_BASEURL'];
264
+ if(!burdenBaseUrl) {
265
+ burdenBaseUrl = getJsViewBurdenDefaultBaseUrl();
266
+ }
267
+ if(!burdenBaseUrl.endsWith('/')) {
268
+ burdenBaseUrl += '/';
269
+ }
270
+
271
+ const burdenFilePathList = [];
272
+
273
+ const assetFileNames = fs.readdirSync(options.distAssetsDir);
274
+ for(const fileName of assetFileNames) {
275
+ if (!fileName.endsWith('.ttf')) {
276
+ continue;
277
+ }
278
+ burdenFilePathList.push(path.resolve(options.distAssetsDir, fileName));
279
+ }
280
+ const jsFileNames = fs.readdirSync(options.distJsDir);
281
+ for(const fileName of jsFileNames) {
282
+ if (!fileName.endsWith('.wasm')) {
283
+ continue;
284
+ }
285
+ burdenFilePathList.push(path.resolve(options.distJsDir, fileName));
286
+ }
287
+ for(const filePath of burdenFilePathList) {
288
+ fs.rmSync(filePath);
289
+ Logger.Info('Config burden file: ' + path.relative(options.projectDir, filePath));
290
+ }
291
+
292
+ for(const fileName of jsFileNames) {
293
+ if (!fileName.endsWith('.js') && !fileName.endsWith('.js.map')) {
294
+ continue;
295
+ }
296
+
297
+ const filePath = path.resolve(options.distJsDir, fileName);
298
+ let sourceContent = fs.readFileSync(filePath, 'utf8');
299
+
300
+ for(const burdenFilePath of burdenFilePathList) {
301
+ const relativeBurdenFilePath = path.relative(options.distJsDir, burdenFilePath);
302
+ if(!sourceContent.includes(relativeBurdenFilePath)) {
303
+ continue;
304
+ }
305
+
306
+ const burdenFileUrl = burdenBaseUrl + path.basename(burdenFilePath);
307
+
308
+ sourceContent = sourceContent.replaceAll(relativeBurdenFilePath, burdenFileUrl);
309
+ Logger.Info('Burdenting ' + path.relative(options.projectDir, filePath) + ' for [' + relativeBurdenFilePath + ']');
310
+ }
311
+
312
+ fs.writeFileSync(filePath, sourceContent, 'utf8');
313
+ };
314
+ }
315
+
167
316
  function redirectSourceMappingURL(options)
168
317
  {
169
318
  const jsFileNames = fs.readdirSync(options.distJsDir);
@@ -182,6 +331,9 @@ function redirectSourceMappingURL(options)
182
331
  '# sourceMappingURL=', '# sourceMappingURL=http://localhost:57245/map/');
183
332
  sourceContent = sourceContent.substring(0, mapUrlOffset) + mapUrlStr;
184
333
 
334
+ //添加一个回车,后续把\n归入算进md5计算中
335
+ sourceContent += '\n';
336
+
185
337
  fs.writeFileSync(filePath, sourceContent, 'utf8');
186
338
  };
187
339
  }
@@ -192,41 +344,57 @@ function makeMainJsvMjs(options, framework)
192
344
  return;
193
345
  }
194
346
 
195
- let jsEntryFilePath;
196
- const jsFileNames = fs.readdirSync(options.distJsDir);
197
- for(const fileName of jsFileNames) {
198
- if (fileName.startsWith('main.jsv') && fileName.endsWith('.js')) {
199
- jsEntryFilePath = path.resolve(options.distJsDir, fileName);
200
- break;
201
- }
202
- };
203
-
204
- const sourceContent = fs.readFileSync(jsEntryFilePath, 'utf8');
205
- const md5 = sourceContent.replace(/\n/g, '').replace(/.*\/\*jsvmd5:([a-fA-F0-9]{8})[a-fA-F0-9]*\*\/.*/, '$1');
206
- const newEntryFileName = `main.jsv.${md5}.js`;
347
+ // 更新entry hash
348
+ const jsEntryFilePath = getEntryFilePath(options);
349
+ const newEntryFileName = `main.jsv.${options.appEntryMd5.slice(0, 8)}.js`;
207
350
  const newEntryFilePath = path.resolve(path.dirname(jsEntryFilePath), newEntryFileName);
208
351
  Logger.Info(' -> ' + path.relative(options.projectDir, newEntryFilePath));
209
352
  fs.renameSync(jsEntryFilePath, newEntryFilePath);
210
353
 
354
+ // 更新index.html hash
211
355
  var indexContent = fs.readFileSync(options.distJsIndexFile, 'utf8');
212
356
  indexContent = indexContent.replace(path.basename(jsEntryFilePath), newEntryFileName);
213
357
  Logger.Info(' -> ' + path.relative(options.projectDir, options.distJsIndexFile));
214
358
  fs.writeFileSync(options.distJsIndexFile, indexContent, 'utf8');
215
359
 
360
+ // 创建JsView 加载用的 mjs entry
216
361
  const moduleEntryFilePath = newEntryFilePath.replace(/\.js$/, '.mjs');
217
362
  fs.copyFileSync(newEntryFilePath, moduleEntryFilePath);
363
+
364
+ // 创建JsView Debug用的 mjs entry
365
+ const debugEntryFilePath = path.resolve(options.distJsDir, 'main.jsv.mjs');
366
+ Logger.Info(' -> ' + path.relative(options.projectDir, debugEntryFilePath));
367
+ fs.copyFileSync(newEntryFilePath, debugEntryFilePath);
368
+ }
369
+
370
+ function getWasmMapChunkName(options, wasmMapName)
371
+ {
372
+ let chunkName = wasmMapName;
373
+
374
+ const regex = new RegExp(`sourceMappingURL.${wasmMapName}`);
375
+ const jsFileNames = fs.readdirSync(options.distJsDir);
376
+ for(const fileName of jsFileNames) {
377
+ if (!fileName.endsWith('.wasm')) {
378
+ continue;
379
+ }
380
+
381
+ const filePath = path.resolve(options.distJsDir, fileName);
382
+ const content = fs.readFileSync(filePath, 'utf-8');
383
+ if(regex.test(content)) {
384
+ chunkName = fileName + '.map';
385
+ break;
386
+ }
387
+ };
388
+
389
+ return chunkName;
218
390
  }
219
391
 
220
392
  function makeDebugMap(options, framework)
221
393
  {
222
394
  fs.mkdirSync(options.distDebugMapDir, { recursive: true });
223
395
 
224
- let jsEntryFilePath;
225
396
  const jsFileNames = fs.readdirSync(options.distJsDir);
226
397
  for(const fileName of jsFileNames) {
227
- if (fileName.startsWith('main.jsv') && fileName.endsWith('.mjs')) {
228
- jsEntryFilePath = path.resolve(options.distJsDir, fileName);
229
- }
230
398
  if (!fileName.endsWith('.map')) {
231
399
  continue;
232
400
  }
@@ -237,15 +405,18 @@ function makeDebugMap(options, framework)
237
405
  fs.renameSync(from, to);
238
406
  };
239
407
 
240
- if (jsEntryFilePath) {
241
- let extName = path.extname(jsEntryFilePath);
242
- if (framework == 'vue') {
243
- extName = '.mjs'
408
+ const wasmFileNames = fs.readdirSync(options.jsviewDomBinDir);
409
+ for(const fileName of wasmFileNames) {
410
+ if (!fileName.endsWith('.wasm.map')) {
411
+ continue;
244
412
  }
245
- const to = path.resolve(options.distJsDir, 'main.jsv' + extName);
413
+
414
+ const chunkName = getWasmMapChunkName(options, fileName);
415
+ const from = path.resolve(options.jsviewDomBinDir, fileName);
416
+ const to = path.resolve(options.distDebugMapDir, chunkName);
246
417
  Logger.Info(' -> ' + path.relative(options.projectDir, to));
247
- fs.copyFileSync(jsEntryFilePath, to);
248
- }
418
+ fs.copyFileSync(from, to);
419
+ };
249
420
 
250
421
  const jsmapServeName = 'jsview-jsmap-serve.mjs';
251
422
  const jsmapServePath = path.resolve(options.jsviewToolsDir, jsmapServeName);
@@ -331,10 +502,17 @@ async function main(argv)
331
502
  await checkDomDebugDisabled(options);
332
503
 
333
504
  Logger.Info();
505
+ Logger.Info('Redirecting JsView burden resource...');
506
+ redirectBurdenResource(options)
507
+ Logger.Info('Redirected JsView burden resource...');
508
+
334
509
  Logger.Info('Redirecting JsView source map...');
335
510
  redirectSourceMappingURL(options)
336
511
  Logger.Info('Redirected JsView source map...');
337
512
 
513
+ // EntryMd5 要放在sourcemap更新之后
514
+ updateOptions(options);
515
+
338
516
  Logger.Info('Checking JsView app config...');
339
517
  await checkAppConfig(options);
340
518
  Logger.Info('Checked JsView app config...');
@@ -245,7 +245,7 @@ async function printRevision(options)
245
245
  Logger.Info('**************************************************');
246
246
  }
247
247
 
248
- function doPostInstall(framework, pkgNeedPatch, skipCheckVersion)
248
+ function doPostInstall(framework, pkgNeedPatch, skipCheckVersion, skipCheckNpmcmd)
249
249
  {
250
250
  const options = getOptions(framework);
251
251
  options.projectDir = process.cwd();
@@ -260,7 +260,9 @@ function doPostInstall(framework, pkgNeedPatch, skipCheckVersion)
260
260
  '@shijiu/jsview-react-extra-samples',
261
261
  ];
262
262
 
263
- checkNpmCommand();
263
+ if(!skipCheckNpmcmd) {
264
+ checkNpmCommand();
265
+ }
264
266
 
265
267
  checkNpmLinkForDebug(options, linkablePkgNames);
266
268
 
@@ -304,14 +306,15 @@ function main(argv)
304
306
  Logger.ErrorAndExit('Failed to support framework: ' + framework);
305
307
  }
306
308
 
307
- doPostInstall(argv.framework, pkgNeedPatch, argv.skipCheckVersion);
309
+ doPostInstall(argv.framework, pkgNeedPatch, argv.skipCheckVersion, argv.skipCheckNpmcmd);
308
310
  }
309
311
 
310
312
  const requiredUsages = {
311
313
  '--framework': 'Select from [vue|react]',
312
314
  };
313
315
  const optionalUsages = {
314
- '--skip-check-version': 'Skip check patches version.'
316
+ '--skip-check-version': 'Skip check patches version.',
317
+ '--skip-check-npmcmd': 'Skip check npm command.'
315
318
  };
316
319
  const argv = parseArguments(requiredUsages, optionalUsages);
317
320
  main(argv);