# npm 支持
從小程序基礎(chǔ)庫(kù)版本 2.2.1 或以上、及開(kāi)發(fā)者工具 1.02.1808300 或以上開(kāi)始,小程序支持使用 npm 安裝第三方包。
此文檔要求開(kāi)發(fā)者們對(duì) npm 有一定的了解,因此不會(huì)再去介紹 npm 的基本功能。如若之前未接觸過(guò) npm,請(qǐng)翻閱 官方 npm 文檔 進(jìn)行學(xué)習(xí)。
tips:在小程序中使用npm包前,需先構(gòu)建 npm
# 使用 npm 包
# 1. 安裝 npm 包
在小程序 package.json 所在的目錄中執(zhí)行命令安裝 npm 包:
npm install
此處要求參與構(gòu)建 npm 的 package.json 需要在 project.config.json 定義的 miniprogramRoot 之內(nèi)。
tips:開(kāi)發(fā)者工具 v1.02.1811150 版本開(kāi)始,調(diào)整為根據(jù) package.json 的 dependencies 字段構(gòu)建,所以聲明在 devDependencies 里的包也可以在開(kāi)發(fā)過(guò)程中被安裝使用而不會(huì)參與到構(gòu)建中。如果是這之前的版本,則建議使用
--production選項(xiàng),可以減少安裝一些業(yè)務(wù)無(wú)關(guān)的 npm 包,從而減少整個(gè)小程序包的大小。
tips: miniprogramRoot 字段不存在時(shí),miniprogramRoot 就是 project.config.json 所在的目錄
# 2. 構(gòu)建 npm
點(diǎn)擊開(kāi)發(fā)者工具中的菜單欄:工具 --> 構(gòu)建 npm

