wxa-runner 0.8.2 → 0.9.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 (2) hide show
  1. package/bin/wxa-runner.js +50 -2
  2. package/package.json +3 -3
package/bin/wxa-runner.js CHANGED
@@ -32,15 +32,20 @@ program
32
32
  .option('--forward-console', '浏览器里的 console.warn / console.error 也转发到终端(检测到编程助手时默认开启)')
33
33
  .option('--no-forward-console', '浏览器里的报错不转发到终端')
34
34
  .option('--devtools-login', '借本机微信开发者工具的登录态访问微信后台:真实的 code 和手机号、服务市场、插件')
35
+ .option('--extension <module>', '加载开发服务器扩展(npm 包名或文件路径),可以写多次', (value, previous) => [...previous, value], [])
35
36
  // 旧名,开发服务器会提示改用 --devtools-login
36
37
  .addOption(new Option('--real-login').hideHelp())
37
38
  .action(async (projectPath, options) => {
38
39
  const { DevServer } = require('@open-wxa/wxa-runner-core');
40
+ const resolvedProjectPath = path.resolve(process.cwd(), projectPath);
39
41
 
40
42
  try {
43
+ const extensions = [];
44
+ for (const name of options.extension) extensions.push(await loadExtension(name, resolvedProjectPath));
41
45
  const forward = await resolveForwardConsole(options.forwardConsole);
42
46
  const server = new DevServer({
43
- projectPath: path.resolve(process.cwd(), projectPath),
47
+ projectPath: resolvedProjectPath,
48
+ extensions,
44
49
  port: options.port === undefined ? undefined : parseInt(options.port, 10),
45
50
  host: options.host === true ? '0.0.0.0' : options.host,
46
51
  baseLibVersion: options.baselib,
@@ -55,6 +60,7 @@ program
55
60
  console.log('');
56
61
  console.log(chalk.green(' wxa-runner 已启动'));
57
62
  console.log(` 地址 ${chalk.cyan(url)}`);
63
+ server.extensionEntries.forEach(entry => console.log(` ${bannerLabel(entry.label)}${chalk.cyan(url + entry.path)}`));
58
64
  const networkUrls = server.networkUrls;
59
65
  if (networkUrls.length === 0) {
60
66
  console.log(` 局域网 ${chalk.gray('加 --host 开放局域网访问')}`);
@@ -66,7 +72,8 @@ program
66
72
  if (server.setupFile) console.log(` setup ${server.setupFile}`);
67
73
  console.log('');
68
74
 
69
- if (options.open) openBrowser(url);
75
+ // 有扩展页面时打开第一个:扩展页面通常把小程序嵌在里面
76
+ if (options.open) openBrowser(url + (server.extensionEntries[0]?.path ?? ''));
70
77
 
71
78
  const shutdown = () => server.close().then(() => process.exit(0));
72
79
  process.on('SIGINT', shutdown);
@@ -111,6 +118,47 @@ baselib
111
118
  }
112
119
  });
113
120
 
121
+ /**
122
+ * 加载 --extension 指定的扩展。扩展装在用户项目里,从 wxa-runner 自己的安装位置不一定找得到(如 pnpm 不提升依赖时),
123
+ * 所以依次从项目目录、当前目录、wxa-runner 自身查找。CommonJS 和 ES 模块都可以,
124
+ * 默认导出可以是扩展对象,也可以是不带参数调用后返回扩展的函数
125
+ */
126
+ async function loadExtension(name, projectPath) {
127
+ const { createRequire } = require('module');
128
+ const { pathToFileURL } = require('url');
129
+ const request = name.startsWith('.') ? path.resolve(name) : name;
130
+ let resolved = null;
131
+ for (const base of [path.join(projectPath, 'package.json'), path.join(process.cwd(), 'package.json'), __filename]) {
132
+ try {
133
+ resolved = createRequire(base).resolve(request);
134
+ break;
135
+ } catch (error) {
136
+ if (error.code === 'MODULE_NOT_FOUND') continue;
137
+ // 装了但解析不出入口,如 exports 只给了 import 条件:按 require 的规则解析,找不到可用的入口
138
+ throw new Error(`扩展 ${name} 加载失败:${error.message.split('\n')[0]}。package.json 的 exports 要提供 require 或 default 条件`);
139
+ }
140
+ }
141
+ if (!resolved) {
142
+ console.error(chalk.red(`\n找不到扩展 ${name}:`), chalk.cyan(`npm i -D ${name}`));
143
+ process.exit(1);
144
+ }
145
+ // 用 import() 而不是 require():Node.js 22.12 之前 require() 不能加载 ES 模块,之后也不能加载带顶层 await 的。
146
+ // import() 拿到的 default 对 CommonJS 是 module.exports,所以 exports.default 还要再取一层
147
+ const exported = (await import(pathToFileURL(resolved).href)).default;
148
+ const candidate = exported?.default ?? exported;
149
+ const extension = typeof candidate === 'function' ? candidate() : candidate;
150
+ if (!extension || typeof extension.name !== 'string' || typeof extension.setup !== 'function') {
151
+ throw new Error(`${name} 不是 wxa-runner 的扩展:默认导出要有 name 和 setup(),或是返回这样的对象的函数`);
152
+ }
153
+ return extension;
154
+ }
155
+
156
+ /** 启动信息左列的标签补到 10 列宽,与「地址 」对齐;中文字符占两列 */
157
+ function bannerLabel(label) {
158
+ const width = [...label].reduce((sum, ch) => sum + (ch.charCodeAt(0) > 0xff ? 2 : 1), 0);
159
+ return label + ' '.repeat(Math.max(10 - width, 2));
160
+ }
161
+
114
162
  /**
115
163
  * 没指定 --forward-console / --no-forward-console 时:编程助手自己启动开发服务器时只看得到终端,
116
164
  * console.warn / console.error 也转发;人在自己的终端里启动时用浏览器的开发者工具看,只转发报错
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wxa-runner",
3
- "version": "0.8.2",
3
+ "version": "0.9.0",
4
4
  "description": "Run WeChat Mini Programs in the browser on the official base library, for debugging and E2E testing",
5
5
  "keywords": [
6
6
  "wechat",
@@ -36,8 +36,8 @@
36
36
  "@vercel/detect-agent": "^1.2.7",
37
37
  "chalk": "^4.1.2",
38
38
  "commander": "^11.1.0",
39
- "@open-wxa/wxa-runner-core": "0.8.2",
40
- "@open-wxa/wxa-runner-extractor": "0.8.2"
39
+ "@open-wxa/wxa-runner-core": "0.9.0",
40
+ "@open-wxa/wxa-runner-extractor": "0.9.0"
41
41
  },
42
42
  "engines": {
43
43
  "node": ">=18"