如何写一个ui组件库(Vue)
一、创建Vue项目,组件库需要依赖Vue框架开发,这里我们使用vite构建一个Vue项目
命令行创建app
npm init vite@latest myuiapp -- --template vue
二、组件化开发,创建一个UI文件夹,在文件夹编写组件,如Button、Radio等
Button.vue 注意此处多加一个button文件夹使打包目录更清晰啊,满足按需引入
<template>
<!-- Your template code here -->
我的按钮组件 <button class="btn"></button>
</template>
<script setup>
// Your script setup code here
</script>
<script>
export default {
name: 'Button',
};
</script>
<style scoped>
.btn {
background-color: bisque;
}
/* Your style code here */
</style>
三、编写入口index.js文件,入口文件需要导入我们的所有组件,当执行Install方法的时候再Vue中注册所有组件
index.js
import Button from './button.vue';
// 将组件注册为全局组件
const components = [Button];
const install = (Vue) => {
components.forEach((component) => {
if (component.name) {
console.log(component.name, 'component.name');
Vue.component(component.name, component); // 使用传入的 Vue 参数
} else {
console.warn('组件缺少 name 属性', component);
}
});
};
// 检查是否已经安装
if (typeof window !== 'undefined' && window.Vue) {
install(window.Vue);
}
// 导出组件库
export default {
install,
};
export { Button };
从main.js引入入口文件并且Vue.use去挂载,然后使用我们的组件看看是否正常
import { createApp } from 'vue';
import './style.css';
import App from './App.vue';
import myui from './ui/index';
const app = createApp(App);
app.mount('#app');
app.use(myui);
四、配置package.json
{
"name": "dist",
"version": "0.0.0",
"private": true,
"author": {
"name": "author",
"email": "2876920450@qq.com"
},
"scripts": {
"build": " vite build "
},
"dependencies": {
"vue": "^3.5.12"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.1.4",
"vite": "^5.4.9"
}
}
五、配置在ui目录下配置vite.config.json
// import { VantResolver } from '@vant/auto-import-resolver';
import vue from '@vitejs/plugin-vue';
import fs from 'fs';
import path from 'path';
import { defineConfig } from 'vite';
import { name } from './package.json';
export default defineConfig((mode) => {
const outDir = mode === 'production' ? 'dist' : name;
return {
base: `/${name}`,
build: {
// target: 'modules',/
cssCodeSplit: true,
outDir,
minify: false,
lib: {
//库打包模式
// entry: './index.js',
entry: './index.js',
name: 'my-ui',
fileName: 'index',
formats: ['esm', 'cjs'], //文件输出格式
},
rollupOptions: {
//忽略以下依赖
external: ['vue', 'vant', 'clsx', 'tailwind-merge', 'class-variance-authority', 'radix-vue'],
output: [
{
//打包格式
format: 'esm',
//打包后文件名
entryFileNames: '[name].mjs',
//让打包目录和我们目录对应
preserveModules: true,
exports: 'named',
//配置打包根目录
dir: `./${name}/es`,
preserveModulesRoot: '', //隐藏某目录
},
{
//打包格式
format: 'cjs',
//打包后文件名
entryFileNames: '[name].js',
//让打包目录和我们目录对应
preserveModules: true,
exports: 'named',
dir: `./${name}/lib`,
preserveModulesRoot: '',
},
],
},
},
plugins: [
vue(),
//将所有的css集成在外层的style中
{
name: 'combine-css',
closeBundle() {
const esDir = path.resolve(__dirname, `${name}/es`); // 根打包目录
const libDir = path.resolve(__dirname, `${name}/lib`); // 根打包目录
const esCssPath = path.resolve(esDir, 'style.css');
const libCssPath = path.resolve(libDir, 'style.css');
let combinedCss = '';
// 递归遍历 dist 目录及其子目录,找到所有 .css 文件
function findCssFiles(dir) {
const files = fs.readdirSync(dir);
files.forEach((file) => {
const filePath = path.join(dir, file);
const stat = fs.statSync(filePath);
if (stat.isDirectory()) {
// 如果是目录,递归遍历
findCssFiles(filePath);
} else if (file.endsWith('.css')) {
// 如果是 CSS 文件,读取并合并内容
const cssContent = fs.readFileSync(filePath, 'utf-8');
combinedCss += cssContent + '\n';
}
});
}
// 开始递归查找
findCssFiles(esDir);
// 将合并后的 CSS 写入到 combined.css
fs.writeFileSync(esCssPath, combinedCss);
fs.writeFileSync(libCssPath, combinedCss);
},
},
],
};
});
六、进入ui目录,npm run build进行打包,得到我们打包产物
七、将打包产物发布到npm包
在dist包目录下新建package.json文件夹
这里可以看npm官网发包的配置项
{
"name": "ui-ui",
"version": "1.0.2",
"description": "组件库",
"private": false,
"main": "./dist/lib/index.mjs",
"module": "./dist/es/index.mjs",
"license": "MIT",
"author": "author",
"files": [
"es",
"lib"
],
"scripts": {
"build": "vite build "
},
"dependencies": {
"vue": "^3.4.21"
},
"devDependencies": {
"vue": "^3.4.21"
}
}
命令行进入dist目录 登录远程npm(如果没有需要去npm官网注册)
npm login
发布命令
npm publish --access=public //发布命令
npm pack// 发包之前看看包格式