# 3. 構(gòu)建完成后即可使用 npm 包。
js 中引入 npm 包:
const myPackage = require('packageName')
const packageOther = require('packageName/other')
使用 npm 包中的自定義組件:
{
"usingComponents": {
"myPackage": "packageName",
"package-other": "packageName/other"
}
}
tips:此處使用 npm 包時(shí)如果只引入包名,則默認(rèn)尋找包名下的 index.js 文件或者 index 組件。
# 發(fā)布 npm 包
# 發(fā)布小程序 npm 包的約束
這里要發(fā)布的 npm 包是特指專為小程序定制的 npm 包(下稱小程序 npm 包)。因?yàn)樾〕绦蜃远x組件的特殊性,原有的 npm 包機(jī)制無(wú)法滿足我們的需求,所以這里需要對(duì)小程序 npm 包做一些約束:
- 小程序 npm 包要求根目錄下必須有構(gòu)建文件生成目錄(默認(rèn)為 miniprogram_dist 目錄),此目錄可以通過(guò)在 package.json 文件中新增一個(gè) miniprogram 字段來(lái)指定,比如:
{
"name": "miniprogram-custom-component",
"version": "1.0.0",
"description": "",
"miniprogram": "dist",
"devDependencies": {},
"dependencies": {}
}
- 小程序 npm 包里只有構(gòu)建文件生成目錄會(huì)被算入小程序包的占用空間,上傳小程序代碼時(shí)也只會(huì)上傳該目錄的代碼。如果小程序 npm 包有一些測(cè)試、構(gòu)建相關(guān)的代碼請(qǐng)放到構(gòu)建文件生成目錄外。另外也可以使用
.npmignore文件來(lái)避免將一些非業(yè)務(wù)代碼文件發(fā)布到 npm 中。 - 測(cè)試、構(gòu)建相關(guān)的依賴請(qǐng)放入 devDependencies 字段中避免被一起打包到小程序包中。
# 發(fā)布其他 npm 包的約束
如果是已經(jīng)發(fā)布過(guò)的一些 npm 包,因?yàn)橐恍┰驘o(wú)法改造成小程序 npm 包的結(jié)構(gòu)的話,也可以通過(guò)微調(diào)后被使用,但是請(qǐng)確保遵循以下幾點(diǎn):
- 只支持純 js 包,不支持自定義組件。
- 必須有入口文件,即需要保證 package.json 中的 main 字段是指向一個(gè)正確的入口,如果 package.json 中沒(méi)有 main 字段,則以 npm 包根目錄下的 index.js 作為入口文件。
- 測(cè)試、構(gòu)建相關(guān)的依賴請(qǐng)放入 devDependencies 字段中避免被一起打包到小程序包中,這一點(diǎn)和小程序 npm 包的要求相同。
- 不支持依賴 c++ addon,不支持依賴 nodejs 的內(nèi)置庫(kù):
const addon = require('./addon.node'); // 不支持!
const http = require('http'); // 不支持!
tips:對(duì)于一些純 js 實(shí)現(xiàn)的 nodejs 內(nèi)置庫(kù)(如 path 模塊),可以通過(guò)額外安裝其他開(kāi)發(fā)者實(shí)現(xiàn)的 npm 包來(lái)支持。
- 使用 require 依賴的時(shí)候下列幾種方式也是不允許的:
// 不允許將 require 賦值給其他變量后再使用,以下代碼不會(huì)去解析出具體依賴
let r;
r = require;
r('testa');
let r2 = require;
r2('testa');
// 不允許 require 一個(gè)變量,以下代碼依賴運(yùn)行時(shí),無(wú)法解析出具體依賴
let m = 'testa';
require(m);
- 小程序環(huán)境比較特殊,一些全局變量(如 window 對(duì)象)和構(gòu)造器(如 Function 構(gòu)造器)是無(wú)法使用的。
# 發(fā)布流程
發(fā)布 npm 包的流程簡(jiǎn)述如下:
- 如果還沒(méi)有 npm 賬號(hào),可以到 npm 官網(wǎng) 注冊(cè)一個(gè) npm 賬號(hào)。
- 在本地登錄 npm 賬號(hào),在本地執(zhí)行:
npm adduser
或者
npm login
- 在已完成編寫的 npm 包根目錄下執(zhí)行:
npm publish
到此,npm 包就成功發(fā)布到 npm 平臺(tái)了。
tips:一些開(kāi)發(fā)者在開(kāi)發(fā)過(guò)程中可能修改過(guò) npm 的源,所以當(dāng)進(jìn)行登錄或發(fā)布時(shí)需要注意要將源切回 npm 的源。
# 原理介紹
為了幫助大家更好的理解發(fā)布 npm 包中提到的各種要求,這里簡(jiǎn)單介紹一下原理:
- 首先 node_modules 目錄不會(huì)參與編譯、上傳和打包中,所以小程序想要使用 npm 包必須走一遍“構(gòu)建 npm”的過(guò)程,在每一份 miniprogramRoot 內(nèi)開(kāi)發(fā)者聲明的 package.json 的最外層的 node_modules 的同級(jí)目錄下會(huì)生成一個(gè) miniprogram_npm 目錄,里面會(huì)存放構(gòu)建打包后的 npm 包,也就是小程序真正使用的 npm 包。
- 構(gòu)建打包分為兩種:小程序 npm 包會(huì)直接拷貝構(gòu)建文件生成目錄下的所有文件到 miniprogram_npm 中;其他 npm 包則會(huì)從入口 js 文件開(kāi)始走一遍依賴分析和打包過(guò)程(類似 webpack)。
- 尋找 npm 包的過(guò)程和 npm 的實(shí)現(xiàn)類似,從依賴 npm 包的文件所在目錄開(kāi)始逐層往外找,直到找到可用的 npm 包或是小程序根目錄為止。 下面簡(jiǎn)單介紹下構(gòu)建打包前后的目錄情況,構(gòu)建之前的結(jié)構(gòu):
|--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.js
構(gòu)建之后的結(jié)構(gòu):
|--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.js
tips:打包生成的代碼在同級(jí)目錄下會(huì)生成 source map 文件,方便進(jìn)行逆向調(diào)試。
# js 模塊示例
以下為官方提供的 js 模塊,可以參考并使用:
# 自定義組件相關(guān)示例
請(qǐng)查閱開(kāi)發(fā)第三方自定義組件文檔。
# Tips
從 1.03.2006302 (或 1.03.2006302) 開(kāi)始,我們提供了兩種構(gòu)建 npm 的方式:
# 默認(rèn)的構(gòu)建 npm 方式
默認(rèn)情況下,在 miniprogramRoot 內(nèi)正確配置了 package.json 并執(zhí)行 npm install 之后,其構(gòu)建 npm 的結(jié)果是,為每一個(gè) package.json 對(duì)應(yīng)的 node_modules 構(gòu)建一份 miniprogram_npm,并放置在對(duì)應(yīng) package.json 所在目錄的子目錄中。參考 demo
# 構(gòu)建 npm 前
├── miniprogram
│ ├── app.js
│ ├── app.json
│ ├── app.wxss
│ ├── index
│ │ ├── 略
│ ├── node_modules // 可被默認(rèn)方式構(gòu)建 npm,因?yàn)樗?miniprogramRoot 內(nèi)
│ ├── package.json
│ └── sub_package
│ ├── node_modules // 可被默認(rèn)方式構(gòu)建 npm,因?yàn)樗?miniprogramRoot 內(nèi)
│ ├── package.json
│ └── sub_package_page
├── node_modules // 不被默認(rèn)方式構(gòu)建 npm,因?yàn)樗辉?miniprogramRoot 內(nèi)
├── package.json
└── project.config.json // 其中存在配置 `"miniprogramRoot": "./miniprogram"`
# 構(gòu)建 npm 后
├── miniprogram
│ ├── app.js
│ ├── app.json
│ ├── app.wxss
│ ├── index
│ │ ├── 略
│ ├── miniprogram_npm
│ ├── node_modules // 可被默認(rèn)方式構(gòu)建 npm,因?yàn)樗?miniprogramRoot 內(nèi) --> 同級(jí)的 miniprogram_npm 是這份 node_modules 的構(gòu)建結(jié)果
│ ├── package.json
│ └── sub_package
│ ├── miniprogram_npm
│ ├── node_modules // 可被默認(rèn)方式構(gòu)建 npm,因?yàn)樗?miniprogramRoot 內(nèi) --> 同級(jí)的 miniprogram_npm 是這份 node_modules 的構(gòu)建結(jié)果
│ ├── package.json
│ └── sub_package_page
├── node_modules // 不被默認(rèn)方式構(gòu)建 npm,因?yàn)樗辉?miniprogramRoot 內(nèi) --> 它并沒(méi)有對(duì)應(yīng)的 miniprogram_npm 生成
├── package.json
└── project.config.json // 其中存在配置 `"miniprogramRoot": "./miniprogram"`
# 自定義 node_modules 和 miniprogram_npm 位置的構(gòu)建 npm 方式
與 “默認(rèn)的構(gòu)建 npm 方式” 不一樣,此種方式需要開(kāi)發(fā)者在 project.config.json 中指定 node_modules 的位置 和目標(biāo) miniprogram_npm 的位置。參考demo
# 使用方法
- 配置 project.config.json 的
setting.packNpmManually為true,開(kāi)啟自定義 node_modules 和 miniprogram_npm 位置的構(gòu)建 npm 方式 - 配置 project.config.json 的
setting.packNpmRelationList項(xiàng),指定packageJsonPath和miniprogramNpmDistDir的位置
其中 packNpmRelationList 的格式為
packNpmRelationList: Array<{
"packageJsonPath": string,
"miniprogramNpmDistDir": string
}>
- packageJsonPath 表示 node_modules 源對(duì)應(yīng)的 package.json
- miniprogramNpmDistDir 表示 node_modules 的構(gòu)建結(jié)果目標(biāo)位置
# 構(gòu)建 npm 前
.
├── 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"
}
]
}
# 構(gòu)建 npm 后
.
├── miniprogram
│ ├── app.js
│ ├── app.json
│ ├── app.wxss
│ ├── index
│ ├── miniprogram_npm // 由 src_node_modules_1/node_modules 構(gòu)建得到
│ ├── sitemap.json
│ └── sub_package
│ ├── miniprogram_npm // 由 src_node_modules_2/node_modules 構(gòu)建得到
│ └── sub_package_page
├── project.config.json
├── src_node_modules_1
│ ├── node_modules
│ └── package.json
└── src_node_modules_2
├── node_modules
└── package.json
# miniprogram_npm 組件尋址順序
頁(yè)面配置文件(如:pages/index/index.json)中使用 usingComponents
{
"usingComponents": {
"a": "a"
}
}
其尋址順序?yàn)?/p>
[
// 先尋址相對(duì)路徑
"pages/index/a",
"pages/index/a/index",
// 再嘗試尋址 miniprogram_npm 下的組件
"pages/index/miniprogram_npm/a",
"pages/index/miniprogram_npm/a/index",
// 再嘗試其父層級(jí)中的 miniprogram_npm 目錄
"pages/miniprogram_npm/a",
"pages/miniprogram_npm/a/index",
"miniprogram_npm/a",
"miniprogram_npm/a/index"
]
tips
1.06.2307172 之前的工具尋址順序會(huì)優(yōu)先尋找 a/index,再尋找 a/a,最后才輪到 a,這不太符合認(rèn)知。建議對(duì)于組件是 a/index 和 a/a 的這種情況,或者同時(shí)存在 a 和 a/index 的情況,usingComponents 需要直接顯示的寫明 "a/index" 和 "a/a",而不是只寫 "a"。