@shijiu/jsview 2.3.0 → 2.3.728-alpha.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.
@@ -10,6 +10,7 @@ export default class WasmCoreApis {
10
10
  this.EngineJs = "embedded";
11
11
  this.UrlBuilder = URL;
12
12
  this.Platform = "pc-wasm"; // 平台信息,可选有 android/pc-wasm/harmony-webview
13
+ this.ProcessType = "wasm";
13
14
 
14
15
  this._ForgeHandle = null;
15
16
 
@@ -157,6 +158,14 @@ export default class WasmCoreApis {
157
158
  console.log("removeGlobalJsExceptionAck not implemented");
158
159
  }
159
160
 
161
+ addModuleFailedAck(callback) {
162
+ console.log("addModuleFailedAck not implemented");
163
+ }
164
+
165
+ removeModuleFailedAck(callback) {
166
+ console.log("removeModuleFailedAck not implemented");
167
+ }
168
+
160
169
  toggleViewVisible(toVisible) {
161
170
  console.log("toggleViewVisible not implemented");
162
171
  }
@@ -189,8 +198,22 @@ export default class WasmCoreApis {
189
198
  // wasm不支持调整 cookie domain
190
199
  }
191
200
 
201
+ refreshCookies() {
202
+ // wasm不支持调整 cookie domain
203
+ }
204
+
192
205
  setRenderGlobalConfig(json) {
193
- this._ForgeHandle?.SetGlobalConfig(json);
206
+ // 抓取forge_config中需要的配置, 保持未设时, 在forge_config中也不存在
207
+ const forge_config = {};
208
+ ['texCache', 'holderCache', 'simulDecodeNum', 'touchSlop', 'wheelRate'].forEach(key => { if (key in json) forge_config[key] = json[key]; });
209
+ this._ForgeHandle?.sRenderBridge.SetGlobalConfig(forge_config);
210
+
211
+ // 抓取dom_config中需要的配置, 保持未设时, 在dom_config中也不存在
212
+ const dom_config = {};
213
+ ['maxDomSync'].forEach(key => { if (key in json) dom_config[key] = json[key]; });
214
+ if (typeof dom_config.maxDomSync == 'number') {
215
+ window.JsvCode.Dom.SetLazyTaskOverLoadLevel(dom_config.maxDomSync);
216
+ }
194
217
  }
195
218
 
196
219
  setForgeJsHandle(forgeHandle) {
@@ -201,8 +224,79 @@ export default class WasmCoreApis {
201
224
  console.log("onMainTsDone...");
202
225
  }
203
226
 
227
+ /**
228
+ * 完全释放GLView, 以达到完全清理GL内存的目的,一般配合JsView的visibility的回调一齐使用
229
+ * 场景1: 可以通过此接口,规避在android 9.0上把其他进程的GL内存都算在本进程的内存统计上的问题
230
+ * 场景2: 完全释放绘制资源,以保证作为Launcher时,退到后时最小化内存
231
+ *
232
+ * @param delayedTimeMs int类型 延迟关闭View的时间,可以为0, 单位:秒
233
+ */
234
+ delayRemoveGLView(delayedTimeSec) {
235
+ console.log("delayRemoveGLView not implemented in wasm");
236
+ }
237
+
238
+ /**
239
+ * 恢复已经被关闭的GLView,一般在delayRemoveGLView后对GLView进行重新展示
240
+ * 此接口内部有状态自查,可以在任何状态调用,既使 delayRemoveGLView 没有触发
241
+ */
242
+ restoreGLView() {
243
+ console.log("restoreGLView not implemented in wasm");
244
+ }
245
+
246
+ // wasm专属api调试api, tag参数中以空格隔开每个tag
204
247
  enableConsoleTag(tag) {
205
248
  this.WasmExt.ForgeLogRef?.EnableTag(tag);
206
249
  this.WasmExt.JseLogRef?.EnableTag(tag);
207
250
  }
251
+
252
+ /**
253
+ * 用户无操作时降帧的功能
254
+ *
255
+ * @param enable boolean类型, 是否开启此功能
256
+ * @param idleFps int类型, 0-60, 开启时限制的帧率
257
+ * @param idleTimeMs int类型, 用户无操作多少时间后降帧(毫秒)
258
+ */
259
+ setIdleFps(enable, idleFps, idleTimeMs) {
260
+ console.log("setIdleFps not implemented in wasm");
261
+ }
262
+
263
+ /**
264
+ * 保持fps高帧率的开关,主要用于灵活控制用户无操作时降帧功能的小开关
265
+ *
266
+ * @param enable boolean类型, 是否保持,保持时关闭降帧功能,不保持时开启降帧功能
267
+ */
268
+ keepFpsHighPerf(enable) {
269
+ console.log("keepFpsHighPerf not implemented in wasm");
270
+ }
271
+
272
+ /**
273
+ * 设置图片缓存上限,默认为80M,每次进行回收时会自动回收到其3/4
274
+ * @params new_level int, 新水位
275
+ */
276
+ setTextureMaxWaterLevel(level) {
277
+ console.log("setTextureMaxWaterLevel not implemented in wasm");
278
+ }
279
+
280
+ base64ToLatinBytes(base64String) {
281
+ // 在wasm版本中,String会转成uint8Array, 和C++的jse::impl::JseStringImpl中的处理呼应
282
+ // 因为在wasm,native层无法直接按照Latin-1编码提取String
283
+ const bytes = atob(base64String);
284
+ const uint8Array = new Uint8Array(bytes.length);
285
+
286
+ for (let i = 0; i < bytes.length; i++) {
287
+ const code = bytes.charCodeAt(i);
288
+ // Latin-1 范围是 0x00-0xFF,超出范围的字符会被截断
289
+ uint8Array[i] = code & 0xFF;
290
+ }
291
+
292
+ return uint8Array;
293
+ }
294
+
295
+ AddSwappedOnceListener(callback) {
296
+ console.log("AddSwappedOnceListener not implemented in wasm");
297
+ }
298
+
299
+ RemoveSwappedOnceListener(callback) {
300
+ console.log("RemoveSwappedOnceListener not implemented in wasm");
301
+ }
208
302
  }
@@ -34,4 +34,9 @@ export default class WasmCoreApisExtension {
34
34
  this.ForgeLogRef = forge_log_ref;
35
35
  this.JseLogRef = jse_log_ref;
36
36
  }
37
+ }
38
+
39
+ // 补充setJsvAppConfig api,用于在wasm场景下设置app配置
40
+ if (!window.setJsvAppConfig) {
41
+ window.setJsvAppConfig = function(appConfig) { }
37
42
  }
