@bams-app/work-cli 0.1.6 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +70 -13
- package/bin/work-cli.js +7 -1
- package/commands/build.js +188 -41
- package/package.json +1 -1
- package/templates/project/package.json +8 -1
package/README.md
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
# @bams-app/work-cli
|
|
2
2
|
|
|
3
|
-
BAMS-Work 全局脚手架工具(类似 vue-cli
|
|
4
|
-
开发调试由用户项目**本地的** `@bams-app/ui-dev-server` 承担(`npm run dev:ui <环境标识>`),全局 CLI
|
|
3
|
+
BAMS-Work 全局脚手架工具(类似 vue-cli 模式),提供**项目初始化**、**组件创建**、**环境配置**与**宿主应用打包**能力。
|
|
4
|
+
开发调试由用户项目**本地的** `@bams-app/ui-dev-server` 承担(`npm run dev:ui <环境标识>`),全局 CLI 不参与启动开发服务;
|
|
5
|
+
打包(`work build <app>`)直接调用应用的 `vue-cli-service`,**不经过 ui-dev-server**(它只负责开发服务)。
|
|
5
6
|
|
|
6
7
|
## 设计思路
|
|
7
8
|
|
|
@@ -12,11 +13,13 @@ BAMS-Work 全局脚手架工具(类似 vue-cli 模式),提供**项目初
|
|
|
12
13
|
| ------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
|
|
13
14
|
| 项目/组件创建 | `@bams-app/create-ui-component`、`@bams-app/create-ui-page`、`@bams-app/create-ui-base`(模板内置于各包 `templates/`) |
|
|
14
15
|
| 开发服务 | `@bams-app/ui-dev-server`(由模板写入用户项目 `devDependencies`,`npm run dev:ui <环境标识>` 本地启动;环境标识由第 1 个位置参数传入) |
|
|
15
|
-
|
|
|
16
|
+
| 宿主应用 | `@bams-app/bams-app`、`@bams-app/project-startr`、`@bams-app/touch-startr`(随版本发布,`work create` 模板写入用户项目 `dependencies`) |
|
|
17
|
+
| 打包构建执行 | `@vue/cli-service`(由应用自身 `vue.config.js` 驱动,**不经过 ui-dev-server**;应用基础配置复用 `@bams-app/configs/vue.config.app-base`) |
|
|
18
|
+
| 环境变量加载 | `@bams-app/shared-env`(开发与打包同源:ui-dev-server 解析环境标识、`work build` 直接复用其 `lib/env-loader`) |
|
|
16
19
|
| 环境配置创建 | `@bams-app/create-env`(交互式生成 `.envs/.env.dev-<alias>`) |
|
|
17
20
|
| 动态入口生成 | `@bams-app/create-pages-entry`(扫描 page-_/ui-_ 生成 build-components-entry.js) |
|
|
18
21
|
| 批量页面创建 | `@bams-app/create-pages-from-components`(批量将 ui-_ 转为 page-_,复用 create-ui-page) |
|
|
19
|
-
| 公共配置 | `@bams-app/configs`(app-config.json
|
|
22
|
+
| 公共配置 | `@bams-app/configs`(app-config.json、可配置组件插槽默认值、宿主应用 vue-cli 基础配置 `vue.config.app-base`、组件别名解析,被 ui-dev-server / store / 宿主应用依赖) |
|
|
20
23
|
|
|
21
24
|
- `create` 生成 **scope 目录模式**项目:业务组件按 scope 目录存放(`energy-ui/ui-xxx`);
|
|
22
25
|
项目根 `package.json` 声明 `demo-ui/*`、`bams-components/*`、`*-ui/*`、`apex-web/*`、`bams-ui`
|
|
@@ -27,8 +30,13 @@ BAMS-Work 全局脚手架工具(类似 vue-cli 模式),提供**项目初
|
|
|
27
30
|
ui-dev-server 的 `dependencies` 维护**一处**,安装后提升到项目根 `node_modules`,
|
|
28
31
|
webpack 的 `resolve.modules` 即指向该处,版本随 ui-dev-server 走。
|
|
29
32
|
`create` **不生成**项目 `.npmrc`(`@bams-app/*` 默认走官方 npm)。
|
|
33
|
+
- 宿主应用(`@bams-app/bams-app`、`@bams-app/project-startr`、`@bams-app/touch-startr`)
|
|
34
|
+
作为**可发布包**写入项目 `dependencies`,供 `work build` 打包;应用也可由项目内 `apps/<app>`
|
|
35
|
+
提供(优先),二者取其一即可。
|
|
30
36
|
- 开发调试**不经过 CLI**:`npm run dev:ui <环境标识> [组件名]` 即项目本地的 `ui-dev-server`
|
|
31
37
|
(npm 走 `node_modules/.bin`),环境文件由其自行加载,追加的位置参数覆盖默认值。
|
|
38
|
+
- 打包**由 CLI 承担**:`work build <app>` 定位应用目录后,以该目录为 `cwd` 直接调用其
|
|
39
|
+
`vue-cli-service build`,并把 `WORK_PROJECT_ROOT` 指向项目根;**不经过 ui-dev-server**。
|
|
32
40
|
- 其余命令通过 `require.resolve()` 定位 work 包 bin 并以子进程委托执行,`WORK_PROJECT_ROOT` 环境变量注入项目根。
|
|
33
41
|
|
|
34
42
|
### 整体架构
|
|
@@ -43,28 +51,35 @@ flowchart LR
|
|
|
43
51
|
C["@bams-app/*"]
|
|
44
52
|
end
|
|
45
53
|
subgraph CLI["@bams-app/work-cli(全局 CLI)"]
|
|
46
|
-
D["create / add / env<br/>pages-entry / pages-from-components"]
|
|
54
|
+
D["create / add / env<br/>pages-entry / pages-from-components<br/>build(打包宿主应用)"]
|
|
47
55
|
end
|
|
48
56
|
subgraph PROJ["用户项目"]
|
|
49
|
-
E["package.json<br/>devDependencies:仅 ui-dev-server"]
|
|
57
|
+
E["package.json<br/>dependencies:宿主应用<br/>devDependencies:仅 ui-dev-server"]
|
|
50
58
|
F["npm install<br/>依赖自动安装"]
|
|
51
59
|
G["npm run dev:ui 环境标识<br/>本地 ui-dev-server"]
|
|
60
|
+
H["work build <app><br/>应用自身 vue-cli-service"]
|
|
52
61
|
end
|
|
53
62
|
A -->|"publish-all / 单包 npm publish"| C
|
|
54
63
|
B -->|"发布 + 依赖声明"| C
|
|
55
64
|
C -->|"registry 安装"| CLI
|
|
56
|
-
C -->|"registry 安装(ui-dev-server + 能力包 +
|
|
65
|
+
C -->|"registry 安装(ui-dev-server + 能力包 + 运行时依赖 + 宿主应用)"| PROJ
|
|
57
66
|
CLI -->|"子进程委托 work 包 bin"| B
|
|
67
|
+
CLI -->|"直接调用应用 vue-cli-service(不走 ui-dev-server)"| H
|
|
58
68
|
E --> F
|
|
59
69
|
F --> G
|
|
70
|
+
F --> H
|
|
60
71
|
```
|
|
61
72
|
|
|
62
73
|
```
|
|
63
74
|
用户项目(scope 目录模式)
|
|
64
|
-
├── package.json #
|
|
75
|
+
├── package.json # 项目根配置(dependencies 宿主应用 + devDependencies ui-dev-server)
|
|
65
76
|
├── .bams-work/ # BAMS-Work 项目标记目录(勿删除)
|
|
66
|
-
├── .envs/.env.dev-<env> #
|
|
77
|
+
├── .envs/.env.dev-<env> # 开发环境变量
|
|
78
|
+
├── .envs/.env.production # 打包环境变量(work build 默认加载)
|
|
67
79
|
├── .proxy.js # 自定义代理(可选)
|
|
80
|
+
├── apps/ # 项目内宿主应用(可选,优先于依赖包)
|
|
81
|
+
│ └── <app>/
|
|
82
|
+
├── dist/ # work build 产物目录
|
|
68
83
|
├── demo-ui/ # 默认组件 scope
|
|
69
84
|
│ └── ui-component-demo # 示例组件
|
|
70
85
|
└── energy-ui/ # 业务 scope 目录
|
|
@@ -93,6 +108,12 @@ npm run dev:ui demo ui-order-list # 指定组件(`-c ui-order-list` 等
|
|
|
93
108
|
work add --dir energy-ui --name ui-order-list
|
|
94
109
|
work add --dir energy-ui --name page-order-list --type page
|
|
95
110
|
work add --dir demo-ui --name ui-base-btn --type base
|
|
111
|
+
|
|
112
|
+
# 打包宿主应用(不走 ui-dev-server,直接调用应用的 vue-cli-service)
|
|
113
|
+
work build bams-app # 默认加载 .envs/.env.production
|
|
114
|
+
work build project-startr --env prod # 指定环境文件(.envs/.env.dev-prod)
|
|
115
|
+
work build touch-startr -- --modern # `--` 之后透传给 vue-cli-service
|
|
116
|
+
npm run build:bams-app # 模板内置的等价脚本
|
|
96
117
|
```
|
|
97
118
|
|
|
98
119
|
### 命令一览
|
|
@@ -101,6 +122,7 @@ work add --dir demo-ui --name ui-base-btn --type base
|
|
|
101
122
|
| -------------------------------------------------- | --------------------------------------------------------------------- |
|
|
102
123
|
| `create <name>` | 初始化项目模版(含示例组件与 `.bams-work/` 标记) |
|
|
103
124
|
| `add --dir <scope> --name <name>` | 在 scope 目录下创建组件(component/page/base),并注册 scope 目录 |
|
|
125
|
+
| `build <app> [--env <标识\|文件>] [-- <参数>]` | 打包宿主应用(`apps/<app>` 优先,回退依赖包;不走 ui-dev-server) |
|
|
104
126
|
| `env` | 交互式创建开发环境配置 `.envs/.env.dev-<alias>`(复用 create-env) |
|
|
105
127
|
| `pages-entry --dir <dir> --type <page\|component>` | 扫描 page-_/ui-_ 目录生成 webpack 动态入口(复用 create-pages-entry) |
|
|
106
128
|
| `pages-from-components --dir <dir>` | 批量将 ui-_ 组件转为 page-_ 页面(复用 create-pages-from-components) |
|
|
@@ -145,12 +167,39 @@ work skills sync --force # 内容一致时也重新复制
|
|
|
145
167
|
- 可配置插槽:`COMPONENT_*` 环境变量 + `@configurable/*` 别名(login / header / startr-layout)。
|
|
146
168
|
- 能力包可选组件(未安装时)由 `OPTIONAL_PACKAGE_FALLBACKS` 兜底 alias 到空入口,保证编译不报错。
|
|
147
169
|
|
|
170
|
+
## 打包宿主应用
|
|
171
|
+
|
|
172
|
+
`work build <app>` 用于把宿主应用打成静态产物,**全程不经过 `@bams-app/ui-dev-server`**
|
|
173
|
+
(它只是开发服务):
|
|
174
|
+
|
|
175
|
+
- **应用定位**:优先项目内 `apps/<app>`,回退到依赖包 `node_modules/@bams-app/<app>`
|
|
176
|
+
(须含 `package.json` 与 `vue.config.js`)。未传 `<app>` 且项目内仅一个可用应用时自动选中,
|
|
177
|
+
否则列出可用应用并退出。
|
|
178
|
+
- **构建执行**:以**应用目录为 `cwd`** 直接调用该应用自身的 `@vue/cli-service build`,
|
|
179
|
+
并注入 `WORK_PROJECT_ROOT=<项目根>`、`NODE_ENV=production`。应用基础配置
|
|
180
|
+
(externals、`@components-entry`、`@configurable/*` 别名、代理兜底)由
|
|
181
|
+
`@bams-app/configs/vue.config.app-base` 提供,仓库根与各应用共用同一份,避免漂移。
|
|
182
|
+
- **环境加载**:复用 `@bams-app/shared-env` 的 `lib/env-loader`,与开发服务同源。
|
|
183
|
+
默认加载 `.envs/.env.production`;`--env <标识>` 解析为 `.envs/.env.dev-<标识>`
|
|
184
|
+
(`--env production` 即 `.env.production`);`--env <路径>` 直接按路径解析。
|
|
185
|
+
应用私有 `.env.<mode>` 中同名变量覆盖项目根同名文件。
|
|
186
|
+
- **参数透传**:`--` 之后的参数原样传给 `vue-cli-service build`(如 `-- --modern`)。
|
|
187
|
+
- **产物目录**:由应用 `vue.config.js` 的 `outputDir` 决定(指向项目根 `dist`)。
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
work build bams-app # 打包 bams-app(默认 production 环境)
|
|
191
|
+
work build project-startr --env dev # 加载 .envs/.env.dev-dev
|
|
192
|
+
work build touch-startr -e .envs/.env.dev-demo
|
|
193
|
+
work build bams-app -- --no-clean # 透传 vue-cli 参数
|
|
194
|
+
```
|
|
195
|
+
|
|
148
196
|
## 发布流程
|
|
149
197
|
|
|
150
198
|
所有 work 包统一发布到 npm registry,**默认官方 npm(registry.npmjs.org)**,通过环境变量
|
|
151
199
|
`NPM_REGISTRY` 可随时切换到私有 registry(如 `https://npm.hedpy.cn/`)。work 下所有含
|
|
152
|
-
`package.json` 的目录(`packages/`、`ui/`、`tooling/`、`cli/`、`configs/` 等)
|
|
153
|
-
都会被打包发布,`private`
|
|
200
|
+
`package.json` 的目录(`packages/`、`ui/`、`tooling/`、`cli/`、`configs/`、`apps/` 等)
|
|
201
|
+
都会被打包发布,`private` 包自动跳过。宿主应用(`work/apps/*`)已去掉 `private` 并声明 `files`
|
|
202
|
+
白名单,随版本作为 `@bams-app/<app>` 发布,供用户项目安装后由 `work build` 打包:
|
|
154
203
|
|
|
155
204
|
```bash
|
|
156
205
|
# 0. 登录对应 registry(每次切换目标后需重新登录)
|
|
@@ -173,6 +222,7 @@ cd work/packages/utils && npm publish --registry=https://registry.npmjs.org/
|
|
|
173
222
|
cd work/ui/ui-header-component && npm publish --registry=https://registry.npmjs.org/
|
|
174
223
|
cd work/tooling/create-ui-component && npm publish --registry=https://registry.npmjs.org/
|
|
175
224
|
cd work/configs && npm publish --registry=https://registry.npmjs.org/
|
|
225
|
+
cd work/apps/bams-app && npm publish --registry=https://registry.npmjs.org/
|
|
176
226
|
```
|
|
177
227
|
|
|
178
228
|
单包发布只影响该包,其他包版本号不变;需要整体提升版本时使用 `yarn publish-all`。
|
|
@@ -184,8 +234,9 @@ cd work/configs && npm publish --registry=https://registry.npmjs.org/
|
|
|
184
234
|
|
|
185
235
|
## 用户项目升级
|
|
186
236
|
|
|
187
|
-
|
|
188
|
-
|
|
237
|
+
用户项目在 `devDependencies` 只声明 `@bams-app/ui-dev-server` 一个依赖,能力包与运行时依赖全部作为它的
|
|
238
|
+
传递依赖解析到同一份包,提升到项目根 `node_modules`;`dependencies` 另声明宿主应用
|
|
239
|
+
(`@bams-app/bams-app` / `project-startr` / `touch-startr`,以 `"*"` 跟随 registry 最新已发布版本)。
|
|
189
240
|
|
|
190
241
|
ui-dev-server 对能力包声明的是显式版本范围(`^x.y.z`),范围随 ui-dev-server 每次发布同步更新,
|
|
191
242
|
因此升级就是一条命令:
|
|
@@ -194,6 +245,12 @@ ui-dev-server 对能力包声明的是显式版本范围(`^x.y.z`),范围
|
|
|
194
245
|
npm i @bams-app/ui-dev-server@latest
|
|
195
246
|
```
|
|
196
247
|
|
|
248
|
+
宿主应用随 `yarn publish-all` 同批次发布,升级时可一并刷新:
|
|
249
|
+
|
|
250
|
+
```bash
|
|
251
|
+
npm i @bams-app/bams-app@latest @bams-app/project-startr@latest @bams-app/touch-startr@latest
|
|
252
|
+
```
|
|
253
|
+
|
|
197
254
|
新版本的依赖范围与 `package-lock.json` 中钉住的旧版本不再匹配,npm 会自动重新解析整套能力包,
|
|
198
255
|
无需手工清理 lockfile(历史版本遗留的 `*` 范围才需要旧办法,见 git 历史)。
|
|
199
256
|
|
package/bin/work-cli.js
CHANGED
|
@@ -10,6 +10,7 @@ const COMMANDS = {
|
|
|
10
10
|
create: '初始化项目模版',
|
|
11
11
|
add: '在 scope 目录下创建组件(component/page/base)',
|
|
12
12
|
env: '创建开发环境配置(.envs/.env.dev-<alias>)',
|
|
13
|
+
build: '打包宿主应用(apps/<app> 或依赖中的 @bams-app/<app>,不走 ui-dev-server)',
|
|
13
14
|
'pages-entry': '扫描 page-*/ui-* 目录生成 webpack 动态入口',
|
|
14
15
|
'pages-from-components': '批量将 ui-* 组件转为 page-* 页面',
|
|
15
16
|
skills: '把组件包内嵌的 SKILL.md 同步到项目根 .skills/(中立目录,与 AI 工具无关)'
|
|
@@ -17,7 +18,7 @@ const COMMANDS = {
|
|
|
17
18
|
|
|
18
19
|
// 暂时下线的命令:commands/ 下的实现文件保留,恢复时删除此处对应项即可
|
|
19
20
|
// dev:开发环境由用户项目本地的 ui-dev-server 启动(npm run dev:ui),CLI 不再承担
|
|
20
|
-
const DISABLED_COMMANDS = ['dev', '
|
|
21
|
+
const DISABLED_COMMANDS = ['dev', 'umd'];
|
|
21
22
|
|
|
22
23
|
function printUsage() {
|
|
23
24
|
console.log('');
|
|
@@ -36,6 +37,7 @@ function printUsage() {
|
|
|
36
37
|
console.log(' work create my-bams-project # 初始化项目');
|
|
37
38
|
console.log(' work add --dir energy-ui --name ui-order-list');
|
|
38
39
|
console.log(' work env # 创建开发环境配置(交互式)');
|
|
40
|
+
console.log(' work build bams-app # 打包宿主应用(.envs/.env.production)');
|
|
39
41
|
console.log(' work pages-entry --dir energy-ui --type page');
|
|
40
42
|
console.log(' work pages-from-components --dir energy-ui');
|
|
41
43
|
console.log(' work skills sync # 把组件包内嵌技能同步到 .skills/');
|
|
@@ -43,6 +45,10 @@ function printUsage() {
|
|
|
43
45
|
console.log(colorize('开发调试:', 'bold'));
|
|
44
46
|
console.log(' 在项目根目录执行 npm run dev:ui <环境标识>(由项目本地 ui-dev-server 启动并加载 .envs/ 环境文件)');
|
|
45
47
|
console.log('');
|
|
48
|
+
console.log(colorize('打包:', 'bold'));
|
|
49
|
+
console.log(' work build <app> [--env <标识|文件>] [-- <vue-cli 参数>]');
|
|
50
|
+
console.log(' 直接以应用的 vue-cli-service 打包(默认 .envs/.env.production),不经过 ui-dev-server');
|
|
51
|
+
console.log('');
|
|
46
52
|
}
|
|
47
53
|
|
|
48
54
|
async function main() {
|
package/commands/build.js
CHANGED
|
@@ -1,19 +1,121 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
|
-
const { findProjectRoot, error, info, run } = require('../lib/utils');
|
|
3
|
+
const { findProjectRoot, error, info, warn, log, run, isDirectory } = require('../lib/utils');
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* 用法: work build [
|
|
7
|
-
*
|
|
6
|
+
* 用法: work build [app] [--env <alias|file>] [-- <vue-cli args>]
|
|
7
|
+
*
|
|
8
|
+
* 直接以应用的 vue-cli-service 打包宿主应用(默认 production),
|
|
9
|
+
* 不经过 @bams-app/ui-dev-server(它只负责开发服务)。
|
|
10
|
+
* 应用来源:优先项目内 apps/<app>,回退到依赖 node_modules/@bams-app/<app>。
|
|
11
|
+
* 环境变量复用 @bams-app/shared-env 的 env-loader(含应用私有 .env.<mode> 覆盖)。
|
|
8
12
|
*/
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
|
|
14
|
+
/** 判定目录是否为可打包的 vue-cli 应用(含 package.json 与 vue.config.js) */
|
|
15
|
+
function isAppDir(dir) {
|
|
16
|
+
return isDirectory(dir)
|
|
17
|
+
&& fs.existsSync(path.join(dir, 'package.json'))
|
|
18
|
+
&& fs.existsSync(path.join(dir, 'vue.config.js'));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** @bams-app/foo -> foo;foo -> foo */
|
|
22
|
+
function toShortName(name) {
|
|
23
|
+
return name.startsWith('@') ? (name.split('/')[1] || name) : name;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** 收集项目中可打包的应用(项目内 apps/ 与 node_modules/@bams-app/) */
|
|
27
|
+
function listAvailableApps(projectRoot) {
|
|
28
|
+
const apps = [];
|
|
29
|
+
const seen = new Set();
|
|
30
|
+
|
|
31
|
+
const addApp = (name, dir) => {
|
|
32
|
+
if (seen.has(name) || !isAppDir(dir)) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
seen.add(name);
|
|
36
|
+
apps.push({ name, dir });
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const internalDir = path.join(projectRoot, 'apps');
|
|
40
|
+
if (isDirectory(internalDir)) {
|
|
41
|
+
for (const entry of fs.readdirSync(internalDir, { withFileTypes: true })) {
|
|
42
|
+
if (entry.name.startsWith('.')) {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
addApp(entry.name, path.join(internalDir, entry.name));
|
|
46
|
+
}
|
|
14
47
|
}
|
|
15
48
|
|
|
16
|
-
|
|
49
|
+
const scopeDir = path.join(projectRoot, 'node_modules', '@bams-app');
|
|
50
|
+
if (isDirectory(scopeDir)) {
|
|
51
|
+
for (const entry of fs.readdirSync(scopeDir, { withFileTypes: true })) {
|
|
52
|
+
if (entry.name.startsWith('.')) {
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
addApp(entry.name, path.join(scopeDir, entry.name));
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return apps;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/** 解析应用目录:项目内 apps/<name> 优先,回退 node_modules/@bams-app/<name> */
|
|
63
|
+
function resolveAppDir(projectRoot, name) {
|
|
64
|
+
const shortName = toShortName(name);
|
|
65
|
+
const packageName = name.startsWith('@') ? name : `@bams-app/${name}`;
|
|
66
|
+
|
|
67
|
+
const internal = path.join(projectRoot, 'apps', shortName);
|
|
68
|
+
if (isAppDir(internal)) {
|
|
69
|
+
return { dir: internal, source: '项目内 apps/' };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
try {
|
|
73
|
+
const pkgPath = require.resolve(`${packageName}/package.json`, { paths: [projectRoot] });
|
|
74
|
+
const dir = path.dirname(pkgPath);
|
|
75
|
+
if (isAppDir(dir)) {
|
|
76
|
+
return { dir, source: '依赖包 node_modules' };
|
|
77
|
+
}
|
|
78
|
+
} catch (err) {
|
|
79
|
+
// 未安装该包,交由调用方提示
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** 环境标识/路径 -> env 文件(默认 .envs/.env.production) */
|
|
86
|
+
function resolveEnvFile(projectRoot, envInput) {
|
|
87
|
+
if (!envInput) {
|
|
88
|
+
return { filePath: path.join(projectRoot, '.envs', '.env.production') };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const isPathLike = envInput.includes('/')
|
|
92
|
+
|| envInput.includes('\\')
|
|
93
|
+
|| path.basename(envInput).startsWith('.env');
|
|
94
|
+
|
|
95
|
+
if (isPathLike) {
|
|
96
|
+
return { filePath: path.resolve(projectRoot, envInput) };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const fileName = envInput === 'production' ? '.env.production' : `.env.dev-${envInput}`;
|
|
100
|
+
return { filePath: path.join(projectRoot, '.envs', fileName) };
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** 复用 @bams-app/shared-env 的 env-loader 加载环境变量(含应用私有 .env.<mode> 覆盖) */
|
|
104
|
+
function loadEnvVars(appDir, envFilePath) {
|
|
105
|
+
let loadEnv;
|
|
106
|
+
try {
|
|
107
|
+
({ loadEnv } = require(require.resolve('@bams-app/shared-env/lib/env-loader', { paths: [appDir, path.dirname(envFilePath)] })));
|
|
108
|
+
} catch (err) {
|
|
109
|
+
warn('未安装 @bams-app/shared-env,跳过环境文件加载');
|
|
110
|
+
return { ...process.env };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return loadEnv(appDir, envFilePath);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function parseArgs(args) {
|
|
117
|
+
let app = '';
|
|
118
|
+
let envInput = '';
|
|
17
119
|
let serviceArgs = [];
|
|
18
120
|
let i = 0;
|
|
19
121
|
|
|
@@ -22,54 +124,99 @@ async function main(args) {
|
|
|
22
124
|
if (arg === '--') {
|
|
23
125
|
serviceArgs = args.slice(i + 1);
|
|
24
126
|
break;
|
|
25
|
-
} else if (arg === '--
|
|
26
|
-
|
|
127
|
+
} else if (arg === '--env' || arg === '-e') {
|
|
128
|
+
envInput = args[i + 1] || '';
|
|
27
129
|
i += 2;
|
|
28
|
-
} else if (arg.startsWith('--')) {
|
|
130
|
+
} else if (arg.startsWith('--env=')) {
|
|
131
|
+
envInput = arg.slice('--env='.length);
|
|
132
|
+
i++;
|
|
133
|
+
} else if (arg.startsWith('-')) {
|
|
29
134
|
serviceArgs = args.slice(i);
|
|
30
135
|
break;
|
|
31
|
-
} else if (!
|
|
32
|
-
|
|
136
|
+
} else if (!app) {
|
|
137
|
+
app = arg;
|
|
138
|
+
i++;
|
|
33
139
|
} else {
|
|
34
140
|
serviceArgs = args.slice(i);
|
|
35
141
|
break;
|
|
36
142
|
}
|
|
37
|
-
i++;
|
|
38
143
|
}
|
|
39
144
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
error('
|
|
145
|
+
return { app, envInput, serviceArgs };
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
async function main(args) {
|
|
149
|
+
const projectRoot = findProjectRoot(process.cwd());
|
|
150
|
+
if (!projectRoot) {
|
|
151
|
+
error('未找到 BAMS-Work 项目(缺少 .bams-work 目录),请先执行 work create <name>');
|
|
152
|
+
process.exit(1);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
let { app, envInput, serviceArgs } = parseArgs(args);
|
|
156
|
+
|
|
157
|
+
const available = listAvailableApps(projectRoot);
|
|
158
|
+
const printAvailable = () => {
|
|
159
|
+
if (!available.length) {
|
|
160
|
+
error('当前项目未发现可打包应用(需 apps/<app> 或 node_modules/@bams-app/<app>,且含 vue.config.js)');
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
log('可用应用:');
|
|
164
|
+
available.forEach((item) => log(` - ${item.name}`));
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
if (!app) {
|
|
168
|
+
if (available.length === 1) {
|
|
169
|
+
app = available[0].name;
|
|
170
|
+
} else {
|
|
171
|
+
error('请指定要打包的应用: work build <app>');
|
|
172
|
+
printAvailable();
|
|
173
|
+
process.exit(1);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const resolved = resolveAppDir(projectRoot, app);
|
|
178
|
+
if (!resolved) {
|
|
179
|
+
error(`未找到应用: ${app}`);
|
|
180
|
+
printAvailable();
|
|
47
181
|
process.exit(1);
|
|
48
182
|
}
|
|
49
183
|
|
|
50
|
-
|
|
51
|
-
|
|
184
|
+
const appDir = resolved.dir;
|
|
185
|
+
const appName = toShortName(app);
|
|
52
186
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
187
|
+
let vueCliService;
|
|
188
|
+
try {
|
|
189
|
+
vueCliService = require.resolve('@vue/cli-service/bin/vue-cli-service.js', { paths: [appDir, projectRoot] });
|
|
190
|
+
} catch (err) {
|
|
191
|
+
error('未找到 @vue/cli-service,请先在项目根执行 npm install');
|
|
192
|
+
process.exit(1);
|
|
56
193
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
process.execPath,
|
|
67
|
-
[sharedEnvBin, '--project', '.', '--env', prodEnvFile, '--', ...uiArgs],
|
|
68
|
-
{ cwd: projectRoot, env }
|
|
69
|
-
);
|
|
194
|
+
|
|
195
|
+
const { filePath: envFilePath } = resolveEnvFile(projectRoot, envInput);
|
|
196
|
+
let env;
|
|
197
|
+
if (fs.existsSync(envFilePath)) {
|
|
198
|
+
env = loadEnvVars(appDir, envFilePath);
|
|
199
|
+
info(`环境文件: ${path.relative(projectRoot, envFilePath)}`);
|
|
200
|
+
} else if (envInput) {
|
|
201
|
+
error(`环境文件不存在: ${path.relative(projectRoot, envFilePath)}`);
|
|
202
|
+
process.exit(1);
|
|
70
203
|
} else {
|
|
71
|
-
|
|
204
|
+
warn(`未找到 ${path.relative(projectRoot, envFilePath)},将使用当前进程环境`);
|
|
205
|
+
env = { ...process.env };
|
|
72
206
|
}
|
|
207
|
+
env.WORK_PROJECT_ROOT = projectRoot;
|
|
208
|
+
env.NODE_ENV = 'production';
|
|
209
|
+
|
|
210
|
+
info(`打包应用: ${appName}(来源: ${resolved.source})`);
|
|
211
|
+
info(`应用目录: ${appDir}`);
|
|
212
|
+
if (serviceArgs.length) {
|
|
213
|
+
info(`vue-cli 参数: ${serviceArgs.join(' ')}`);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const code = await run(process.execPath, [vueCliService, 'build', ...serviceArgs], {
|
|
217
|
+
cwd: appDir,
|
|
218
|
+
env
|
|
219
|
+
});
|
|
73
220
|
process.exit(code);
|
|
74
221
|
}
|
|
75
222
|
|
package/package.json
CHANGED
|
@@ -12,13 +12,20 @@
|
|
|
12
12
|
],
|
|
13
13
|
"scripts": {
|
|
14
14
|
"dev:ui": "ui-dev-server",
|
|
15
|
+
"build": "work build",
|
|
16
|
+
"build:bams-app": "work build bams-app",
|
|
17
|
+
"build:project-startr": "work build project-startr",
|
|
18
|
+
"build:touch-startr": "work build touch-startr",
|
|
15
19
|
"add:component": "work add",
|
|
16
20
|
"create:env": "work env",
|
|
17
21
|
"sync:skills": "work skills sync",
|
|
18
22
|
"postinstall": "work skills sync --quiet || exit 0"
|
|
19
23
|
},
|
|
20
24
|
"dependencies": {
|
|
21
|
-
"@bams-app/bams-
|
|
25
|
+
"@bams-app/bams-app": "*",
|
|
26
|
+
"@bams-app/bams-components": "*",
|
|
27
|
+
"@bams-app/project-startr": "*",
|
|
28
|
+
"@bams-app/touch-startr": "*"
|
|
22
29
|
},
|
|
23
30
|
"devDependencies": {
|
|
24
31
|
"@bams-app/ui-dev-server": "*"
|