封装一个自己的组件库
coderzhouyu2023/11/18
背景
平时开发会积累很多业务组件,但是在不同的项目中,我们需要重新复制粘贴这些组件,这样会导致组件的维护成本变得很高,所以我们需要将这些组件进行封装,然后发布到 npm 上,这样就可以在不同的项目中使用了。
技术栈
- vue3
- vite
- ant-design-vue
- vueuse
开发组件库
项目初始化
npm create vue@latest
安装依赖
因为真正发布的时候,我们不需要将 ant-design-vue 和 vueuse 一起发布,所以我们将这两个依赖安装到 devDependencies 中。
npm install vue ant-design-vue @vueuse/core --save-dev
配置组件库导出
组件库中单个组件导出
组件库中的组件一般都是单个导出,所以我们需要将组件库中的组件进行单个导出,这样才能在项目中按需引入组件。这个需要在每个组件目录下创建 index.js 文件,然后在 index.js 文件中导出组件
。
// src/components/button/index.js
import Button from "./src/button.vue";
Button.install = (app) => {
// 如果用setup语法糖 Button.name 可以写对应的字符串
app.component(Button.name, Button);
};
export default Button;
组件库中所有组件导出
组件库的统一导出可以配置一个src/bundle.js
文件,然后在src/bundle.js
文件中导出所有的组件。
// 打包 npm 包用
import "./style.scss";
import SjBusinessTable from "@/components/SjBusinessTable";
const components = {
SjBusinessTable,
};
const install = function (app) {
// 注册自定义组件到全局
for (const key in components) {
app.component(key, components[key]);
}
};
export default {
install,
};
export { SjBusinessTable };
配置组件库打包
通常组件库的打包有两种方式,一种是打包成 esm 模块,一种是打包成 umd 模块。
打包成 esm 模块
vite.es.config.js
文件
配置一个单独的// 打包 npm 包
import { fileURLToPath, URL } from "node:url";
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import vueJsx from "@vitejs/plugin-vue-jsx";
export default defineConfig({
plugins: [vue(), vueJsx()],
resolve: {
alias: {
"@": fileURLToPath(new URL("./src", import.meta.url)),
},
},
//public 目录下的文件不会被打包
publicDir: "empty",
build: {
// 打包后的文件夹
outDir: "dist/es",
lib: {
// 入口文件
entry: fileURLToPath(new URL("./src/bundle.js", import.meta.url)),
// 项目名
name: "SujuPlus",
// 打包后的文件名
fileName: "suju-plus",
// 打包格式
formats: ["es"],
},
rollupOptions: {
// 不需要打包的模块
external: ["vue"],
},
},
});
配置 package.json
{
// 指定打包格式为 esm
"type": "module",
// 指定引用的入口文件
"module": "dist/es/suju-plus.js",
// 指定引用的别名
"exports": {
".": {
"import": "./dist/es/suju-plus.js"
},
"./style.css": {
"import": "./dist/style.css"
}
},
// 只发布 dist 目录下的文件到 npm
"files": ["dist"],
"scripts": {
"build:es": "vite build --config vite.es.config.js"
}
}
打包成 umd 模块
vite.umd.config.js
文件
配置一个单独的// 打包 umd 包
import { fileURLToPath, URL } from "node:url";
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import vueJsx from "@vitejs/plugin-vue-jsx";
export default defineConfig({
plugins: [vue(), vueJsx()],
resolve: {
alias: {
"@": fileURLToPath(new URL("./src", import.meta.url)),
},
},
publicDir: "empty",
build: {
outDir: "dist/umd",
lib: {
entry: fileURLToPath(new URL("./src/bundle.js", import.meta.url)),
name: "SujuPlus",
fileName: "suju-plus",
formats: ["umd"],
},
rollupOptions: {
// 不需要打包的模块
external: ["vue"],
output: {
exports: "named",
globals: {
vue: "Vue",
},
},
},
},
});
配置 package.json
{
"main": "dist/umd/suju-plus.umd.cjs",
"exports": {
".": {
"require": "./dist/umd/suju-plus.umd.cjs"
},
"./style.css": {
"require": "./dist/umd/style.css"
}
}
}
一个完整的 package.json 实例
{
"name": "suju-plus",
"version": "0.0.2",
"description": "A Vue.js 3.0 UI Toolkit for Web",
"license": "MIT",
"keywords": ["vue3", "components", "library"],
"type": "module",
"module": "dist/es/suju-plus.js",
"main": "dist/umd/suju-plus.umd.cjs",
"exports": {
".": {
"import": "./dist/es/suju-plus.js",
"require": "./dist/umd/suju-plus.umd.cjs"
},
"./style.css": {
"import": "./dist/style.css",
"require": "./dist/umd/style.css"
}
},
"files": ["dist"],
"scripts": {
"dev": "vite",
"build": "pnpm run build:es && pnpm run build:umd",
"build:es": "vite build -c ./vite.es.config.js && pnpm run move-style",
"build:umd": "vite build -c ./vite.umd.config.js",
"move-style": "move-file dist/es/style.css dist/style.css",
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix --ignore-path .gitignore",
"format": "prettier --write src/"
},
"dependencies": {},
"peerDependencies": {
"@vueuse/core": "^10.2.1",
"ant-design-vue": "^4.0.7",
"vue": "^3.3.4"
},
"devDependencies": {
"ant-design-vue": "^4.0.7",
"@ant-design/icons-vue": "6.1.0",
"@rushstack/eslint-patch": "^1.3.3",
"@vitejs/plugin-vue": "^4.4.0",
"@vitejs/plugin-vue-jsx": "^3.0.2",
"@vue/eslint-config-prettier": "^8.0.0",
"@vueuse/core": "^10.2.1",
"autoprefixer": "^10.4.14",
"eslint": "^8.49.0",
"eslint-plugin-vue": "^9.17.0",
"move-file-cli": "^3.0.0",
"postcss": "^8.4.31",
"prettier": "^3.0.3",
"tailwindcss": "2.2.16",
"vite": "^4.4.11",
"vue": "^3.3.4",
"vue-router": "^4.2.5"
}
}
发布组件库
注册 npm 账号
切换 npm 源
npm config set registry https://registry.npmjs.org/
登录 npm 账号
npm login
发布 npm 包
npm publish