首页/文章/vite工具

全网最细使用Vite搭建一个组件库

2024-06-11
15096 分钟
...

先使用vite 搭建基础版本脚手架这里不做讲解、由于vite初始化什么都没有安装、我采用了自己改造过的脚手架

详情见GitHub 内置vue-router、commitlint、stylelint、eslint、prettier、unplugin-vue-components、unplugin-auto-import、lint-staged、sentry、pinia、husky...基本上可以满足团队日常开发需求。

😅言归正传、生成目录大概是这样的

├── README.md
├── commitlint.config.cjs
├── index.html
├── package.json
├── pnpm-lock.yaml
├── public
│   ├── version.txt
│   └── vite.svg
├── src
│   ├── App.vue
│   ├── api
│   │   └── index.ts
│   ├── assets
│   ├── auto-imports.d.ts
│   ├── components
│   ├── components.d.ts
│   ├── global.d.ts
│   ├── hooks
│   ├── intercept.ts
│   ├── main.ts
│   ├── router
│   ├── store
│   ├── utils
│   ├── views
│   ├── vite-env.d.ts
│   └── workers
│       ├── versionCheckWorker.ts
│       └── worker.ts
├── tsconfig.json
├── tsconfig.node.json
└── vite.config.ts

一系列的修改操作

  1. 修改srcpackages,删除views目录
  2. 修改alias把所有和src相关的别名路径修改为components、修改目录为vite.config.tstsconfig.json

 alias: [
        {
            find: "@",
            replacement: resolve(__dirname, "../packages"),
        },
    ],

{
...
 "paths": {
            "@/*": [
                "packages/*"
            ],
          },
...
}
  1. 删除不需要用到的文件夹 store...
  2. 修改index.html中script标签中src路径为 /packages/main.ts
  3. packages 下新建文件夹theme-chalk 后续用来存放样式

修改后的目录结构

├── README.md
├── commitlint.config.cjs
├── index.html
├── package.json
├── pnpm-lock.yaml
├── public
│   ├── version.txt
│   └── vite.svg
├── packages
│   ├── App.vue
│   ├── api
│   ├── assets
│   ├── auto-imports.d.ts
│   ├── components
│   ├── components.d.ts
│   ├── global.d.ts
│   ├── hooks
│   ├── intercept.ts
│   ├── main.ts
│   ├── router
│   ├── store
│   ├── utils
│   └── vite-env.d.ts
├── tsconfig.json
├── tsconfig.node.json
└── vite.config.ts

后续就可以在components文件夹下开发组件了,查看组件的话直接在router上配置路径即可

敲黑板:每个组件必须设置name,不然后续全局注册会有问题 components整体格式如下

├── components
    ├── button
    │   ├──Button.vue
    │   └──index.ts
    └──index.ts

相关代码如下

<!-- Button.vue -->
<template>
    <div class="bq-button">
        <span>-测试按钮-6</span>
    </div>
</template>

<script setup lang="ts">
defineOptions({
    name: "BqButton",
});
</script>

<style lang="scss" scoped>
@import "@theme-chalk/button.scss";
</style>

import Button from "./Button.vue";
import { withInstall } from "../../utils/tool";
export const BqButton = withInstall(Button);
export default BqButton;

withInstall相关方法如下、主要是为了全局注册

import type { App } from "vue";
export const withInstall = <T extends Component>(comp: T) => {
    (comp as Record<string, unknown>).install = (app: App) => {
        const compName = comp.name;
        if (!compName) return;
        app.component(compName, comp);
    };
    return comp;
};

export * from "./button";

这时候我们的组件基本就写好了,查看组件只需要在router下配置路径即可

 {
        path: "/",
        name: "button",
        meta: {
            title: "login",
        },
        component: () => import( "@/components/button/Button.vue"),
    },

先给大家看配置、再给大家讲为什么


import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
import { resolve } from "path";
import { pluginsConfig, resolveConfig } from "./scripts/preview";
import dts from "vite-plugin-dts";
export default defineConfig(() => {
    return {
        build: {
            outDir: "build",
            cssCodeSplit: true,
            rollupOptions: {
                external: ["three", "@ant-design/icons-vue", "ant-design-vue", "unplugin-vue-components", "unplugin-auto-import", "vue"],
                output: [
                    {
                        format: "es",
                        entryFileNames: "[name].js",
                        exports: "named",
                        name: "BqDesign",
                        dir: "./build/dist",
                    },
                    {
                        format: "es",
                        entryFileNames: "[name].js",
                        exports: "named",
                        preserveModules: true,
                        preserveModulesRoot: "packages",
                        dir: "./build/es",
                    },
                    {
                        format: "cjs",
                        entryFileNames: "[name].js",
                        exports: "named",
                        preserveModules: true,
                        preserveModulesRoot: "packages",
                        dir: "./build/lib",
                    },
                ],
            },
            lib: {
                entry: resolve(__dirname, "./packages/index.ts"),
                name: "BqDesign",
                fileName: (format) => `bq-design.${format}.js`,
                formats: ["es", "cjs"],
            },
        },
        plugins: [
            vue(),
            dts({
                tsconfigPath: "./tsconfig.prod.json",
                outDir: "build/lib",
            }),
            dts({
                tsconfigPath: "./tsconfig.prod.json",
                outDir: "build/es",
            }),
            ...pluginsConfig,
        ],
        resolve: resolveConfig,
    };
});

