本文將從以下幾個方面分享如何搭建一個npm包,在搭建過程中需要注意的事項
- 初始化
- 入口
- 依賴
- 檔案
- 版本號管理
- 自動化釋出
初始化
在專案根目錄下執行:npm init
建立 package.json
檔案,這也是npm包的核心配置檔案
入口
package.json
中可以通過下面兩個欄位來指定入口檔案:
- main 指向 commonjs 模組的入口,使用 require 語法引入
- module 指向 ES2015 模組的入口,使用 import 語法引入,支援webpack等構建工具的 tree shaking 優化
這裡,可以展開介紹一下 umd、commonjs、es module 模組型別的區別
- umd 是相容 commonjs、amd 的通用模組規範,支援全變數規範,可以直接通過
<script>
標籤引入,寫法如下:
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global['xxx'] = factory());
}(this, (function () { 'use strict';
...
})));
複製程式碼
- commonjs 使用
module.exports
定義模組對外輸出的介面,使用require
載入模組 - es module 是ES6模組,使用
export
、import
語法
而一般npm包都需要支援以上三種模組規範,以下列出通用的rollup配置:
import path from 'path';
import babel from 'rollup-plugin-babel';
import cleanup from 'rollup-plugin-cleanup';
import replace from 'rollup-plugin-replace';
import { uglify } from 'rollup-plugin-uglify';
import nodeResolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import pkg from './package.json';
const { version, name, author } = pkg;
const banner = `/*!
* ${name} v${version}
* (c) ${new Date().getFullYear()} ${author}
*/`;
const resolve = p => {
return path.resolve(__dirname, p);
}
const pluginsCommon = [
commonjs({
// polyfill async/await
'node_modules/@babel/runtime/helpers/asyncToGenerator.js': ['default']
}),
nodeResolve({
module: false,
}),
babel({
runtimeHelpers: true,
}),
]
export default [
{
input: resolve('src/index.js'),
plugins: pluginsCommon.concat([
cleanup(),
]),
output: {
file: resolve(`dist/npmpackage-name-${version}.js`),
format: 'umd',
name: 'npmpackage-name',
banner,
}
},
{
input: resolve('src/index.js'),
plugins: pluginsCommon.concat([
uglify(),
]),
output: {
file: resolve(`dist/npmpackage-name-${version}.min.js`),
format: 'umd',
name: 'npmpackage-name',
banner,
}
},
{
input: resolve('src/index.js'),
plugins: pluginsCommon.concat([
cleanup(),
]),
output: [
{
file: resolve(`dist/npmpackage-name.es.js`),
format: 'es',
banner,
},
{
file: resolve(`dist/npmpackage-name.js`),
format: 'cjs',
banner,
}
]
},
];
複製程式碼
再附上對應的babel配置:
{
"presets": [
["@babel/preset-env", {
"targets": {
"browsers": ["Android >= 4", "iOS >= 8"]
},
"modules": false,
"loose": true
}]
],
"plugins": [
"@babel/plugin-external-helpers",
[
"@babel/plugin-transform-runtime",
{
"regenerator": true
}
]
]
}
複製程式碼
以上,配置則能構建出滿足以上三種模組規範的檔案
相應的package.json
檔案中,也需要通過不同的欄位,來指定對應模組規範的入口檔案,如下:
{
...
"main": "dist/npmpackage-name.js",
"module": "dist/npmpackage-name.es.js",
...
}
複製程式碼
而dist/npmpackage-name-${version}.js
的檔案,則可以直接通過<script>
標籤引入
注意:不要將入口檔案指定為未過babel的檔案,這往往會導致使用了此包的專案出現相容問題
依賴
package.json
中跟npm包依賴相關的欄位主要有:
- dependencies:專案執行時所依賴的模組
- devDependencies:專案開發時所依賴的模組
- peerDependencies:這是“同伴依賴”,一種特殊的依賴,在釋出包的時候需要。有這種依賴意味著安裝包的使用者也需要和包同樣的依賴。(在安裝包時會提示)
我們在開發npm包過程中,需要注意安裝依賴的型別。
對於那些對版本有強要求的依賴,為了避免因依賴版本不一致導致問題,需要將此類依賴安裝在 peerDependencies 中
檔案
一個npm包一般包括原始檔、構建產出的檔案、demo檔案、測試檔案等檔案,而為了減小npm包大小,加快下載速度,釋出時應該將無用的檔案剔除掉,有兩種方式:
- 使用
package.json
中的files
指定需要釋出的檔案 - 在
.npmignore
檔案中指定需要提出的檔案
版本號管理
每釋出一個版本,版本號需要相應的升級(不要手動在package.json中維護)
應該通過npm version
來對版本號進行管理,版本號有以下幾種型別:
- major: 主版本號
- minor: 次版本號
- patch: 補丁號
- premajor: 預備主版本
- preminor: 預備次版本
- prepatch: 預備補丁號
- prerelease: 預釋出版本
版本號管理策略如下:
- 版本號格式:主版本號.次版本號.修訂號
- 主版本號:有不相容的 API 修改
- 次版本號:有向後相容的功能性新增
- 修訂號:有向後相容的問題修正
而升級對應的版本號的命令則如下:
npm version [<newversion> | major | minor | patch | premajor | preminor | prepatch | prerelease [--preid=<prerelease-id>] | from-git]
複製程式碼
釋出自動化
package.json
配置如下:
{
"scripts": {
"build": "rm -rf dist && rollup --config",
"release_major": "npm version major",
"release_minor": "npm version minor",
"release_patch": "npm version patch",
"postversion": "npm publish",
"prepublishOnly": "npm run build"
},
}
複製程式碼
直接通過執行對應的release_
命令來進行釋出即可
以上就是一個npm包通常會用到基本事項,後續會不斷更新一些進階的用法~
寫在最後
希望能對有需要的小夥伴有幫助~~~
喜歡我的文章小夥伴可以去 我的個人部落格 點star ⭐️