Enhanced Wechat App Development Toolkit (微信小程序增强开发工具)
厌倦了不停的对比 taro、wepy 或者 mpvue 的特性,间歇性的踩雷,构建和运行速度慢以及 code once, run everywhere 的幻想。只想给小程序开发插上效率的翅膀 ~
- Async/Await 支持
- Javascript ES2020 语法
- 原生小程序所有功能,无需学习,极易上手
- 微信接口 Promise 化
- 支持安装 NPM 包
- 支持 SCSS(或 LESS) 以及 小于 16k 的 background-image
- 支持 source map, 方便调试
- 添加新页面或新组件无需重启编译
- 允许自定义编译流程
- 自动兼容旧版本手机中的显示样式
- 支持 WXSS 和 SCSS(或 LESS) 混用
- 代码混淆及高度压缩,节省包大小
- Typescript 支持
- 支持转换成 百度 / 字节跳动 / QQ / 支付宝小程序
- 多种小程序开发插件,为小程序开发减负,解放生产力
需要 node 版本 >= 10.13
npm i -g ewa-cli 或者 yarn global add ewa-cli
ewa new your_project_name
注意:使用此方法,请务必对项目代码做好备份!!!
cd your_project_dir && ewa init
运行 npm start 即可启动实时编译
运行 npm run build 即可编译线上版本(相比实时编译而言,去除了 source map 并增加了代码压缩混淆等,体积更小)
上述命令运行成功后,可以看到本地多了个 dist 目录,这个目录里就是生成的小程序相关代码。
使用微信开发者工具选择 dist 目录打开,即可预览项目
├── .ewa 特殊占位目录,用于检查是否为 ewa 项目
├── dist 小程序运行代码目录(该目录由ewa的start 或者 build指令自动编译生成,请不要直接修改该目录下的文件)
├── node_modules 外部依赖库
├── src 代码编写的目录(该目录为使用ewa后的开发目录)
│ ├── components 小程序组件目录
│ ├── pages 小程序页面目录
│ │ ├── index
│ │ │ ├── index.js
│ │ │ ├── index.wxml
│ │ │ └── index.wxss
│ │ └── logs
│ │ ├── logs.js
│ │ ├── logs.json
│ │ ├── logs.wxml
│ │ └── logs.wxss
│ ├── templates 小程序模版目录
│ ├── utils
│ │ └── util.js
│ ├── app.js 小程序入口文件
│ ├── app.json 小程序全局配置文件
│ ├── app.wxss 小程序全局样式文件
│ └── project.config.json 微信开发者工具小程序项目配置文件
├── ewa.config.js ewa 配置文件
├── .gitignore
├── .eslintrc.js eslint 配置
└── package.json
ewa <cmd> [args]
命令:
ewa new <projectName> 创建新的微信小程序项目 [别名: create]
ewa init 在现有的小程序项目中初始化 EWA
ewa start 启动 EWA 小程序项目实时编译 [别名: dev]
ewa build 编译小程序静态文件
ewa clean 清理小程序静态文件
ewa upgrade 升级 EWA 工具
ewa generate <type> <name> 快速生成模版 [别名: g]
选项:
-v, --version 当前版本号 [布尔]
-h, --help 获取使用帮助 [布尔]
ewa start
启动 EWA 小程序项目实时编译
选项:
-v, --version 当前版本号 [布尔]
-h, --help 获取使用帮助 [布尔]
-t, --type 构建目标 `weapp` 或 `swan` 或 `alipay` 或 `tt` 或 `qq`
[字符串] [可选值: "weapp", "swan", "alipay", "tt", "qq"] [默认值: "weapp"]
ewa build
编译小程序静态文件
选项:
-v, --version 当前版本号 [布尔]
-h, --help 获取使用帮助 [布尔]
-t, --type 构建目标 `weapp` 或 `swan` 或 `alipay` 或 `tt` 或 `qq`
[字符串] [可选值: "weapp", "swan", "alipay", "tt", "qq"] [默认值: "weapp"]
ewa generate <type> <name>
快速生成模版
位置:
type 类型 `page` 或 `component` 或 `template`
[字符串] [必需] [可选值: "page", "component", "template"]
name 名称 [字符串] [必需]
选项:
-v, --version 当前版本号 [布尔]
-h, --help 获取使用帮助 [布尔]
-d, --target-dir 目标文件夹,默认为 src,也可以指定为 src 中的某个子目录
[字符串]
-i, --index 生成的文件名称为 [name]/index,默认为 [name]/[name] [布尔]
ewa clean
清理小程序静态文件
选项:
-v, --version 当前版本号 [布尔]
-h, --help 获取使用帮助 [布尔]
-t, --type 构建目标 `weapp` 或 `swan` 或 `alipay` 或 `tt` 或 `qq`
[字符串] [可选值: "weapp", "swan", "alipay", "tt", "qq"] [默认值: "weapp"]
目前 EWA 支持 微信 / 百度 / 字节跳动 / QQ / 支付宝 5个平台的小程序。
只需要基于微信小程序开发,可以通过命令行工具自动构建为不同平台的小程序,具体参见上方的命令行说明。
多端构建的 dist 目录分别为:
微信: dist
百度: dist-swan
字节跳动: dist-tt
QQ: dist-qq
支付宝: dist-alipay
EWA 会提供 process.env.EWA_ENV 和 process.env.NODE_ENV 来辅助开发同学判断多端和不同的开发环境
可以在 .js 或 .ts 文件中直接使用,可选值见下方说明:
process.env.EWA_ENV: 多端支持的环境变量
可选值为 "weapp"、"swan"、"alipay"、"tt"、"qq", 默认是 "weapp"
process.env.NODE_ENV: 开发环境变量
可选值为 "development" 和 "production", 分别对应 ewa start 和 ewa build 命令
// 引入 const { api } = require('ewa'); // 例: Page({ async onLoad() { let { data } = await api.request({ url: 'http://your_api_endpoint' }); } })
在 Page 和 Component 中引入 this.setState(data, callback) 方法, 并根据 data 数据自动 diff 出变更, 减少单次 data 提交的数据量,避免超过小程序 1mb 的限制
- 由于小程序本身的 bug, 当增量更新数组元素的时候, wxml 中无法正确获取到数组元素的 length
// 在 app.js 中引入插件,并初始化 const { enableState } = require('ewa'); // 参数支持: // opts: 参数对象 // debug: 是否开启 debug 模式,支持3种参数: true, 'page', 'component', 默认为 false // component: 是否开启 component 支持, 默认为 true // page: 是否开启 page 支持, 默认为 true // overwriteArrayOnDeleted: 是否在数组发生删除操作是覆盖整个数组 true 或者 false, 默认为 true // autoSync: 是否在 调用 setData 时自动同步 state, 默认为 true; 如果关闭此操作,在同一个页面或组件中混用 setState 或 setData 的时候,可能会导致BUG, 也可以手动调用 this.syncState() 来手动同步 enableState({ debug: true, component: true, page: true, overwriteArrayOnDeleted: true, autoSync: true }); // 上述插件会引入 this.setState 方法,在 Page 和 Component 中均可调用 // setState 方法会自动 diff 并仅提交数据变更 // 例: Page({ data: { a: 1, b: 1, c: { d: 1, e: 1 } } async onLoad() { // 自动 diff 变化 // 相当于 this.setData({ b: 2, 'c.d': 2 }); this.setState({ a: 1, b: 2, c: { d: 2, e: 1 } }); // this.setState 支持使用 promise 来代替回调函数,如 this.setState({ info: { name: 'My Page Title' } }).then(() => { // 数据已更新到视图, 这里写完成视图更新后的逻辑 }); // 同理,这里可以使用 await 来简化 await this.setState({ info: { name: 'My Page Title' } }); // 数据已更新到视图, 这里写完成视图更新后的逻辑 } })
支持设置全局响应式对象, 能够监听对象属性并自动更新到 data 中
// 1. 创建 store: 对任意纯对象调用 createStore 使其响应式化(以 app.js 中 globalData 为例) // app.js 中引入 const { createStore } = require('ewa'); App({ ... globalData: createStore ( // 全局响应式对象 { a: 'old1', b: { c: 'old2' } }, // 可以自定义注入到 Page 或 Component 中的方法和属性,也可以不设置 // 如果设置了自定义的方法和变量 // 那么实际在 Page 或 Component 中引用的时候需要相应的替换成 自定义的名称,示例如下: { $set: 'yourCustomSet', $on: 'yourCustomOn', $emit: 'yourCustomEmit', $off: 'yourCustomOff', $once: 'yourCustomOnce', $watch: 'yourCustomWatch' } ) }) // 2. 改变 globalData 以及全局状态更新(支持嵌套属性和数组下标修改) // pageA.js Page({ data: { a: '', b: { c: '' } } }) onLoad() { App().globalData.a = 'new1' console.log(this.data.a === 'new1') // true App().globalData.b.c = 'new2' console.log(this.data.b.c === 'new2') // true } // 3. 注入全局方法 使用示例: this.$on('test', (val) => { console.log(val) }) // 发射数据变化 this.$emit('test', 'value'); // 使用方法同 this.$on 只会触发一次 this.$once('test', (val) => {}); // 解绑当前实例通过 this.$on(...) 注册的事件 this.$off('test'); // 以上方法适用于 // 1. 页面与页面 // 2. 页面与组件 // 3. 组件与组件 // 注: 所有页面或组件销毁时会自动解绑所有的事件(无需手动调用 `this.$off(...)`) // `this.$set('coinName', '金币')` 更新所有页面和组件 data 中 'coinName' 的值为 '金币'(支持嵌套属性和数组下标修改) // $watch 监听页面或组件 data 中属性 支持监听属性路径形式如 'a[1].b' // 使用示例: Page({ data: { prop: '', obj: { key: '' } }, $watch: { // 方式一 'prop': function(newVal, oldVal) { }, // 方式二 'obj': { handler: function(newVal, oldVal) { }, deep: Boolean, // 深度遍历 immediate: Boolean // 立即触发 } } });
ewa 通过 ewa.config.js 来支持个性化配置。如下所示:
// ewa.config.js module.exports = { // 公用代码库 (node_modules 打包生成的文件)名称,默认为 vendors.js commonModuleName: 'vendors.js', // 通用模块匹配模式,默认为 /[\\/](node_modules|utils|vendor)[\\/].+\.js/ // 如需添加多个文件夹,可自定义正则,如 /[\\/](node_modules|utils|custom_dirname)[\\/].+\.js/ commonModulePattern: /[\\/](node_modules|utils|vendor)[\\/].+\.js/, // 是否简化路径,作用于 page 和 component,如 index/index.wxml=> index.wxml,默认为 false simplifyPath: false, // 文件夹快捷引用 aliasDirs: [ 'apis', 'assets', 'constants', 'utils' ], // 需要拷贝的文件类型 copyFileTypes: [ 'png', 'jpeg', 'jpg', 'gif', 'svg', 'ico' ], // webpack loader 规则 rules: [], // webpack 插件 plugins: [], // 开发环境下是否自动清理无用文件,默认为 true autoCleanUnusedFiles: true, // css 解析器,sass 或者 less,默认为 sass cssParser: 'sass', // 是否开启 hashed module id hashedModuleIds: true, // 是否开启缓存,默认为 true cache: true, // 自定义环境变量, 默认为 ['NODE_ENV', 'EWA_ENV'] customEnvironments: [], // 嫌不够灵活?直接修改 webpack 配置 webpack: function(config) { return config; } };
本项目遵从 Angular Style Commit Message Conventions,更新日志请查阅 Release。
- 可以使用
@来代替 源代码根目录 来引入代码或样式,如const utils = require('@/utils/util') - WXSS 中可以直接编写 SCSS 样式代码
- WXSS 或 SCSS 中引用绝对路径需要在路径前加
~符号,如:@import "~@/assets/styles/common.scss";,具体原因参见: sass-loader ewa build后如果无法正常运行小程序,可检查下是否关闭了微信开发者工具中的ES6 转 ES5和增强编译选项。原因是:ewa 打包时会将 ES6 转换为 ES5 并混淆压缩,此功能和微信开发者工具自带的ES6 转 ES5和增强编译功能有部分重复,多次转换会导致代码无法运行,所以只要关闭即可。- 其他问题欢迎直接在 Github 上提交 issue,也可以添加下方微信反馈(请注明来意 ^_^)