一点一点给大家捋一下为什么这么写

1、为什么output需要这样配置

首先按照官网给的示例配置并执行

打包后,有问题吗?没问题。但就是有点奇怪,因为我们打包后结构是这样的

└── dist
    ├── index.js
    └── style.css

毕竟我们都是见过世面的🤓,为什么我们打包出来的和ant-design-vueElementPlus差距这么大, 其实小编在做这个事情的时候也看了这些优秀的开源组件库、毕竟学习的过程就是先模仿创造

大概看了一下 ElementPlus 是基于vite开发的,ant-design-vue还是webpack、那我们先看一下ElementPlus打包后的结构大概如下

└── build
    ├── dist
    ├── es
    ├── lib
    ├── README.md
    └── package.json

很明显他输出了三个包(说明我们在output中也需要配置3个输出文件)、首先es文件夹用来兼容esm语法、lib文件夹兼容commentJsdist也是esm语法他的css是打包在一个文件里的主要是为了全局引入css,配置好后大概是这个样子

output: [
                    {
                        format: "es",
                        entryFileNames: "[name].js",
                        dir: "./build/dist",
                    },
                    {
                        format: "es",
                        entryFileNames: "[name].js",
                        dir: "./build/es",
                    },
                    {
                        format: "cjs",
                        entryFileNames: "[name].js",
                        dir: "./build/lib",
                    },
                ],

之后我们执行打包脚步 pnpm run build 不报错的情况下打包出来应该已经是有三个文件了,但好像jscss还是在一起,怎么办?当然是看文档了🤑

原来如此、配置后执行打包命令,果然没问题

2、为什么cssCodeSplit是要改为true

因为在vitelib模式下cssCodeSplit默认是false,其实官方有说明,可只在英文文档做了说明🥲

没注意到的打包后所有组件css都在一个文件、后续就没有办法实现我们的按需引入了

3、如何打包出ts类型标注

使用pnpm下载 vite-plugin-dts 该插件

pnpm add vite-plugin-dts -D

由于我们在libes库里都需要打包ts,所以需要配置两个dts,代码如下

  dts({
                tsconfigPath: "./tsconfig.prod.json",
                outDir: "build/lib",
            }),
            dts({
                tsconfigPath: "./tsconfig.prod.json",
                outDir: "build/es",
            }),

tsconfigPath,需要单独引入一个新的tsconfig配置、主要是因为我们打包的include和exclude配置和实际开发中还是有一定区别。并且include配置有问题会导致打包出的类型没有放在实际文件夹下。

新建了一个tsconfig.prod.json文件,代码如下

{
    "extends": "./tsconfig.json",
    "include": [
        "packages/**/*.vue",
        "packages/**/*.d.ts",
        "packages/**/*.ts",
    ],
    "exclude": [
        "./packages/main.ts",
        "node_modules",
        "./packages/router/*"
    ]
}

走到这里其实我们的组件已经小有所成了

一个好的组件离不开一个优秀的文档、这里我推荐大家使用VitePress,相对于市面上其他的文档生成工具VitePress拥有着强大的生态环境和相对稳定的版本,文档地址,根据文档操作,之后会在最外层目录下生成一个docs文件,里面就可以快乐的写我们的文档了,这里就不做演示了。

const BqDesignResolver = () => {
    return {
        type: "component" as const,
        resolve: (name) => {
            if (name.startsWith("Bq")) {
                const pathName = name.slice(2).toLowerCase();
                return {
                    importName: name,
                    from: "bq-design",
                    path: `bq-design/es/components/${pathName}/index.js`,
                    sideEffects: `bq-design/es/components/${pathName}/${name.slice(2)}.css`,
                };
            }
        },
    };
};

更改名称为自己组件库即可

在vite中严格意义上是不需要手动导入,因为Vite提供了基于 ES Module 的开箱即用的Tree Shaking 功能,但有一种情况就是我开发的组件库引入了第三方包,比如threeJs,但在实际运用中,我只引用了我的Button按钮,会报错,因为我们的导出模块是有关联的,实际这么引用

上述情况使用Vite一定要在 optimizeDeps.exclude 添加相应的包如bq-design,因为预加载发现缺少依赖会报错

import {Button} from 'bq-design'

开发环境下是会导出全部的bq-design(生产环境并不会哦),默认情况按需引入需要这样导入

import BqButton from "bq-design/es/components/button";

但这样还存在着无法引入样式的问题,所以我们需要自己开发一个vite插件进行转换,代码如下

