技术选型
为什么一定要选择打包工具来开发 npm
包?
- 不一定非要使用构建工具来开发,使用构建工具主要是为了使用它强大的生态系统。比如代码风格检测、本地服务、同时构建多种规范的产物等等,方便我们的开发
为什么是 rollup
而不是 webpack
?
- 随着
rollup
和webpack
的版本更新,二者之间的差异性特性越来越小 rollup
配置简单,支持同时打包输出多种规范的产物(iife、cjs、umd、esm、amd、system)webpack
功能强大社区丰富,更加适合大型应用;不支持打包输出为es module
,而且产物不是很纯净- 构建
App应用
时,webpack比较合适;如果是类库(纯js项目)
,rollup更加适合。
完整的开发流程
- 初始化项目
- 创建合理的目录结构
- 配置
eslint
统一代码风格 - 配置
typescript
开发环境 - 配置
babel
- 配置
git
提交的校验钩子 - 开始编写代码
- watch 模式开发(本地服务)
- 添加单元测试,编写测试示例
- 完善
package.json
必要字段 - 配置合适的
npm script
- 本地测试开发的
npm
包 - 发布包到
npm
- 提交代码到
git
仓库
合理的包结构
├── bin // 用于存放可执行二进制文件的目录
├── dist(lib) // 产物输出目录
├── docs // 文档说明
├── examples // 示例
├── package.json
├── README.md // 包说明,会在npm展示
├── scripts // 脚本
├── src(packages) // 源码
├── test // 单元测试
└── ... // 一些配置文件(eg: eslint、babel)
使用 rollup 开发
项目地址:vtools
初始化
mkdir vtools
npm init -y
配置 rollup
- 根据开发环境区分不同的配置
- 设置对应的
npm script
- 输出不同规范的产物:umd、umd.min、cjs、esm
- 兼容
jest
不支持es module
的问题
mkdir scripts
cd scripts
touch rollup.config.base.js // 通用配置
touch rollup.config.dev.js // 开发环境配置
touch rollup.config.prod.js // 正式环境配置
rollup.config.base.js
// 安装以下 npm 包
import { nodeResolve } from '@rollup/plugin-node-resolve' // 解析 node_modules 中的模块
import commonjs from '@rollup/plugin-commonjs' // cjs => esm
import alias from '@rollup/plugin-alias' // alias 和 reslove 功能
import replace from '@rollup/plugin-replace'
import eslint from '@rollup/plugin-eslint'
import { babel } from '@rollup/plugin-babel'
import { terser } from 'rollup-plugin-terser'
import clear from 'rollup-plugin-clear'
import json from '@rollup/plugin-json' // 支持在源码中直接引入json文件,不影响下面的
import { name, version, author } from '../package.json'
const pkgName = 'vtools'
const banner =
'/*!\n' +
` * ${name} v${version}\n` +
` * (c) 2014-${new Date().getFullYear()} ${author}\n` +
' * Released under the MIT License.\n' +
' */'
export default {
input: 'src/index.js',
// 同时打包多种规范的产物
output: [
{
file: `dist/${pkgName}.umd.js`,
format: 'umd',
name: pkgName,
banner
},
{
file: `dist/${pkgName}.umd.min.js`,
format: 'umd',
name: pkgName,
banner,
plugins: [terser()]
},
{
file: `dist/${pkgName}.cjs.js`,
format: 'cjs',
name: pkgName,
banner
},
{
file: `dist/${pkgName}.esm.js`,
format: 'es',
banner
}
],
// 注意 plugin 的使用顺序
plugins: [
json(),
clear({
targets: ['dist']
}),
alias(),
replace({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
preventAssignment: true
}),
nodeResolve(),
commonjs({
include: 'node_modules/**'
}),
eslint({
throwOnError: true, // 抛出异常并阻止打包
include: ['src/**'],
exclude: ['node_modules/**']
}),
babel({ babelHelpers: 'bundled' })
]
}
touch rollup.config.dev.js
import baseConfig from './rollup.config.base'
import serve from 'rollup-plugin-serve'
import livereload from 'rollup-plugin-livereload'
export default {
...baseConfig,
plugins: [
...baseConfig.plugins,
serve({
port: 8080,
contentBase: ['dist', 'examples/brower'],
openPage: 'index.html',
}),
livereload({
watch: 'examples/brower',
})
]
}
touch rollup.config.prod.js
import baseConfig from './rollup.config.base'
import filesize from 'rollup-plugin-filesize'
export default {
...baseConfig,
plugins: [
...baseConfig.plugins,
filesize()
]
}
配置eslint
npm i eslint -D
// 生成配置文件
npx eslint --init
// 使用 standard 规范
npm install --save-dev eslint-config-standard eslint-plugin-promise eslint-plugin-import eslint-plugin-node
// .eslintrc.js 配置
module.exports = {
root: true,
env: {
browser: true,
es2021: true,
jest: true // 支持jest
},
extends: 'standard',
parserOptions: {
ecmaVersion: 12,
sourceType: 'module'
},
rules: {
'space-before-function-paren': ['error', 'never']
}
}
// .eslintignore 配置, 防止校验打包的产物
dist
配置 babel
npm i -D @babel/core @babel/preset-env
// .babelrc.js
module.exports = {
presets: [
['@babel/preset-env', {
// rollupjs 会处理模块,所以设置成 false
modules: false
}]
],
plugins: [
]
}
单元测试
- 选用
jest
做单元测试 - 配置
eslint
的jest
环境 - 解决
jest
不支持es module
的问题
npm i -D jest
// 支持 `es module`
npm i -D rollup-jest
// package.json 中设置
"jest": {
"preset": "rollup-jest"
}
// 执行测试
jest
// 测试覆盖率
jest --coverage
添加忽略文件
.gitignore
node_modules
dist
coverage
.npmignore
node_modules
test
src
.babelrc.js
.eslintrc.js
scripts
coverage
docs
.czrc
.eslintignore
.huskyrc
.commitlint.config.js
.commitlint.config
README.md
添加徽标
- GitHub徽标官网是shields.io
- 普通徽标
https://img.shields.io/badge/{徽标标题}-{徽标内容}-{徽标颜色}.svg
// eg
![build](https://img.shields.io/badge/build-passing-success.svg)
- 动态徽标
https://img.shields.io/github/issues/{github用户名}/{仓库名}.svg
https://img.shields.io/github/forks/{github用户名}/{仓库名}.svg
https://img.shields.io/github/stars/{github用户名}/{仓库名}.svg
https://img.shields.io/github/license/{github用户名}/{仓库名}.svg
git 提交校验
npm install --save-dev husky @commitlint/config-conventional @commitlint/cli commitizen cz-conventional-changelog
// commitlint.config
touch commitlint.config.js
module.exports = {
extends: ["@commitlint/config-conventional"]
};
// huskyrc
touch .huskyrc
{
"hooks": {
"pre-commit": "npm run format && npm run lint && npm test",
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
}
}
// touch .czrc
touch .czrc
{ "path": "cz-conventional-changelog" }
// package.json
{
"scripts": {
"commit": "git-cz"
}
}
package.json
{
"name": "@vtian/vtools",
"version": "2.0.0",
"description": "tools",
"main": "dist/vtools.umd.js",
"module": "dist/vtools.esm.js",
"repository": {
"type": "git",
"url": "https://github.com/tiandashu/vtools.git"
},
"bugs": {
"url": "https://github.com/tiandashu/vtools/issues"
},
"bin": {
"hello": lib/index.js
},
"homepage": "https://github.com/tiandashu/vtools#readme",
"scripts": {
"dev": "rollup -w --environment NODE_ENV:development -c scripts/rollup.config.dev.js",
"build": "rollup --environment NODE_ENV:development -c scripts/rollup.config.prod.js",
"x": "npm --no-git-tag-version version major",
"y": "npm --no-git-tag-version version minor",
"z": "npm --no-git-tag-version version patch",
"lint": "eslint src",
"fix": "npm run lint --fix",
"commit": "git-cz",
"test": "jest",
"test:c": "jest --coverage",
"prepublish": "npm run build",
"pub": "npm publish --access=public",
"pub:x": "npm run x && npm publish --access=public",
"pub:y": "npm run y && npm publish --access=public",
"pub:z": "npm run z && npm publish --access=public"
},
"author": "tiandashu",
"license": "ISC",
# 开发依赖(作为npm包被install时,开发依赖不会被下载进node_modules)
"devDependencies": {},
# 依赖(作为npm包被install时,依赖会被下载进node_modules)
"dependencies": {},
"jest": {
"preset": "rollup-jest"
}
}
使用 @vue/cli 开发
项目地址:admin-widgets
- @vue/cli 初始化项目
- 修改目录
- 配置vue.config.js
- 修改package.json
npm i -g @vue/cli
vue create qqmap-track
目录结构
├── babel.config.js
├── docs // 文档
├── examples // 示例
├── lib // 构建目录
├── package.json
├── packages // 源码
├── public
├── README.md
├── types
└── vue.config.js
vue.config.js
// vue.config.js
module.exports = {
pages: {
index: {
entry: 'examples/main.js',
template: 'public/index.html',
filename: 'index.html'
}
},
css: {
extract: false // 是否单独抽离css
},
configureWebpack: {
output: {
libraryExport: 'default',
}
}
}
package.json
{
"name": "@vtian/admin-widgets",
"version": "0.0.1",
"private": false,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint",
"lib": "vue-cli-service build --target lib --name adminWidgets --dest lib ./packages/index.js",
"prepublish": "npm run lib2"
},
"main": "lib/adminWidgets.umd.js",
"typings": "types/index.d.ts",
"homepage": "https://github.com/tiandashu/admin-widgets#README.md",
"repository": {
"type": "git",
"url": "https://github.com/tiandashu/admin-widgets.git"
},
"bugs": {
"url": "https://github.com/tiandashu/admin-widgets/issues"
},
"dependencies": {
"core-js": "^3.6.5",
"vue": "^2.6.11"
},
"devDependencies": {},
"eslintConfig": {
"root": true,
"globals": {
"TMap": "readonly"
},
"env": {
"node": true
},
"extends": [
"plugin:vue/essential",
"eslint:recommended"
],
"parserOptions": {
"parser": "babel-eslint"
},
"rules": {}
},
"browserslist": [
"> 1%",
"last 2 versions",
"not dead"
]
}
测试 npm 包
- npm link
// 包根目录下
npm link
// 测试目录下
npm link vtools
- 通过 file 协议安装
npm i ../../vtools
发布
- 版本号严格按照 主版本号.次版本号.修订号 格式命名
- 版本是严格递增的,:1.8.0 -> 1.8.1 -> 16.8.2
- 发布重大版本或版本改动较大时,先发布alpha、beta、rc等先行版本
- 内部版本(alpha);公测版本(beta);正式版本的候选版本rc: 即 Release candiate
npm login
npm run pub
参考资料
cloud.tencent.com/developer/a…
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!