前言
微信小程序支持使用 npm 安装第三方包,但是在使用前,需先构建 npm,这和我们常规的使用方式不太一样。
常规方式:npm install -> 打包编译(webpack)
此外,微信小程序在构建 npm 时也有很多“反常规”的操作,本文将详细介绍如何正确构建 npm 。
使用 npm 包
1.安装 npm 包
在小程序 package.json 所在的目录中执行命令安装 npm 包:
npm install
此处小程序对 package.json 文件所在的目录有要求,默认需要在 project.config.json 定义的 miniprogramRoot 之内。当然,小程序提供自定义规则能力,后文将详细介绍。
根据 package.json 的 dependencies 字段构建,所以声明在 devDependencies 里的包也可以在开发过程中被安装使用而不会参与到构建中。
2.构建 npm
点击开发者工具中的菜单栏:工具 --> 构建 npm
3.使用 npm 包
js 中引入 npm 包
const myPackage = require('packageName')
使用 npm 包中的自定义组件
{
"usingComponents": {
"componentName":"packageName/componentName"
}
}
构建 npm 原理
核心点
- 1.node_modules 目录不会参与编译、上传和打包
- 2.会生成一个 miniprogram_npm 目录,里面会存放构建打包后的 npm 包,也就是小程序真正使用的 npm 包。
- 3.构建打包分为两种:
- 小程序 npm 包会直接拷贝构建文件生成目录(默认为 miniprogram_dist 目录)下的所有文件到 miniprogram_npm 中;(此处涉及小程序 npm 包发布,本文不做介绍,具体参见发布 npm 包)
- 其他 npm 包则会从入口 js 文件开始走一遍依赖分析和打包过程(类似 webpack)。
构建规则
核心就一句话:在每一份 project.config.json/miniprogramRoot 内开发者声明的 package.json 的最外层的 node_modules 的同级目录下会生成一个 miniprogram_npm 目录,里面会存放构建打包后的 npm 包。
虽然只有一句话,但是理解起来并不容易,下面举几个具体的案例来说明。
1.miniprogramRoot 字段不存在
当 miniprogramRoot 字段不存在时,miniprogramRoot 就是 project.config.json 所在的目录。
构建前:
|--node_modules
| |--testComp // 小程序 npm 包
| | |--package.json
| | |--src
| | |--miniprogram_dist
| | |-index.js
| | |-index.json
| | |-index.wxss
| | |-index.wxml
| |--testa // 其他 npm 包
| |--package.json
| |--lib
| | |--entry.js
| |--node_modules
| |--testb
| |--package.json
| |--main.js
|--pages
|--app.js
|--app.wxss
|--app.json
|--project.config.json
构建后:
|--node_modules
|--miniprogram_npm
| |--testComp // 小程序 npm 包
| | |-index.js
| | |-index.json
| | |-index.wxss
| | |-index.wxml
| |--testa // 其他 npm 包
| |--index.js // 打包后的文件
| |--miniprogram_npm
| |--testb
| |--index.js // 打包后的文件
| |--index.js.map
|--pages
|--app.js
|--app.wxss
|--app.json
|--project.config.json
2.默认的构建方式
默认情况下,在 miniprogramRoot 内配置了 package.json 并执行 npm install 之后,其构建 npm 的结果是,为每一个 package.json 对应的 node_modules 构建一份 miniprogram_npm,并放置在对应 package.json 所在目录的子目录中。
构建前:
├── miniprogram
│ ├── app.js
│ ├── app.json
│ ├── app.wxss
│ ├── index
│ │ ├── 略
│ ├── node_modules // 可被默认方式构建 npm,因为它在 miniprogramRoot 内
│ ├── package.json
│ └── sub_package
│ ├── node_modules // 可被默认方式构建 npm,因为它在 miniprogramRoot 内
│ ├── package.json
│ └── sub_package_page
├── node_modules // 不被默认方式构建 npm,因为它不在 miniprogramRoot 内
├── package.json
└── project.config.json // 其中存在配置 `"miniprogramRoot": "./miniprogram"`
构建后:
├── miniprogram
│ ├── app.js
│ ├── app.json
│ ├── app.wxss
│ ├── index
│ │ ├── 略
│ ├── miniprogram_npm
│ ├── node_modules // 可被默认方式构建 npm,因为它在 miniprogramRoot 内 --> 同级的 miniprogram_npm 是这份 node_modules 的构建结果
│ ├── package.json
│ └── sub_package
│ ├── miniprogram_npm
│ ├── node_modules // 可被默认方式构建 npm,因为它在 miniprogramRoot 内 --> 同级的 miniprogram_npm 是这份 node_modules 的构建结果
│ ├── package.json
│ └── sub_package_page
├── node_modules // 不被默认方式构建 npm,因为它不在 miniprogramRoot 内 --> 它并没有对应的 miniprogram_npm 生成
├── package.json
└── project.config.json // 其中存在配置 `"miniprogramRoot": "./miniprogram"`
3.自定义构建方式
以我们常规的开发习惯,node_modules 文件夹一般放在项目的根目录下,而不是放在主要源码(miniprogram、src等)的位置下。微信小程序允许我们自定义构建方式,此种方式需要开发者在 project.config.json 中指定 node_modules 的位置 和目标 miniprogram_npm 的位置。
使用方法
- 配置 project.config.json 的 setting.packNpmManually 为 true,开启自定义 node_modules 和 miniprogram_npm 位置的构建 npm 方式
- 配置 project.config.json 的 setting.packNpmRelationList 项,指定 packageJsonPath 和 miniprogramNpmDistDir 的位置
"packNpmManually": true,
"packNpmRelationList": [
{
"packageJsonPath": "./package.json",
"miniprogramNpmDistDir": "./miniprogram/"
}
]
- packageJsonPath 表示 node_modules 源对应的 package.json
- miniprogramNpmDistDir 表示 node_modules 的构建结果目标位置
构建前:
├── miniprogram
│ ├── app.js
│ ├── app.json
│ ├── app.wxss
│ ├── index
│ ├── sitemap.json
│ └── sub_package
│ └── sub_package_page
├── project.config.json
├── src_node_modules_1
│ ├── node_modules
│ └── package.json
└── src_node_modules_2
├── node_modules
└── package.json
其中 project.config.json 配置:
"setting": {
"packNpmManually": true,
"packNpmRelationList": [
{
"packageJsonPath": "./src_node_modules_1/package.json",
"miniprogramNpmDistDir": "./miniprogram/"
},
{
"packageJsonPath": "./src_node_modules_2/package.json",
"miniprogramNpmDistDir": "./miniprogram/sub_package"
}
]
}
构建后:
├── miniprogram
│ ├── app.js
│ ├── app.json
│ ├── app.wxss
│ ├── index
│ ├── miniprogram_npm // 由 src_node_modules_1/node_modules 构建得到
│ ├── sitemap.json
│ └── sub_package
│ ├── miniprogram_npm // 由 src_node_modules_2/node_modules 构建得到
│ └── sub_package_page
├── project.config.json
├── src_node_modules_1
│ ├── node_modules
│ └── package.json
└── src_node_modules_2
├── node_modules
└── package.json
命令行构建
除了使用 IDE 来构建 npm ,还可以通过 miniprogram-ci 工具构建。需要特别注意的是:采用不同的构建方式,miniprogram-ci 的编译指令也不同。
默认构建方式
采用的命令为:ci.packNpm。
const ci = require('miniprogram-ci')
;(async () => {
const project = new ci.Project({
appid: 'wxsomeappid',
type: 'miniProgram',
projectPath: 'the/project/path',
privateKeyPath: 'the/path/to/privatekey',
ignores: ['node_modules/**/*'],
})
// 在有需要的时候构建npm
const warning = await ci.packNpm(project, {
ignores: ['pack_npm_ignore_list'],
reporter: (infos) => { console.log(infos) }
})
console.warn(warning)
// 可对warning进行格式化
/*
warning.map((it, index) => {
return `${index + 1}. ${it.msg}
\t> code: ${it.code}
\t@ ${it.jsPath}:${it.startLine}-${it.endLine}`
}).join('---------------\n')
*/
// 完成构建npm之后,可用ci.preview或者ci.upload
})()
自定义构建方式
采用的命令为:ci.packNpmManually。
let packResult = await ci.packNpmManually({
packageJsonPath: './lib/package.json',
miniprogramNpmDistDir: './miniprogram-project/miniprogram/',
})
console.log('pack done, packResult:', packResult)
// 输出 pack done, packResult: { miniProgramPackNum: 0, otherNpmPackNum: 1, warnList: [] }