export default function importPlugin() {
    const regStr = /(?<!\/\/.*|\/\*[\s\S]*?\*\/\s*)import\s*{\s*([^{}]+)\s*}\s*from\s*['"]bq-design['"]/g;
    return {
        name: "vite-plugin-import",
        enforce: "pre",
        transform: (code: string, id: string) => {
            if (id.endsWith(".vue")) {
                const str = code.replaceAll(regStr, (match, imports) => {
                    const list = imports.split(",");
                    const newPath: string[] = [];
                    list.forEach((item: string) => {
                        item = item.trim();
                        const name = item.slice(2).charAt(0).toLowerCase() + item.slice(3);
                        const str = `import ${item.trim()} from 'bq-design/es/components/${name.trim()}';
                        import 'bq-design/es/components/${name.trim()}/${item.trim().slice(2)}.css'`;
                        newPath.push(str);
                    });
                    return newPath.join(";");
                });
                return str;
            }
            return code;
        },
    };
}

Webpack用户可以使用 babel-plugin-import 进行处理同样这也是ant-design-vue的处理方式

这是小编自己搭建的组件库地址

biuat.ibaiqiu.com/bq-design/

相关github地址

github.com/Js-Man-H5/b…

如果您觉得这篇文章有帮助,请点个赞吧~

分享文章

相关文章

更多文章 →
vite工具2026-03-17
深度解析:NODE_ENV 与 Mode (模式)
在现代前端开发中,尤其是使用 Vite 、 Qwik 、 Next.js 等基于 Node.js 的构建工具时,开发者经常会被两个相似的概念绕晕: 和 Mode (模式) 。 它们看起来都在做同一件事:“区分开发环境和生产环境”。但实际上,它们在架构设计中扮演着截然不同却又紧密协作的角色。混淆这两者可能导致构建配置错误、环境变量加载失败,甚至生产环境泄露敏感信息。 一、核心定义:它们到底是什么? 1\. :行业通用的“运行时开关” 起源...
学习
vite工具2025-10-01
vite常用配置
目录 1\. 基础配置 1.1 项目初始化 1.2 基础 vite.config.js 配置 配置说明与最佳实践 插件配置 (plugins) 好处 : 插件系统是Vite的核心特性,提供了丰富的功能扩展能力 坏处 : 过多插件会增加构建时间,插件冲突可能导致构建失败 建议 : 只引入必要的插件,定期检查插件更新和兼容性 适用场景 : 所有Vite项目都需要根据技术栈选择合适的插件 开发服务器配置 (server) host: ‘0.0...
学习
vite工具2025-06-04
Vite 项目中使用 vite-plugin-dts 插件的详细指南
在现代前端开发中,TypeScript 的类型声明文件( )对于提供良好的开发体验和代码提示至关重要。如果你正在使用 Vite 构建一个库项目, 插件是一个非常有用的工具,它可以帮助你自动生成 文件。以下是如何在你的 Vite 项目中安装、配置和使用 插件的详细指南。 一、插件介绍 是一个用于在 Vite 的库模式下,从 或 源文件生成类型文件( )的插件。它能够帮助开发者在构建库时,自动生成类型声明文件,从而提高开发效率。 二、安装插...
学习
vite工具2025-03-11
vite项目打包build后提示说超过500k了
说可以通过配置build.rollupOptions.output.manualChunks来提升一下,好可以,我来配置一下,把那些可能大的包单独分配一下: 然后再看一下,是变小了,但是还是500警告啊: 那就开始分析是哪个包比较大吧,使用rollup plugin visualizer这个插件来分析一下,rollup plugin visualizer是一个开源项目,地址: 安装: 配置插件 在 文件中添加 插件的配置,如下: 构建完...
学习
vite工具2024-10-10
一次低端机 WebView 白屏的兼容之路
问题 项目:Vite4 + Vue3,APP WebView 项目 页面在 OPPO A5 手机上打不开,页面空白。 最开始是客户端在看,然后发现一个警告,大概也因为没看出什么问题,给到 Web 前端。 相关背景 为了方便描述过程的行为,先做一些相关背景的介绍。知道这些背景才能更好的了解问题的复杂。这些在解决问题的过程中始终是干扰因素,在反复调试试错的过程中才梳理总结出来,这里把它们列出来。 使用测试 App,其中有两个入口,一个是本地...
学习
vite工具2024-09-09
推荐工具vite-plugin-fake-server,可线上部署使用mockmock线上部署
最近遇到了个麻烦,后端迟迟给不了接口,测试那边又要求数据不能写死,必须可以提供mock调试。这不最近找到了一个mock工具,能解决传统mock工具无法线上部署的问题。 工具名字叫做 ,兼容vite,从官网示例上来看是同时支持 和 来模拟数据的。使用起来也非常简单,分三步走就行。 1. 安装 2. 引入 这里贴出最简单的配置,一个是制定文件夹,一个是设置在生产环境下模拟数据。 3. 使用 这里我根据个人习惯,在 文件夹下创建一个 和数个模...
学习

评论

请登录后发表评论

去登录
加载评论中...

目录