@@ -20,7 +20,7 @@ class JsThreadBlockTester {
20
20
  if (gap > CYCLE_TIME + BLOCK_CHECK_TIME) {
21
21
  console.warn(JsThreadBlockTester.#TAG, `js thread blocked, preTime: ${preTimestamp}, curTime: ${JsThreadBlockTester.#timestamp}, curTime-preTime: ${gap}`);
22
22
  }
23
- JsThreadBlockTester.#timeoutHandler = setTimeout(JsThreadBlockTester.#checkTask, CYCLE_TIME);
23
+ JsThreadBlockTester.#timeoutHandler = window.JsvCoreApi.BackgroundTask.postDelay(JsThreadBlockTester.#checkTask, CYCLE_TIME);
24
24
  };
25
25
  static #onVisibleChange = (data) => {
26
26
  if (data.status == "hide") {
@@ -42,12 +42,12 @@ class JsThreadBlockTester {
42
42
  static #start() {
43
43
  console.log(JsThreadBlockTester.#TAG, "start");
44
44
  JsThreadBlockTester.#timestamp = Date.now();
45
- JsThreadBlockTester.#timeoutHandler = setTimeout(JsThreadBlockTester.#checkTask, CYCLE_TIME);
45
+ JsThreadBlockTester.#timeoutHandler = window.JsvCoreApi.BackgroundTask.postDelay(JsThreadBlockTester.#checkTask, CYCLE_TIME);
46
46
  }
47
47
 
48
48
  static #stop() {
49
49
  console.log(JsThreadBlockTester.#TAG, "stop");
50
- clearTimeout(JsThreadBlockTester.#timeoutHandler);
50
+ window.JsvCoreApi.BackgroundTask.clear(JsThreadBlockTester.#timeoutHandler);
51
51
  JsThreadBlockTester.#timeoutHandler = -1;
52
52
  }
53
53
  }
@@ -138,6 +138,13 @@ export default class JsViewLoader {
138
138
  // (可选配置)按键接受的扩展,例如将静音按键(JAVA键值为164)映射为JS键值20001,PS:注意"164"的引号
139
139
  window.JsvCoreApi.addKeysMap(this.#config.vendorConfig.bindKeys);
140
140
 
141
+ // 设置触摸滑动距离阈值
142
+ if (this.#config.vendorConfig.touchConfig.slop > 0) {
143
+ window.JsvCoreApi.setRenderGlobalConfig({
144
+ touchSlop: this.#config.vendorConfig.touchConfig.slop
145
+ });
146
+ }
147
+
141
148
  // (可选配置)localStorage支持
142
149
  let storageDomain = this.#config.jsviewConfig.localStorage.domain;
143
150
  if (!storageDomain || storageDomain === "default") {
@@ -17,6 +17,7 @@ async function main() {
17
17
  const onInitJsViewEnv = async function () {
18
18
  // JsView环境加载完毕后,加载vue/react的main.js文件。
19
19
  try {
20
+ window.setJsvAppConfig(JSON.stringify(appConfig));
20
21
  await import('/src/main.tsx');
21
22
  } finally {
22
23
  window.JsvCoreApi.onMainTsDone(); // 通知Java, 此时app首次渲染执行完毕
@@ -37,6 +37,10 @@ export default {
37
37
  displayScale: 1.5
38
38
  },
39
39
 
40
+ touchConfig: {
41
+ slop: undefined, // 触摸滑动距离阈值, 单位px,为undefined时表示使用JsView系统默认距离
42
+ },
43
+
40
44
  // (可选配置)按键接受的扩展,例如将静音按键(JAVA键值为164)映射为JS键值20001,
41
45
  // PS:注意'164'的引号
42
46
  bindKeys: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shijiu/jsview",
3
- "version": "2.3.0",
3
+ "version": "2.3.728-alpha.0",
4
4
  "bin": {
5
5
  "jsview-post-build": "./tools/jsview-post-build.js",
6
6
  "jsview-post-install": "./tools/jsview-post-install.js"
@@ -368,6 +368,7 @@ const comparator = (a, b) => {
368
368
  };
369
369
  // JsView Modified >>>
370
370
  let JsvRenderCount = 0;
371
+ let hasBreakEnableApi = !!(window.JsView?.ifRenderBreakEnable);
371
372
  // JsView Modified <<<
372
373
  function flushJobs(seen) {
373
374
  isFlushPending = false;
@@ -5167,8 +5168,9 @@ function baseCreateRenderer(options, createHydrationFns) {
5167
5168
  // 有按键打断, 取消patch
5168
5169
  if (n1 == null && n2) {
5169
5170
  if (n2.key == "__QcodeJsviewMetroWidgetSlot"
5171
+ && (!hasBreakEnableApi || window.JsView.ifRenderBreakEnable())
5170
5172
  && (jsvPendingForFirstDelayRender
5171
- || window.JsvCode.Dom.GetLazyTaskAmount() > 1200 // 1200个同步单位时间 = 60ms(每个相当于50us)
5173
+ || window.JsvCode.Dom.IsLazyTaskQueueOverLoad() // 用于解决一次性dom元素过多导致一帧卡太久的问题
5172
5174
  || window.JsView?.hasPendingUserInput?.())
5173
5175
  && JsvRenderCount >= (window.JsView?.getInstantRenderNum?.() ?? 0)) {
5174
5176
  // 创建Comment节点, 以解决el释放可能出错问题
@@ -5184,7 +5186,9 @@ function baseCreateRenderer(options, createHydrationFns) {
5184
5186
  }
5185
5187
  };
5186
5188
 
5187
- if (n2.children[0].key === "__QcodeJsviewMetroWidgetSlot") {
5189
+ // TODO: 有时候children[0]不存在
5190
+ // TODO: 为什么需要对children[0]进行设置?是否是考虑patch时第一子节点不递归的问题, 需要vue版本升级时重新评估
5191
+ if (n2.children?.[0]?.key === "__QcodeJsviewMetroWidgetSlot") {
5188
5192
  n2.children[0].anchor = anchor;
5189
5193
  n2.children[0].jsvRenderBreaker = {
5190
5194
  breaked: true,
@@ -21,12 +21,16 @@ async function main(argv)
21
21
  const zipName = 'dist.dat';
22
22
  const zipPath = path.resolve(options.distDir, zipName);
23
23
 
24
- const password = argv.password ?? 'jsview.shijiu.com';
24
+ let password = argv.password ?? 'jsview.shijiu.com';
25
+ if(argv.noPassword) {
26
+ password = null;
27
+ }
25
28
 
26
29
  execCommand('npm run build');
27
30
 
28
31
  let childFileNames = fs.readdirSync(options.distDir);
29
32
  childFileNames = childFileNames.filter(it => it !== zipName);
33
+ childFileNames = childFileNames.filter(it => it !== 'debug');
30
34
  childFileNames = childFileNames.map(it => path.resolve(options.distDir, it));
31
35
 
32
36
  makeZip(zipPath, password, ...childFileNames)
@@ -37,7 +41,8 @@ async function main(argv)
37
41
  const requiredUsages = {
38
42
  };
39
43
  const optionalUsages = {
40
- '--password': 'Input passwork',
44
+ '--password': 'Input password',
45
+ '--no-password': 'Ignore password',
41
46
  };
42
47
  const argv = parseArguments(requiredUsages, optionalUsages);
43
48
  main(argv);
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ // #!/usr/bin/env node
2
2
  'use strict';
3
3
 
4
4
  import childProcess from 'node:child_process';
@@ -66,6 +66,10 @@ function parseArguments(requiredUsages = {},
66
66
  || value === 'null'
67
67
  || value === '') {
68
68
  formattedValue = null;
69
+ } else if(value === 'true') {
70
+ formattedValue = true;
71
+ } else if(value === 'false') {
72
+ formattedValue = false;
69
73
  }
70
74
  return formattedValue;
71
75
  }
@@ -180,6 +184,7 @@ function parseArguments(requiredUsages = {},
180
184
  * jsview-test-project
181
185
  * ├── dist
182
186
  * │   ├── assets
187
+ * │   ├── css
183
188
  * │   ├── debug
184
189
  * │   │   └── map
185
190
  * │   └── js
@@ -197,6 +202,7 @@ function parseArguments(requiredUsages = {},
197
202
  * │   │   │   ├── tools
198
203
  * │   │   ├── jsview-vue -> ../../../../@shijiu/jsview-vue
199
204
  * │   │   │   └── utils
205
+ * │   │   ├── jsview-vue-plus -> ../../../../@shijiu/jsview-vue-plus
200
206
  * │   │   └── jsview-vue-samples -> ../../../../@shijiu/jsview-vue-samples
201
207
  * └── src
202
208
  *    └── appConfig
@@ -217,6 +223,7 @@ function getOptions(framework)
217
223
  options.jsviewDomRevisionFile = path.resolve(options.jsviewDir, 'dom', 'target_core_revision.mjs');
218
224
 
219
225
  options.jsviewVueDir = path.resolve(options.modulesDir, '@shijiu', 'jsview-vue');
226
+ options.jsviewVuePlusDir = path.resolve(options.modulesDir, '@shijiu', 'jsview-vue-plus');
220
227
  options.jsviewReactDir = path.resolve(options.modulesDir, '@shijiu', 'jsview-react');
221
228
  if (framework) {
222
229
  options.jsviewFrameworkDir = path.resolve(options.modulesDir, '@shijiu', 'jsview-' + framework);
@@ -240,10 +247,12 @@ function getOptions(framework)
240
247
  }
241
248
  }
242
249
  }
250
+ options.distJsvConfigFile = path.resolve(options.distDir, 'jsv-config.json');
243
251
  options.distJsvListFile = path.resolve(options.distDir, 'jsv-list.json');
244
252
  options.distJsvInfoFile = path.resolve(options.distDir, 'jsv-info.json');
245
253
  options.distJsIndexFile = path.resolve(options.distDir, 'index.html');
246
254
  options.distAssetsDir = path.resolve(options.distDir, 'assets');
255
+ options.distCssDir = path.resolve(options.distDir, 'css');
247
256
  options.distJsDir = path.resolve(options.distDir, 'js');
248
257
  options.distDebugDir = path.resolve(options.distDir, 'debug');
249
258
  options.distDebugMapDir = path.resolve(options.distDebugDir, 'map');
@@ -95,6 +95,7 @@ function updateOptions(options)
95
95
  options.appPrivKey = privKey;
96
96
  options.appPubKey = pubKey;
97
97
  options.appEntryMd5 = appEntryMd5;
98
+ options.appEntryFileName = `main.jsv.${options.appEntryMd5.slice(0, 8)}.js`;
98
99
  }
99
100
 
100
101
  function getOtherSignVerifyKeys(options)
@@ -191,6 +192,22 @@ async function prepareMainAppData(options)
191
192
  preloadBurdenResources.push(fileName);
192
193
  }
193
194
 
195
+ const aesKeyFilePath = path.resolve(options.appConfigDir, 'fingerprint_aes_key.mjs');
196
+ if (fs.existsSync(aesKeyFilePath)) {
197
+ const aesKeyFileUrl = url.pathToFileURL(aesKeyFilePath);
198
+ const { default: aesKeyConfig } = await import (aesKeyFileUrl);
199
+ const aesKey = aesKeyConfig.aes_key;
200
+ const aesIv = aesKeyConfig.iv;
201
+
202
+ // 对appConfig.AppName进行aes加密并赋值给EncryptCode2
203
+ if (aesKey && aesIv) {
204
+ const cipher = crypto.createCipheriv('aes-128-cbc', Buffer.from(aesKey, 'utf8'), Buffer.from(aesIv, 'utf8'));
205
+ let encrypted = cipher.update(appConfig.AppName, 'utf8', 'base64');
206
+ encrypted += cipher.final('base64');
207
+ appConfig.EncryptCode2 = encrypted;
208
+ }
209
+ }
210
+
194
211
  // 组装AppData
195
212
  appConfig.PublicKeys = publicKeys; // 使用签名数组,支持后续追加签名
196
213
  appConfig.EncryptCodes = [encryptBase64]; // 同样使用数组,支持后续追加
@@ -199,10 +216,32 @@ async function prepareMainAppData(options)
199
216
  BaseUrl: bunderBaseUrl,
200
217
  Resources: preloadBurdenResources,
201
218
  };
219
+ if (appConfig.FingerPrint) {
220
+ // 删除FingerPrint的存储,节省信息字节数
221
+ delete appConfig.FingerPrint;
222
+ }
202
223
 
203
224
  return JSON.stringify(appConfig);
204
225
  }
205
226
 
227
+ async function checkCssFileSize(options)
228
+ {
229
+ if(fs.existsSync(options.distCssDir) == false) {
230
+ return;
231
+ }
232
+
233
+ const cssFileNames = fs.readdirSync(options.distCssDir);
234
+ for(const fileName of cssFileNames) {
235
+ const filePath = path.resolve(options.distCssDir, fileName)
236
+ const fileStats = await fs.statSync(filePath);
237
+ if (fileStats.size > 0) {
238
+ continue;
239
+ }
240
+
241
+ fs.writeFileSync(filePath, ' ', 'utf8'); // 防止空文件。
242
+ }
243
+ }
244
+
206
245
  async function checkAppConfig(options)
207
246
  {
208
247
  const appConfigFilePath = path.resolve(options.appConfigDir, 'app.config.mjs');
@@ -333,7 +372,8 @@ function redirectBurdenResource(options)
333
372
  let sourceContent = fs.readFileSync(filePath, 'utf8');
334
373
 
335
374
  for(const burdenFilePath of burdenFilePathList) {
336
- const relativeBurdenFilePath = path.relative(options.distJsDir, burdenFilePath);
375
+ let relativeBurdenFilePath = path.relative(options.distJsDir, burdenFilePath);
376
+ relativeBurdenFilePath = relativeBurdenFilePath.replaceAll('\\', '/'); // 更正windows分隔符
337
377
  if(!sourceContent.includes(relativeBurdenFilePath)) {
338
378
  continue;
339
379
  }
@@ -395,14 +435,13 @@ function makeMainJsvMjs(options, framework)
395
435
 
396
436
  // 更新entry hash
397
437
  const jsEntryFilePath = getEntryFilePath(options);
398
- const newEntryFileName = `main.jsv.${options.appEntryMd5.slice(0, 8)}.js`;
399
- const newEntryFilePath = path.resolve(path.dirname(jsEntryFilePath), newEntryFileName);
438
+ const newEntryFilePath = path.resolve(options.distJsDir, options.appEntryFileName);
400
439
  Logger.Info(' -> ' + path.relative(options.projectDir, newEntryFilePath));
401
440
  fs.renameSync(jsEntryFilePath, newEntryFilePath);
402
441
 
403
442
  // 更新index.html hash
404
443
  var indexContent = fs.readFileSync(options.distJsIndexFile, 'utf8');
405
- indexContent = indexContent.replace(path.basename(jsEntryFilePath), newEntryFileName);
444
+ indexContent = indexContent.replace(path.basename(jsEntryFilePath), options.appEntryFileName);
406
445
  Logger.Info(' -> ' + path.relative(options.projectDir, options.distJsIndexFile));
407
446
  fs.writeFileSync(options.distJsIndexFile, indexContent, 'utf8');
408
447
 
@@ -478,6 +517,38 @@ function makeDebugMap(options, framework)
478
517
  fs.copyFileSync(jsmapServePath, to);
479
518
  }
480
519
 
520
+ async function makeJsvConfig(options)
521
+ {
522
+ const jsviewVersionURL = url.pathToFileURL(options.jsviewDomRevisionFile);
523
+ const { default: jsviewTargetVersion } = await import(jsviewVersionURL);
524
+ const appEntryFilePath = path.resolve(options.distJsDir, options.appEntryFileName);
525
+ let appEntryFileName = `./${path.relative(options.distDir, appEntryFilePath)}`;
526
+ // appEntryFileName = appEntryFileName.replace(/\.js$/, '.mjs'); // deprecated
527
+ appEntryFileName = appEntryFileName.replaceAll('\\', '/'); // windows平台适配
528
+
529
+ const appConfigFilePath = path.resolve(options.appConfigDir, 'app.config.mjs');
530
+ if (!fs.existsSync(appConfigFilePath)) {
531
+ Logger.ErrorAndExit('Failed to open app config file from ' + appConfigFilePath);
532
+ }
533
+ const appConfigFileUrl = url.pathToFileURL(appConfigFilePath);
534
+ const { default: appConfig } = await import(appConfigFileUrl);
535
+
536
+ const jsvConfig = {
537
+ "COREVERSIONRANGE": jsviewTargetVersion.CoreRevisionAndBranch,
538
+ "ENGINE": jsviewTargetVersion.JseUrl,
539
+ "URL": appEntryFileName,
540
+ "MINIAPPNAME": appConfig.AppName,
541
+ };
542
+
543
+ // 启动图
544
+ if (appConfig.StartImageUrl && appConfig.StartImageUrl.length != 0) {
545
+ jsvConfig.STARTIMG = appConfig.StartImageUrl;
546
+ }
547
+
548
+ const content = JSON.stringify(jsvConfig, null, 2);
549
+ fs.writeFileSync(options.distJsvConfigFile, content, 'utf8');
550
+ }
551
+
481
552
  function makeJsvList(options)
482
553
  {
483
554
  let jsvList = makeFileListRecusive(options.distDir);
@@ -551,6 +622,10 @@ async function main(argv)
551
622
  await checkDomDebugDisabled(options);
552
623
 
553
624
  Logger.Info();
625
+ const jsviewPkgJson = loadPackageObject(options.jsviewDir);
626
+ Logger.Info(`JsView version: ${jsviewPkgJson.version}`);
627
+ Logger.Info();
628
+
554
629
  Logger.Info('Redirecting JsView burden resource...');
555
630
  redirectBurdenResource(options)
556
631
  Logger.Info('Redirected JsView burden resource...');
@@ -562,6 +637,10 @@ async function main(argv)
562
637
  // EntryMd5 要放在sourcemap更新之后
563
638
  updateOptions(options);
564
639
 
640
+ Logger.Info('Checking JsView css file size...');
641
+ await checkCssFileSize(options);
642
+ Logger.Info('Checked JsView css file size...');
643
+
565
644
  Logger.Info('Checking JsView app config...');
566
645
  await checkAppConfig(options);
567
646
  Logger.Info('Checked JsView app config...');
@@ -578,13 +657,16 @@ async function main(argv)
578
657
  makeDebugMap(options, argv.framework);
579
658
  Logger.Info('Made JsView Debug map.');
580
659
 
660
+ Logger.Info('Cleaning JsView Burden Resource...');
661
+ cleanupBurdenResource(options);
662
+ Logger.Info('Cleaned JsView Burden Resource...');
663
+
581
664
  Logger.Info('Making JsView info...');
665
+ await makeJsvConfig(options);
582
666
  makeJsvList(options);
583
667
  await makeJsvInfo(options);
584
668
  Logger.Info('Made JsView info...');
585
669
 
586
- cleanupBurdenResource(options);
587
-
588
670
  Logger.Info('Done...');
589
671
  }
590
672
 
@@ -230,10 +230,10 @@ async function printRevision(options)
230
230
  let versionFilePath = path.resolve(pathname, 'version.mjs');
231
231
  if (fs.existsSync(versionFilePath)) {
232
232
  const versionFileURL = url.pathToFileURL(versionFilePath);
233
- const { default: targetVersion } = await import(versionFileURL);
234
- Logger.Info(`* [${path.basename
235
- (pathname)}] : ${targetVersion.packageName
236
- } : ${targetVersion.version}`);
233
+ const versionModule = await import(versionFileURL);
234
+ // 兼容 default 导出(JsvAudio/JsvPlayer)与命名导出 PluginInfo(JsvLatex)
235
+ const targetVersion = versionModule.PluginInfo ?? versionModule.default;
236
+ Logger.Info(`* [${path.basename(pathname)}] : ${targetVersion.packageName} : ${targetVersion.version}`);
237
237
  pluginCount++;
238
238
  }
239
239
  }
@@ -250,9 +250,15 @@ function doPostInstall(framework, pkgNeedPatch, skipCheckVersion, skipCheckNpmcm
250
250
  const options = getOptions(framework);
251
251
  options.projectDir = process.cwd();
252
252
 
253
+ Logger.Info();
254
+ const jsviewPkgJson = loadPackageObject(options.jsviewDir);
255
+ Logger.Info(`JsView version: ${jsviewPkgJson.version}`);
256
+ Logger.Info();
257
+
253
258
  const linkablePkgNames = [
254
259
  '@shijiu/jsview',
255
260
  '@shijiu/jsview-vue',
261
+ '@shijiu/jsview-vue-plus',
256
262
  '@shijiu/jsview-vue-samples',
257
263
  '@shijiu/jsview-vue-extra-samples',
258
264
  '@shijiu/jsview-react',
@@ -79,6 +79,7 @@ async function getExtraOptions(argv)
79
79
  options.genKeypair = argv.genKeypair;
80
80
  options.buildMinifyExclude = argv.buildMinifyExclude;
81
81
  options.buildZip = argv.buildZip;
82
+ options.noPassword = argv.noPassword;
82
83
  options.buildBurdenLocal = argv.buildBurdenLocal;
83
84
  options.buildBurdenBaseurl = argv.buildBurdenBaseurl;
84
85
  options.vueDevtools = argv.vueDevtools;
@@ -129,11 +130,7 @@ function doCommand(options, argv) {
129
130
  } else if(options.buildZip) {
130
131
  const defaultPassword = 'jsview.shijiu.com';
131
132
  const password = (typeof(options.buildZip) === 'string' ? options.buildZip : defaultPassword);
132
- if(password !== options.buildZip) {
133
- Logger.Warn(`Zip password is not set, use default value: ${defaultPassword}`);
134
- }
135
-
136
- command = `node node_modules/@shijiu/jsview/tools/jsview-build-zip.mjs --password=${password}`;
133
+ command = `node node_modules/@shijiu/jsview/tools/jsview-build-zip.mjs --password=${password} ${options.noPassword ? '--no-password' : ''}`;
137
134
  } else if(options.buildBurdenLocal) {
138
135
  command = 'JSVIEW_BURDEN_LOCAL=true npm run build';
139
136
  } else if(options.buildBurdenBaseurl) {
@@ -217,7 +214,7 @@ const optionalUsages = {
217
214
  '-c | --config-app': 'Config app, like: -c or --config-app=[AppName:AppTitle].',
218
215
  '-g | --gen-keypair': 'Generate sign keypair.',
219
216
  '-m | --build-minify-exclude': 'Build target with minify-exclude filter, like: -m or --build-minify-exclude=[filter], additional options: -s or --script=build:dev.',
220
- '-z | --build-zip': 'Build target to offline zip package, like: -z or --build-zip=[password].',
217
+ '-z | --build-zip': 'Build target to offline zip package, like: -z, --build-zip=[password] or --build-zip --no-password.',
221
218
  '-l | --build-burden-local': 'Build target with local burden files.',
222
219
  '-b | --build-burden-baseurl': 'Build target with custom burden base url.',
223
220
  '-d | --vue-devtools': 'Start vue dev server and vue-devtools standalone, like: -d or --vue-devtools=[port].',