Skip to content

Commit

Permalink
docs: 添加文档《MorJS 使用社区组件库指南》 (#48)
Browse files Browse the repository at this point in the history
* docs: 添加文档《MorJS 使用社区组件库指南》

* docs: 添加如何编写一个多端组件库的教程
  • Loading branch information
BboyZaki committed Jun 1, 2023
1 parent 30413b9 commit 388e728
Show file tree
Hide file tree
Showing 3 changed files with 331 additions and 1 deletion.
6 changes: 5 additions & 1 deletion website/config/sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,11 @@ module.exports = {
label: 'MorJS 开发博客',
type: 'category',
collapsed: false,
items: ['guides/advance/subpackage-volume-optimization']
items: [
'guides/advance/use-community-component',
'guides/advance/learn-create-component-library',
'guides/advance/subpackage-volume-optimization'
]
}
// {
// label: 'MorJS 更新日志',
Expand Down
166 changes: 166 additions & 0 deletions website/docs/guides/advance/learn-create-component-library.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
# 五分钟教会你如何让小程序组件库支持多端

## 背景

上文 [《MorJS 使用社区组件库指南》](https://mor.eleme.io/guides/advance/use-community-component) 我们提到了 MorJS 能够支持在业务转端的同时,将业务所引用的社区组件库一同转端,而针对很多定制属性较强的项目,大多会自行维护一套组件库提供给多个项目使用,本文教会你如何让你的小程序组件库支持多端,与上文的区别在于:

- 上文是将社区组件库作为源码的一部分,通过 MorJS 编译业务代码的同时,将 node_modules 中的组件也作为源码编译的一部分,生成能够在不同端运行的产物;
- 本文是将小程序组件库单独编译,生成能够分别在不同端引入使用的组件进行发包,支持不同项目自行引用 npm 包,组件库与业务、框架解耦;

## 已有组件库快速上手

组件库转端需要使用 MorJS 提供的一码多端能力,总体流程为:

项目接入 MorJS => 添加多端编译配置 => 配置脚本 => 编译构建生成产物 => 发包

### 接入 MorJS

在组件库项目中添加必要的依赖:

```shell
$ npm i @morjs/cli -D && npm i @morjs/core --save
```

### 添加配置文件

在项目根目录下增加文件 mor.config.ts,修改需要编译的配置

```typescript
import { defineConfig, UserConfig } from '@morjs/cli'

// 公共配置
const CommonConfig: UserConfig = {
sourceType: 'wechat', // 源码类型: 微信 DSL
srcPath: './src/components', // 源码目录,指定组件库源代码所在的目录
compileMode: 'default', // 编译模式,由于组件库不是完整项目,需使用转换模式编译
autoInjectRuntime: {
// 运行时自动注入配置
api: 'minimal' // API 运行时抹平注入,使用最小替换将仅替换函数调用
},
compilerOptions: {
// ts 编译配置
esModuleInterop: false, // 开启 ES 模块互操作性,针对 ES Module 提供 Commonjs 兼容
declaration: true, // 生成 (.d.ts) 文件
target: 'ES5', // 输出的 ES 版本
module: 'CommonJS' // 模块输出类型
}
}

export default defineConfig([
// 第一套配置: 微信 DSL 编译
{
...CommonConfig,
name: 'wx',
target: 'wechat', // 编译目标: 微信
outputPath: './miniprogram_dist/lib' // 输出产物目录
},
// 第二套配置: 微信转支付宝
{
...CommonConfig,
name: 'ali',
target: 'alipay', // 编译目标: 支付宝
outputPath: './alipay/lib' // 输出产物目录
},
// 第三套配置: 微信转抖音
{
...CommonConfig,
name: 'dy',
target: 'bytedance', // 编译目标: 抖音
outputPath: './bytedance/lib' // 输出产物目录
},
// 第四套配置: 微信转 Web
{
...CommonConfig,
name: 'web',
target: 'web', // 编译目标: Web
outputPath: './lib' // 输出产物目录
}
])
```

### 编译调试

在项目目录终端下执行编译命令启动项目,即可构建生成对应的多端产物,分别用对应平台的 IDE 打开即可开发预览。

你也可以针对不同端,在 package.json 中添加单端的编译命令和相关配置,在终端执行对应的编译命令生成单端的编译产物进行开发调试。

相关文档可参考:[《MorJS 基础用法 - 命令行》](https://mor.eleme.io/guides/basic/cli)

```json
{
"name": "my-component",
"version": "1.0.0",
"scripts": {
"build": "mor compile --production", // 开启生产环境构建所有端
"dev:wx": "mor compile --name wx", // 编译构建配置名为 wx 的产物
"dev:ali": "mor compile --name ali --production", // 编译构建配置名为 ali 的产物
"dev:dy": "mor compile --name dy --production" // 编译构建配置名为 dy 的产物
}
}
```

### 构建发包

在项目目录终端执行打包构建命令编译项目,生成对应的多端产物,产物目录取决与配置文件各端的 outputPath 配置,该目录需要和 package.json 中多端适配输出目录一致。

相关文档可参考:[《MorJS - 多端组件库规范》](https://mor.eleme.io/specifications/component)

```json
{
"name": "my-component",
"version": "1.0.0",
// 缺省目录设置,未指定端的小程序组件文件会从该目录下获取,
"main": "lib",
// 微信小程序的入口配置
"miniprogram": "miniprogram_dist",
// 支付宝小程序的入口配置
"alipay": "alipay",
// 字节小程序的入口配置
"bytedance": "bytedance",
// 建议配置只输出组件内容目录
"files": ["lib", "miniprogram_dist", "alipay", "bytedance"]
}
```

修改 package.json 的包名 name 和版本号 version,运行 `npm publish` 进行发包。

## 开始一个新组件库项目

如果你还没有开始写组件库,想要重新开始一个新的多端组件库项目,欢迎你使用官方脚手架工具来创建新项目:

1. 选定项目目录,并在目录终端执行以下任一命令:

```shell
$ npm init mor # npm 创建项目
$ yarn create mor # yarn 创建项目
$ pnpm create mor # pnpm 创建项目
```

2. 选择工程类型 MorJS 多端组件库,按照提示完成初始化操作

```shell
✔ 请选择工程类型 › MorJS 多端组件库
✔ 请选择源码类型 › 微信小程序 DSL
✔ 请输入 小程序 的名称 … my-components
✔ 请输入 小程序 的描述 … my first components
✔ 用户名 … yourUserName
✔ 邮箱 … [email protected]
✔ 请输入 Git 仓库地址 … https://github.com/yourUserName/myapp
✔ 请选择 npm 客户端 › npm / pnpm / yarn
```

3. 编译与调试,在终端运行 `tnpm run dev`,将生成的产物用各端对应的 IDE 打开进行预览调试

4. 构建与发包,在终端运行 `tnpm run build`,生成对应各端的小程序产物,修改 package.json 的包名 name 和版本号 version,运行 `npm publish` 进行发包

## Q&A

- Q: 转端过程中,发现小程序的 JSAPI 转端后不兼容怎么办?
- A: 修改 mor.config.ts 中的 autoInjectRuntime.api 配置,默认 minimal 时只做最小替换,设置为 true 或 enhanced 时,MorJS 会接管 JSAPI 调用并提供接口兼容支持

- Q: 个别情况下,组件转端表现不一致该怎么办?
- A: 各个小程序平台的兼容性问题,超出多端编译覆盖范围的,需要自行处理,可考虑使用条件编译进行分端兼容

- Q: 组件库中使用的字体资源文件会被一同编译吗?
- A: 会,Mor 编译时,针对业务的静态资源会全部拷过去,不依赖构建关系
160 changes: 160 additions & 0 deletions website/docs/guides/advance/use-community-component.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
# MorJS 使用社区组件库指南

## 背景

距离 MorJS 开源已经有一段时间了,随着使用人数的上升,较多开发者将现有小程序项目接入 MorJS 框架都会提出一个疑问,项目中除了开发同学写的原生业务代码外,很多项目还用到了第三方的组件库,这些社区组件库能够被一同转成其他小程序端么?

答案是:可以,只要是(微信/支付宝)小程序原生开发的组件,理论上是可以一并转换的,使用方式上,需按照对应平台 npm 组件的规范 来使用,本次我们将分别对使用到社群中提及频率较高的 [Vant Weapp](https://github.com/youzan/vant-weapp)[TDesign](https://github.com/Tencent/tdesign-miniprogram)[Wux Weapp](https://github.com/wux-weapp/wux-weapp/) 的项目进行转端(如果你的项目选用的是其他组件库,也可以参考以下流程)

## 一. 项目接入 MorJS

使用 MorJS 提供的一码多端能力,自然需要用到 MorJS 本身,我们针对不同业务场景,提供了两种接入方式:

- 新项目使用 create-mor 创建项目,文档参考:[《MorJS - 快速上手》](https://mor.eleme.io/guides/introduction/getting-started)
- 已有项目添加必要依赖进行接入,文档参考:[《MorJS - 原生小程序接入》](https://mor.eleme.io/guides/migrate-from-original-miniprogram-to-mor)

完成以上接入后,可在项目目录终端下执行编译命令启动项目 npm run dev,多端产物已构建在 dist 目录下,分别用对应平台的 IDE 打开即可开发预览。

```
.
├── dist // 产物目录,可在 mor.config.* 中通过 outputPath 配置进行修改
│ ├── alipay // 支付宝端产物,可在用支付宝 IDE 进行预览调试
│ ├── wechat // 微信端产物,可在用微信 IDE 进行预览调试
│ └── web // 转 web 产物,可在浏览器中进行预览调试
├── node_modules // 安装 node 后用来存放用包管理工具下载安装的包的文件夹
├── src // 源码目录,可在 mor.config.* 中通过 srcPath 配置进行修改
├── mor.config.ts // MorJS 配置文件,用于提供多套编译配置
└── package.json // 项目的基础配置文件
```

## 二. 项目接入社区组件库

根据对应的社区组件库文档进行接入,如果你的项目选用的是其他组件库,也可以参考以下流程进行接入。

请注意,项目所使用的组件库和项目的小程序 DSL 需要为同一套源码,例如选择使用微信 DSL 写的项目,引入的组件库需要是 for 微信小程序的组件库,支付宝 DSL 亦然。

### 接入 [Vant Weapp](https://github.com/youzan/vant-weapp) 流程

1. 安装:通过 npm 安装组件库 `npm i @vant/weapp -S --production`
2. 配置:MorJS 工程默认配置下,可直接跳过这步

- app.json 配置:小程序新版组件库与 [Vant Weapp](https://github.com/youzan/vant-weapp) 可能存在一定样式冲突问题,请根据业务需求及项目表现,自行决定是否需要去除新版基础组件样式,如需去除删除 app.json 文件的 `"style": "v2"` 配置项即可
- project.config.json 配置:MorJS 默认的 bundle 模式无需修改此项配置
- 构建 npm 包:MorJS 默认的 bundle 模式无需构建此项
- typescript 支持:MorJS 本身支持 typescript,无需配置此项

3. 使用:在对应的 json 文件中配置所用组件对应的路径,在 xml 中直接使用组件即可

> 配置组件路径有两种方式:可以按照 组件库规范 来引用组件,或按照实际路径引用组件
```json
{
"usingComponents": {
"van-button": "@vant/weapp/button/index", // 按照规范引用 button 组件
"van-popup": "@vant/weapp/lib/popup/index" // 按照实际路径引用 popup 组件
}
}
```

### 接入 [TDesign](https://github.com/Tencent/tdesign-miniprogram) 流程

1. 安装:通过 npm 安装组件库 `npm i tdesign-miniprogram -S --production`
2. 配置:MorJS 工程默认配置下,可直接跳过这步

- app.json 配置:小程序新版组件库与 [TDesign](https://github.com/Tencent/tdesign-miniprogram) 可能存在一定样式冲突问题,请根据业务需求及项目表现,自行决定是否需要去除新版基础组件样式,如需去除删除 app.json 文件的 `"style": "v2"` 配置项即可
- 构建 npm 包:MorJS 默认的 bundle 模式无需构建此项
- typescript 支持:MorJS 本身支持 typescript,无需配置此项

3. 使用:在对应的 json 文件中配置所用组件对应的路径,在 xml 中直接使用组件即可

> 配置组件路径有两种方式:可以按照 组件库规范 来引用组件,或按照实际路径引用组件
```json
{
"usingComponents": {
"van-button": "tdesign-miniprogram/button/button", // 按照规范引用 button 组件
"van-popup": "tdesign-miniprogram/miniprogram_dist/popup/popup" // 按照实际路径引用 popup 组件
}
}
```

### 接入 [Wux Weapp](https://github.com/wux-weapp/wux-weapp/) 流程

1. 安装:通过 npm 安装组件库 `npm i wux-weapp -S --production`
2. 配置:MorJS 工程默认配置下,无需进行 npm 构建或单独拷贝组件产物
3. 使用:在对应的 json 文件中配置所用组件对应的路径,在 xml 中直接使用组件即可

> 配置组件路径有两种方式:可以按照 组件库规范 来引用组件,或按照实际路径引用组件
```json
{
"usingComponents": {
"van-button": "wux-weapp/button/index", // 按照规范引用 button 组件
"van-popup": "wux-weapp/packages/lib/popup/index" // 按照实际路径引用 popup 组件
}
}
```

## 三. 添加组件库转端配置

接入社区组件库后,执行编译命令 npm run dev 启动项目会发现,仅本端的编译是正常执行的,转为其他端的编译会报类似 Can't resolve 'xxx' in 'xxx' 的错误,这是因为 MorJS 默认是不会在编译环节动态编译处理 node_modules 的 NPM 组件的,所以导致引入使用的组件无法载入,需要通过添加 mor.config.ts 中的 processNodeModules 配置,让编译环节处理 node_modules 中的组件

相关文档可参考:[《MorJS 基础用法 - 配置 processNodeModules》](https://mor.eleme.io/guides/basic/config/#processnodemodules---%E6%98%AF%E5%90%A6%E5%A4%84%E7%90%86-node_modules)

```typescript
import { defineConfig } from '@morjs/cli'

export default defineConfig([
{
name: 'ali',
sourceType: 'wechat', // 源码类型: 微信 DSL
target: 'alipay', // 编译目标: 支付宝小程序
processNodeModules: {
include: [
/@vant\/weapp/, // 添加处理 @vant/weapp 组件
/tdesign\-miniprogram/, // 添加处理 tdesign-miniprogram 组件
/wux\-weapp/ // 添加处理符合 wux-weapp 组件
]
}
}
])
```

> 之所以 MorJS 编译默认不处理 node_modules 的 NPM 组件,原因大致有以下几点:
- 动态编译性能差:node_modules 里面文件繁多,需要所有文件都去判断是否需要进行编译处理,效率较低,会一定程度上影响编译效率;
- 排查问题困难:动态转换会变成黑箱,使用方无法直接感知到转换过程中所做的处理;
- 无法直接给原生小程序复用:组件在满足一定条件下,是可以同时给非 MorJS 的小程序工程使用的,如果采用动态编译就能且只能给 MorJS 工程使用;
- 降低了组件提供方的自测责任:在 NPM 组件 输出时直接提供了编译后产物,能够要求 NPM 组件 做好对应测试,而不是依赖于 MorJS 动态编译来确保可用性;
-

## 四. 编译调试

在项目目录终端下执行编译命令启动项目,即可构建生成对应的多端产物,默认是放在项目 dist 目录下,分别用对应平台的 IDE 打开即可开发预览。

你也可以针对不同端,在 package.json 中添加单端的编译命令和相关配置,在终端执行对应的编译命令生成单端的编译产物进行开发调试。

相关文档可参考:[《MorJS 基础用法 - 命令行》](https://mor.eleme.io/guides/basic/cli)

```json
{
"scripts": {
"dev": "mor compile -w", // 编译构建所有端并开启文件变更监听
"dev:ali": "mor compile --name ali", // 编译构建配置名为 ali 的产物
"dev:wx": "mor compile --name wx", // 编译构建配置名为 wx 的产物
"dev:dy": "mor compile --name dy", // 编译构建配置名为 dy 的产物
"build": "mor compile --production" // 开启生产环境构建所有端
}
}
```

## Q&A

- Q: 为什么 MorJS 接入组件库不需要执行 IDE 构建 npm 包?
- A: 默认的 bundle 打包模式下,MorJS 会生成闭包并基于规则合并 js 文件,同时将小程序多端组件自动提取到产物对应的 npm_components 目录,但如果 compileMode 配置的是 transform 模式,会因为该编译模式下并不处理 node_modules 和多端组件,所以得走常规的微信构建 npm

- Q: 为什么我按照规范(xxx/button/index)引用组件转其他端会报 Can't resolve 'xxx' in 'xxx' 的错误?
- A: MorJS 是通过目录结构结合 package.json 的 [目录指向字段配置](https://mor.eleme.io/specifications/component#%E7%9B%AE%E5%BD%95%E5%AD%97%E6%AE%B5%E9%85%8D%E7%BD%AE) 来实现的,若转端读取的字段入口对应目录下没有组件产物,编译引入组件时将报上述错误,可以把使用路径改为组件实际路径,或联系组件开发者补充 main 入口字段

- Q: 社区组件库中使用的字体资源文件会被一同编译吗?
- A: 不会,针对 node_modules 中的非预期文件类型不会进行处理,请把资源文件改为引用 cdn 资源

0 comments on commit 388e728

Please sign in to comment.