本教程使用官网教程中指示的 Rollup 作为打包工具,并尽量遵循官网教程的指引进行实践;组件项目的初始化创建方式亦是使用官网提倡的 Vue CLI 工具简便生成(生成步骤)。另外组件打包发布到 npm 还可以使用 webpack 作为打包工具,但不在本文讨论范围。
1. 前期准备及版本信息
node: v18.14.2
@vue/cli: 5.0.8
使用 @vue/cli 初始化创建项目,项目生成后,其中依赖包版本信息为:
"dependencies": {
"core-js": "^3.8.3",
"vue": "^2.6.14",
"vue-router": "^3.5.1",
"vuex": "^3.6.2"
},
"devDependencies": {
"@babel/core": "^7.12.16",
"@babel/eslint-parser": "^7.12.16",
"@vue/cli-plugin-babel": "~5.0.0",
"@vue/cli-plugin-eslint": "~5.0.0",
"@vue/cli-plugin-router": "~5.0.0",
"@vue/cli-plugin-vuex": "~5.0.0",
"@vue/cli-service": "~5.0.0",
"eslint": "^7.32.0",
"eslint-plugin-vue": "^8.0.3",
"sass": "^1.32.7",
"sass-loader": "^12.0.0",
"vue-template-compiler": "^2.6.14"
}
2. 安装 Rollup 相关开发时依赖
npm install rollup -D
npm install rollup-plugin-vue@5.1.9 -D
npm install @rollup/plugin-buble -D
npm install @rollup/plugin-commonjs -D
npm install @rollup/plugin-image -D (可选,用于引入图片)
安装完成后的 devDependencies 如下
留意各依赖版本号。根据作者之前的经验,Vue 官网教程中使用的旧版 Rollup 与较新版 Vue 2 存在一些兼容性问题,导致无法编译。故建议读者可以使用当前最新的 Rollup 相关依赖库。但要特别注意的是:rollup-plugin-vue 必须安装 5.x.x 版本,当前最新的 6.x.x 据说只与 Vue 3 兼容,经作者测试,6.x.x 版本在编译项目时的确会报错。
如果仍然出现无法正常编译的问题,可使用和本教程一样的 Vue 和 Rollup 以及相关的各依赖库版本。
"devDependencies": {
"@babel/core": "^7.12.16",
"@babel/eslint-parser": "^7.12.16",
"@rollup/plugin-buble": "^1.0.2",
"@rollup/plugin-commonjs": "^24.0.1",
"@rollup/plugin-image": "^3.0.2",
"@vue/cli-plugin-babel": "~5.0.0",
"@vue/cli-plugin-eslint": "~5.0.0",
"@vue/cli-plugin-router": "~5.0.0",
"@vue/cli-plugin-vuex": "~5.0.0",
"@vue/cli-service": "~5.0.0",
"eslint": "^7.32.0",
"eslint-plugin-vue": "^8.0.3",
"rollup": "^3.18.0",
"rollup-plugin-vue": "^5.1.9",
"sass": "^1.32.7",
"sass-loader": "^12.0.0",
"vue-template-compiler": "^2.6.14"
}
3. 编写自己的将要发布的组件
在项目 src/components 下新建 my-component.vue。
my-component.vue 内容如下:
<template>
<div class="my-component">
<img :src="logoSrc" />
</div>
</template>
<script>
import LOGO from "../assets/logo.png";
export default {
data() {
return {
logoSrc: LOGO,
};
},
};
</script>
<style lang="scss" scoped>
.my-component {
width: 100px;
height: 100px;
img {
width: 100%;
height: 100%;
}
}
</style>
以上代码还展示了如何在组件中引入图片资源,得益于之前安装的 @rollup/plugin-image 依赖,可用 import 方式直接引入图片资源,图片在编译阶段会转换为 Base64 格式。需要特别注意的是需要用相对路径方式引入图片资源,Vue CLI 生成的项目所支持的 @ 路径引入方式实测无效。
4. 编写 wrapper.js
wrapper.js 负责组件导出(export)以及将组件自动注册到 Vue。
在项目 src 文件夹下新建 wrapper.js。
wrapper.js 内容如下:
// Import vue component
import component from './components/my-component.vue';
// Declare install function executed by Vue.use()
export function install(Vue) {
if (install.installed) return;
install.installed = true;
Vue.component('MyComponent', component);
}
// Create module definition for Vue.use()
const plugin = {
install,
};
// Auto-install when vue is found (eg. in browser via <script> tag)
let GlobalVue = null;
if (typeof window !== 'undefined') {
GlobalVue = window.Vue;
} else if (typeof global !== 'undefined') {
GlobalVue = global.Vue;
}
if (GlobalVue) {
GlobalVue.use(plugin);
}
// To allow use as module (npm/webpack/etc.) export component
export default component;
MyComponent 改为你组件的名称
5. 编写 rollup.config.js
在项目根目录新建 build 文件夹,文件夹内新建 rollup.config.js。
rollup.config.js 内容如下:
import commonjs from '@rollup/plugin-commonjs'; // Convert CommonJS modules to ES6
import vue from 'rollup-plugin-vue'; // Handle .vue SFC files
import buble from '@rollup/plugin-buble'; // Transpile/polyfill with reasonable browser support
import image from '@rollup/plugin-image';
export default {
input: 'src/wrapper.js', // Path relative to package.json
output: {
name: 'MyComponent',
exports: 'named',
},
plugins: [
commonjs(),
image(),
vue({
css: true, // Dynamically inject css as a <style> tag
compileTemplate: true, // Explicitly convert template to render function
}),
buble({
objectAssign: true,
transforms: {
asyncAwait: false,
forOf: false,
}
}), // Transpile to ES5
],
};
MyComponent 改为你组件的名称
6. 修改 package.json
内容如下:
{
"name": "my-component",
"version": "0.1.0",
"keywords": [
"buble",
"publish",
"example",
"vue"
],
"author": "your name",
"license": "MIT",
"main": "dist/my-component.umd.js",
"module": "dist/my-component.esm.js",
"unpkg": "dist/my-component.min.js",
"browser": {
"./sfc": "src/components/my-component.vue"
},
"type": "module",
"private": false,
"files": [
"dist/*"
],
"scripts": {
"serve": "vue-cli-service serve",
"lint": "vue-cli-service lint",
"build": "npm run build:umd & npm run build:es & npm run build:unpkg",
"build:umd": "rollup --config build/rollup.config.js --format umd --file dist/my-component.umd.js",
"build:es": "rollup --config build/rollup.config.js --format es --file dist/my-component.esm.js",
"build:unpkg": "rollup --config build/rollup.config.js --format iife --file dist/my-component.min.js"
},
"dependencies": {
...
},
"devDependencies": {
...
}
}
备注
"type": "module" 是可选的。如果 Vue 项目中 CommonJS 和 ES modules 语法混用,加上 "type": "module" 的话,会导致 Vue 项目调试运行时出错。
但如果 package.json 中不写上 "type": "module" 的话,需要把 rollup.config.js 重命名为 rollup.config.mjs,并相应更改 package.json 中出现过 rollup.config.js 的地方。
对其中一些字段的解释(详见 package.json 官方解释)
字段名 | 解释 |
name | 发布npm的必须项。组件在npm上的名称,需要在npm中全局唯一。如果 name 在 npm 上已被其它组件占用,发布组件时将报错,但只会提示操作被禁止,不会提示名字被占用,因为 npm 认为你在向同名的那个组件提交新版本,但你本人的账号当然是无权向他人发布的组件提交新版的 |
version | 发布 npm 的必须项。组件的版本号。每次再次发布新版组件,版本号需要递进 |
keywords | 在 npm 上可以通过这些关键字搜索到本组件 |
author | 组件的作者名称 |
license | 代码许可证 |
type | 可取值 commonjs 或 module,前者则无扩展名的文件和 .js 结尾文件将被视为 commonjs,后者则无扩展名的文件和 .js 结尾文件将被视为 ES 模块 |
private | 是否私有项目。只有设为 false,才允许将本组件发布到 npm |
7. 注册 npm 账号
略。读者请自行解决。
8. 命令行登录 npm
使用 npm adduser 指令登录 npm,根据提示输入上一步得到的用户、密码、邮箱等信息。
9. 编译组件
在指向组件项目根目录的命令行下,运行 npm run build 指令,组件会根据 package.json 中的配置进行编译,编译结果在项目根目录的 dist 文件夹中。
10. 发布组件到 npm
运行 npm publish,组件将发布到 npm 上。此后,npm 上可以搜索到你的组件。
11. 后续问题
请参考另一篇文章 Vue 2 组件发布到 npm 的常见问题解决