如何写一个ui组件库(Vue)

638 阅读2分钟

如何写一个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// 发包之前看看包格式