|
8 | 8 | - **Hooks API** — `useState`、`useEffect`、`useContext`、`usePageEvent`、`useAppEvent` 等 React 风格 Hooks |
9 | 9 | - **API Promise 化** — 内置 `promisify` 工具函数,将小程序回调 API 转换为 Promise,支持 async/await |
10 | 10 | - **两种编程范式** — 支持函数式组件(Hooks)和 Options API(传统小程序 Page/Component 配置) |
| 11 | +- **环境变量注入(编译时替换)** — 零依赖、无运行时开销;支持 `.env` 文件、系统 `RSMAX_*` 环境变量、`rsmax.config.js` 的 `define` 三层来源,`process.env.XXX` 编译时替换为字面量 |
11 | 12 | - **CSS Modules** — `.module.less` / `.module.css` / `.module.scss` 自动局部作用域,class 名自动 hash |
12 | 13 | - **样式预处理** — 内置 Less/Sass 支持,px 自动转 rpx(1px → 1rpx,按 750rpx 设计稿) |
13 | 14 | - **第三方 UI 库** — 自动识别并注册 Vant Weapp、TDesign MiniProgram、Ant Design Mini 组件 |
@@ -88,25 +89,47 @@ your-project/ |
88 | 89 | ### build — 构建项目 |
89 | 90 |
|
90 | 91 | ```bash |
91 | | -rsmax build <source> -o <output> |
| 92 | +rsmax build <source> -o <output> [-m, --mode <mode>] |
92 | 93 | ``` |
93 | 94 |
|
94 | 95 | 将源码编译输出到 dist 目录。编译前会清空输出目录,但保留 `miniprogram_npm`。 |
95 | 96 |
|
| 97 | +**选项:** |
| 98 | + |
| 99 | +| 参数 | 别名 | 说明 | 默认值 | |
| 100 | +|------|------|------|--------| |
| 101 | +| `-o, --output <output>` | - | 输出目录 | `dist` | |
| 102 | +| `-m, --mode <mode>` | - | 环境模式(development/production/test 等任意自定义),决定加载的 `.env.<mode>` 文件和注入的 `process.env.NODE_ENV/MODE` 值 | `production` | |
| 103 | + |
96 | 104 | ```bash |
| 105 | +# 生产环境构建(默认) |
97 | 106 | rsmax build src -o dist |
| 107 | + |
| 108 | +# 预发环境构建 |
| 109 | +rsmax build src -o dist -m staging |
98 | 110 | ``` |
99 | 111 |
|
100 | 112 | ### dev — 开发模式(监听) |
101 | 113 |
|
102 | 114 | ```bash |
103 | | -rsmax dev <source> -o <output> |
| 115 | +rsmax dev <source> -o <output> [-m, --mode <mode>] |
104 | 116 | ``` |
105 | 117 |
|
106 | 118 | 监听源文件变化,增量编译。 |
107 | 119 |
|
| 120 | +**选项:** |
| 121 | + |
| 122 | +| 参数 | 别名 | 说明 | 默认值 | |
| 123 | +|------|------|------|--------| |
| 124 | +| `-o, --output <output>` | - | 输出目录 | `dist` | |
| 125 | +| `-m, --mode <mode>` | - | 环境模式,决定加载的 `.env.<mode>` 文件 | `development` | |
| 126 | + |
108 | 127 | ```bash |
| 128 | +# 开发模式(默认 mode=development) |
109 | 129 | rsmax dev src -o dist |
| 130 | + |
| 131 | +# 开发模式 + 使用预发环境接口 |
| 132 | +rsmax dev src -o dist --mode staging |
110 | 133 | ``` |
111 | 134 |
|
112 | 135 | ### clean — 清理输出目录 |
@@ -269,6 +292,223 @@ export default function Detail() { |
269 | 292 | | 独立分包页面 | 分包根目录(独立拷贝) | `../../rsmax-runtime.js`(回溯到分包根) | |
270 | 293 | | 分包内组件 | 与同包页面一致 | 根据所在包自动计算 | |
271 | 294 |
|
| 295 | +## 环境变量注入(编译时 Define 替换) |
| 296 | + |
| 297 | +Rsmax 提供**零依赖、无运行时开销**的轻量级变量注入方案。所有 `process.env.XXX` 在**编译阶段被静态替换为字面量**,小程序运行时无需加载 Dotenv 等任何库,打包体积和运行时性能均零损耗。 |
| 298 | + |
| 299 | +> 设计原则:编译时静态替换(类似 Vite 的 `import.meta.env` / Webpack 的 `DefinePlugin`),不是运行时读取。 |
| 300 | +
|
| 301 | +### 三层变量来源(优先级从低到高) |
| 302 | + |
| 303 | +``` |
| 304 | +优先级 1(最低) .env 文件(4 种类型,按加载顺序依次覆盖) |
| 305 | + │ |
| 306 | +优先级 2 系统环境变量(RSMAX_ 前缀 + 白名单 NODE_ENV/ENV/MODE) |
| 307 | + │ |
| 308 | +优先级 3(最高) rsmax.config.js 中的 define 配置 |
| 309 | +``` |
| 310 | + |
| 311 | +> **注意**:CLI 的 `--mode` 参数会强制注入 `process.env.NODE_ENV` 和 `process.env.MODE`,优先级高于 `.env` 文件和系统环境变量,但低于 `define` 配置(即 `define` 可以覆盖一切)。 |
| 312 | +
|
| 313 | +### 第一层:.env 文件(4 种,支持覆盖链) |
| 314 | + |
| 315 | +在项目根目录(与 `rsmax.config.js` 同级)创建 `.env` 系列文件,支持 4 种加载类型(后者覆盖前者): |
| 316 | + |
| 317 | +| 文件名 | 说明 | 何时加载 | |
| 318 | +|--------|------|----------| |
| 319 | +| `.env` | **默认**配置,所有环境都会加载 | 始终加载 | |
| 320 | +| `.env.local` | **本地个人**覆盖,不应提交到 git | 始终加载(优先级高于 `.env`) | |
| 321 | +| `.env.<mode>` | **指定环境**的配置(如 `.env.production`) | 当 `--mode <mode>` 匹配时加载 | |
| 322 | +| `.env.<mode>.local` | **指定环境的本地个人**覆盖 | 当 `--mode <mode>` 匹配时加载(优先级最高) | |
| 323 | + |
| 324 | +`.env` 文件语法兼容 Dotenv 主流用法: |
| 325 | + |
| 326 | +```dotenv |
| 327 | +# 简单键值对 |
| 328 | +API_BASE=https://api.example.com |
| 329 | +APP_NAME=我的小程序 |
| 330 | +
|
| 331 | +# 支持引号包裹(单/双引号都可以),包含空格或特殊字符时推荐 |
| 332 | +MOTTO="Hello World" |
| 333 | +SECRET_KEY='abc123' |
| 334 | +
|
| 335 | +# 支持 export 前缀(可与 shell source 命令兼容) |
| 336 | +export DEBUG=true |
| 337 | +
|
| 338 | +# 支持 ${VAR} 和 $VAR 引用同一文件中前面的变量 |
| 339 | +HOST=localhost |
| 340 | +PORT=8080 |
| 341 | +BASE_URL=http://${HOST}:${PORT} |
| 342 | +FULL_URL=$BASE_URL/api |
| 343 | +
|
| 344 | +# 井号开头的行为注释(注释不能出现在行首以外除非前面有空格) |
| 345 | +APP_TITLE=测试应用 # 这是行尾注释 |
| 346 | +``` |
| 347 | + |
| 348 | +示例项目结构: |
| 349 | + |
| 350 | +``` |
| 351 | +your-project/ |
| 352 | +├── .env # 公共默认 |
| 353 | +├── .env.local # 本地个人覆盖(建议加入 .gitignore) |
| 354 | +├── .env.development # 开发环境 |
| 355 | +├── .env.development.local # 开发环境本地私钥 |
| 356 | +├── .env.production # 生产环境 |
| 357 | +├── .env.staging # 预发环境 |
| 358 | +├── src/ |
| 359 | +└── rsmax.config.js |
| 360 | +``` |
| 361 | + |
| 362 | +### 第二层:系统环境变量 |
| 363 | + |
| 364 | +系统环境变量在编译时从 `process.env` 读取,**仅以下两类会被注入**(避免将无关的系统变量意外注入到小程序包): |
| 365 | + |
| 366 | +1. **`RSMAX_` 前缀** — 所有以 `RSMAX_` 开头的变量名会被原样注入(包含前缀): |
| 367 | + ```bash |
| 368 | + # 例:CI/CD 脚本中设置 |
| 369 | + RSMAX_DEPLOY_VERSION=$(git rev-parse --short HEAD) |
| 370 | + RSMAX_UPLOAD_TOKEN=xxxxxxxxxxxx |
| 371 | + ``` |
| 372 | + 代码中直接使用 `process.env.RSMAX_DEPLOY_VERSION`、`process.env.RSMAX_UPLOAD_TOKEN`。 |
| 373 | + |
| 374 | +2. **白名单** — `NODE_ENV`、`ENV`、`MODE` 三个常用变量(不带前缀也可注入)。 |
| 375 | + |
| 376 | +> 提示:为避免命名冲突和安全泄漏,推荐始终使用 `RSMAX_` 前缀(除 `NODE_ENV/MODE` 外)。 |
| 377 | +
|
| 378 | +### 第三层(最高优先级):rsmax.config.js 的 define 配置 |
| 379 | + |
| 380 | +在项目根目录 `rsmax.config.js` 中通过 `define` 字段注入(或覆盖)任意变量: |
| 381 | + |
| 382 | +```js |
| 383 | +// rsmax.config.js |
| 384 | +module.exports = { |
| 385 | + // 组件映射等其他配置... |
| 386 | + components: { /* ... */ }, |
| 387 | + |
| 388 | + // 编译时 Define 变量(优先级最高,可覆盖 .env 和系统环境变量) |
| 389 | + define: { |
| 390 | + // 支持 string / number / boolean / null / undefined / 可 JSON 序列化的对象数组 |
| 391 | + API_BASE: 'https://api.rsmax.dev', |
| 392 | + TIMEOUT: 10000, |
| 393 | + DEBUG: true, |
| 394 | + ENABLE_MOCK: process.env.CI ? false : true, |
| 395 | + FEATURE_FLAGS: { |
| 396 | + enableNewUserGuide: true, |
| 397 | + enableDarkMode: false |
| 398 | + }, |
| 399 | + // 你甚至可以强制覆盖 NODE_ENV(极少需要) |
| 400 | + // NODE_ENV: 'production' |
| 401 | + } |
| 402 | +}; |
| 403 | +``` |
| 404 | + |
| 405 | +### 在代码中使用(process.env.XXX) |
| 406 | + |
| 407 | +#### 1. 点访问 / 方括号访问(推荐) |
| 408 | + |
| 409 | +```jsx |
| 410 | +// pages/index/index.jsx |
| 411 | +import { useEffect, useState } from '@rsmax/runtime'; |
| 412 | + |
| 413 | +export default function Home() { |
| 414 | + const [userList, setUserList] = useState([]); |
| 415 | + |
| 416 | + useEffect(async () => { |
| 417 | + // 编译时替换为字面量:https://api.example.com/users |
| 418 | + const resp = await wx.request({ |
| 419 | + url: process.env.API_BASE + '/users', |
| 420 | + timeout: process.env.TIMEOUT |
| 421 | + }); |
| 422 | + setUserList(resp.data); |
| 423 | + }, []); |
| 424 | + |
| 425 | + return ( |
| 426 | + <view> |
| 427 | + <text>当前环境:{process.env.NODE_ENV}</text> |
| 428 | + {process.env.DEBUG && <text class="tag-dev">调试模式</text>} |
| 429 | + </view> |
| 430 | + ); |
| 431 | +} |
| 432 | +``` |
| 433 | + |
| 434 | +#### 2. 解构赋值 |
| 435 | + |
| 436 | +```jsx |
| 437 | +const { API_BASE, DEBUG, TIMEOUT } = process.env; |
| 438 | + |
| 439 | +// 解构后 API_BASE / DEBUG / TIMEOUT 都是已替换的字面量常量 |
| 440 | +console.log(API_BASE, DEBUG, TIMEOUT); |
| 441 | +``` |
| 442 | + |
| 443 | +#### 3. 内置的 NODE_ENV / MODE |
| 444 | + |
| 445 | +无论是否配置,`process.env.NODE_ENV` 和 `process.env.MODE` 始终可用: |
| 446 | +- 默认值(未指定时):`dev` 命令为 `development`,`build` 命令为 `production` |
| 447 | +- 运行 `rsmax dev src -m staging` 时,两者都是 `'staging'` |
| 448 | +- 可用于常见的「环境判断」代码: |
| 449 | + ```jsx |
| 450 | + if (process.env.NODE_ENV === 'production') { |
| 451 | + // 生产环境才启用的统计上报 |
| 452 | + wx.reportMonitor('perf_page_load', duration); |
| 453 | + } |
| 454 | + ``` |
| 455 | + |
| 456 | +### 常用场景示例 |
| 457 | + |
| 458 | +**场景:开发/生产接口地址切换** |
| 459 | + |
| 460 | +```dotenv |
| 461 | +# .env.development(开发环境) |
| 462 | +API_BASE=https://dev-api.example.com |
| 463 | +DEBUG=true |
| 464 | +MOCK_ENABLED=true |
| 465 | +``` |
| 466 | + |
| 467 | +```dotenv |
| 468 | +# .env.production(生产环境) |
| 469 | +API_BASE=https://api.example.com |
| 470 | +DEBUG=false |
| 471 | +MOCK_ENABLED=false |
| 472 | +``` |
| 473 | + |
| 474 | +```bash |
| 475 | +# 开发模式 → 自动加载 .env + .env.development + 对应 local 文件 |
| 476 | +rsmax dev src -o dist |
| 477 | + |
| 478 | +# 生产构建 → 自动加载 .env + .env.production + 对应 local 文件 |
| 479 | +rsmax build src -o dist |
| 480 | +``` |
| 481 | + |
| 482 | +**场景:CI/CD 中注入版本号** |
| 483 | + |
| 484 | +```bash |
| 485 | +# Jenkins / GitHub Actions 等流水线脚本 |
| 486 | +export RSMAX_BUILD_VERSION="v$(cat package.json | grep version | head -1 | awk -F: '{print $2}' | sed 's/[\",]//g' | tr -d '[[:space:]]')-$(git rev-parse --short HEAD)" |
| 487 | +rsmax build src -o dist -m production |
| 488 | +``` |
| 489 | + |
| 490 | +代码中直接读取: |
| 491 | +```jsx |
| 492 | +console.log('构建版本:', process.env.RSMAX_BUILD_VERSION); |
| 493 | +// 输出类似:构建版本:v1.2.3-a1b2c3d |
| 494 | +``` |
| 495 | + |
| 496 | +### 注意事项 |
| 497 | + |
| 498 | +1. **纯编译时替换,不支持动态拼接键名**: |
| 499 | + ```jsx |
| 500 | + // ✅ 正确:静态确定的键名 |
| 501 | + const url = process.env.API_BASE; |
| 502 | + |
| 503 | + // ❌ 错误:运行时才知道访问哪个键(无法静态分析,不会被替换) |
| 504 | + const key = 'API_BASE'; |
| 505 | + const url = process.env[key]; // 该表达式不会被替换,会报错 |
| 506 | + ``` |
| 507 | + |
| 508 | +2. **对象/数组字面量会以 `JSON.parse(...)` 形式注入**,性能开销可忽略;如需更轻量可先在 `define` 中扁平化为多个标量。 |
| 509 | + |
| 510 | +3. **不要在代码中注入密码、私钥等超高敏感信息**:编译后的值是**明文**写在产物 JS 文件中的(与所有同类方案一致),任何用户都可以反编译看到。建议仅注入非敏感的配置(接口域名、功能开关、版本号等)。 |
| 511 | + |
272 | 512 | ## Hooks API |
273 | 513 |
|
274 | 514 | ### useState |
|
0 commit comments