使用Vite和TypeScript带你从零打造一个属于自己的Vue3组件库(下)

简介: 使用Vite和TypeScript带你从零打造一个属于自己的Vue3组件库(下)

开始发布



如果打包和发布流程你想做到自动化控制,你可以先点个赞,然后直接阅读 从0搭建Vue3组件库:使用gulp自动化处理打包与发布 当然你也可以继续往下阅读,看下本篇文章的处理方式


做了那么多终于到发布的阶段了;其实npm发包是很容易的,就拿我们的组件库kitty-ui举例吧


发布之前记得到npm官网注册个账户,如果你要发布@xx/xx这种包的话需要在npm新建个组织组织组织名就是@后面的,比如我建的组织就是kitty-ui,注册完之后你就可以发布了

首先要将我们代码提交到git仓库,不然pnpm发布无法通过,后面每次发版记得在对应包下执行 pnpm version patch你就会发现这个包的版本号patch(版本号第三个数) +1 了,同样的 pnpm version major major和 pnpm version minor 分别对应版本号的第一和第二位增加。

如果你发布的是公共包的话,在对应包下执行

pnpm publish --access public

输入你的账户和密码(记得输入密码的时候是不显示的,不要以为卡了)正常情况下应该是发布成功了


注意

发布的时候要将npm的源切换到npm的官方地址(registry.npmjs.org/); 如果你使用了其它镜像源的话


样式问题



引入我们打包后的组件你会发现没有样式,所以你需要在全局引入我们的style.css才行;如 main.ts中需要

import 'kitty-ui/es/style.css';

很显然这种组件库并不是我们想要的,我们需要的组件库是每个css样式放在每个组件其对应目录下,这样就不需要每次都全量导入我们的css样式。


下面就让我们来看下如何把样式拆分打包


处理less文件


首先我们需要做的是将less打包成css然后放到打包后对应的文件目录下,我们在components下新建build文件夹来存放我们的一些打包工具,然后新建buildLess.ts,首先我们需要先安装一些工具cpy和fast-glob

pnpm i cpy fast-glob -D -w
  • cpy

它可以直接复制我们规定的文件并将我们的文件copy到指定目录,比如buildLess.ts:

import cpy from 'cpy'
import { resolve } from 'path'
const sourceDir = resolve(__dirname, '../src')
//lib文件
const targetLib = resolve(__dirname, '../lib')
//es文件
const targetEs = resolve(__dirname, '../es')
console.log(sourceDir);
const buildLess = async () => {
    await cpy(`${sourceDir}/**/*.less`, targetLib)
    await cpy(`${sourceDir}/**/*.less`, targetEs)
}
buildLess()

然后在package.json中新增命令

...
"scripts": {
    "build": "vite build",
    "build:less": "esno build/buildLess"
  },
...

终端执行 pnpm run build:less 你就会发现lib和es文件对应目录下就出现了less文件.

但是我们最终要的并不是less文件而是css文件,所以我们要将less打包成css,所以我们需要用的less模块.在ts中引入less因为它本身没有声明文件所以会出现类型错误,所以我们要先安装它的 @types/less

pnpm i --save-dev @types/less -D -w
buildLess.ts如下(详细注释都在代码中)


import cpy from 'cpy'
import { resolve, dirname } from 'path'
import { promises as fs } from "fs"
import less from "less"
import glob from "fast-glob"
const sourceDir = resolve(__dirname, '../src')
//lib文件目录
const targetLib = resolve(__dirname, '../lib')
//es文件目录
const targetEs = resolve(__dirname, '../es')
//src目录
const srcDir = resolve(__dirname, '../src')
const buildLess = async () => {
    //直接将less文件复制到打包后目录
    await cpy(`${sourceDir}/**/*.less`, targetLib)
    await cpy(`${sourceDir}/**/*.less`, targetEs)
    //获取打包后.less文件目录(lib和es一样)
    const lessFils = await glob("**/*.less", { cwd: srcDir, onlyFiles: true })
    //遍历含有less的目录
    for (let path in lessFils) {
        const filePath = `${srcDir}/${lessFils[path]}`
        //获取less文件字符串
        const lessCode = await fs.readFile(filePath, 'utf-8')
        //将less解析成css
        const code = await less.render(lessCode, {
            //指定src下对应less文件的文件夹为目录
            paths: [srcDir, dirname(filePath)]
        })
        //拿到.css后缀path
        const cssPath = lessFils[path].replace('.less', '.css')
        //将css写入对应目录
        await fs.writeFile(resolve(targetLib, cssPath), code.css)
        await fs.writeFile(resolve(targetEs, cssPath), code.css)
    }
}
buildLess()

执行打包命令之后你会发现对应文件夹下多了.css文件

image.png

现在我已经将css文件放入对应的目录下了,但是我们的相关组件并没有引入这个css文件;所以我们需要的是每个打包后组件的index.js中出现如:

import "xxx/xxx.css"

之类的代码我们的css才会生效;所以我们需要对vite.config.ts进行相关配置

首先我们先将.less文件忽略

external: ['vue', /\.less/],

这时候打包后的文件中如button/index.js就会出现

import "./style/index.less";

然后我们再将打包后代码的.less换成.css就大功告成了

...
plugins: [
            ...
            {
                name: 'style',
                generateBundle(config, bundle) {
                    //这里可以获取打包后的文件目录以及代码code
                    const keys = Object.keys(bundle)
                    for (const key of keys) {
                        const bundler: any = bundle[key as any]
                        //rollup内置方法,将所有输出文件code中的.less换成.css,因为我们当时没有打包less文件
                        this.emitFile({
                            type: 'asset',
                            fileName: key,//文件名名不变
                            source: bundler.code.replace(/\.less/g, '.css')
                        })
                    }
                }
            }
        ...
        ]
...

我们最终的vite.config.ts如下

import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue"
import dts from 'vite-plugin-dts'
export default defineConfig(
    {
        build: {
            target: 'modules',
            //打包文件目录
            outDir: "es",
            //压缩
            minify: false,
            //css分离
            //cssCodeSplit: true,
            rollupOptions: {
                //忽略打包vue和.less文件
                external: ['vue', /\.less/],
                input: ['src/index.ts'],
                output: [
                    {
                        format: 'es',
                        //不用打包成.es.js,这里我们想把它打包成.js
                        entryFileNames: '[name].js',
                        //让打包目录和我们目录对应
                        preserveModules: true,
                        //配置打包根目录
                        dir: 'es',
                        preserveModulesRoot: 'src'
                    },
                    {
                        format: 'cjs',
                        //不用打包成.mjs
                        entryFileNames: '[name].js',
                        //让打包目录和我们目录对应
                        preserveModules: true,
                        //配置打包根目录
                        dir: 'lib',
                        preserveModulesRoot: 'src'
                    }
                ]
            },
            lib: {
                entry: './index.ts',
                formats: ['es', 'cjs']
            }
        },
        plugins: [
            vue(),
            dts({
                //指定使用的tsconfig.json为我们整个项目根目录下掉,如果不配置,你也可以在components下新建tsconfig.json
                tsConfigFilePath: '../../tsconfig.json'
            }),
            //因为这个插件默认打包到es下,我们想让lib目录下也生成声明文件需要再配置一个
            dts({
                outputDir: 'lib',
                tsConfigFilePath: '../../tsconfig.json'
            }),
            {
                name: 'style',
                generateBundle(config, bundle) {
                    //这里可以获取打包后的文件目录以及代码code
                    const keys = Object.keys(bundle)
                    for (const key of keys) {
                        const bundler: any = bundle[key as any]
                        //rollup内置方法,将所有输出文件code中的.less换成.css,因为我们当时没有打包less文件
                        this.emitFile({
                            type: 'asset',
                            fileName: key,//文件名名不变
                            source: bundler.code.replace(/\.less/g, '.css')
                        })
                    }
                }
            }
        ]
    }
)

最后我们将打包less与打包组件合成一个命令(package.json):

...
"scripts": {
    "build": "vite build & esno build/buildLess"
  },
...

后续直接执行pnpm run build 即可完成所有打包啦


直接使用



如果你不想一步步的搭建,想直接使用现成的话,你可以直接把项目clone下来->kittyui,然后你只需要以下几步便可将其完成

  • 安装pnpm npm i pnpm -g
  • 安装esno npm i esno -g
  • 安装所有依赖 pnpm install
  • 本地测试 进入examples文件夹执行 pnpm run dev 启动vue3项目
  • 打包 pnpm run build
  • 启动文档 pnpm run docs:dev
  • 打包文档 pnpm run docs:build
  • 启动打包后文档服务 pnpm run docs:serve


写在最后



由于作者水平有限,难免会存在一些错误或不妥之处,希望各位能够不吝指出,一定及时修改。如果你对这个项目有更好的想法或者建议也欢迎在评论区提出,不胜感激。

后续我会对一些常用组件进行开发,每个组件的开发都会以文章的形式展现出来以供大家参考。也欢迎大家将项目fork下来,提交自己组件或者对kittyui的修改到kittyui

创作不易,你的点赞就是我的动力!如果感觉对自己有帮助的话就请点个赞吧,感谢~

如果你对组件开发感兴趣的话欢迎关注下面的专栏


说明



组件库最新代码导出方式写法有所改变,源码可能和文章有所出入,请注意查看



相关文章
|
3月前
|
JavaScript 前端开发 IDE
[译] 用 Typescript + Composition API 重构 Vue 3 组件
[译] 用 Typescript + Composition API 重构 Vue 3 组件
[译] 用 Typescript + Composition API 重构 Vue 3 组件
|
13天前
|
JavaScript 前端开发
Vue2整合TypeScript:借助vue-property-decorator以类模式编写组件
Vue2整合TypeScript:借助vue-property-decorator以类模式编写组件
72 3
|
22天前
|
JavaScript 安全 开发工具
在 Vue 3 中使用 TypeScript
【10月更文挑战第3天】
|
24天前
|
JavaScript 前端开发 安全
使用 TypeScript 加强 React 组件的类型安全
【10月更文挑战第1天】使用 TypeScript 加强 React 组件的类型安全
35 3
|
3月前
|
JSON JavaScript IDE
[译] 使用 microbundle 打包 TypeScript 组件库
[译] 使用 microbundle 打包 TypeScript 组件库
|
3月前
|
JavaScript API
如何使用Vue 3和Type Script进行组件化设计
【8月更文挑战第16天】如何使用Vue 3和Type Script进行组件化设计
39 3
|
3月前
|
JavaScript API
如何使用Vue 3和Type Script进行组件化设计
【8月更文挑战第16天】如何使用Vue 3和Type Script进行组件化设计
54 1
|
3月前
|
JavaScript 前端开发 安全
立等可取的 Vue + Typescript 函数式组件实战
立等可取的 Vue + Typescript 函数式组件实战
|
3月前
|
资源调度 JavaScript 前端开发
Vue3+TypeScript前端项目新纪元:揭秘高效事件总线Mitt,轻松驾驭组件间通信的艺术!
【8月更文挑战第3天】Vue3结合TypeScript强化了类型安全与组件化开发。面对大型应用中复杂的组件通信挑战,可通过引入轻量级事件发射器Mitt实现事件总线模式。Mitt易于集成,通过简单几步即可完成安装与配置:安装Mitt、创建事件总线实例、并在组件中使用`emit`与`on`方法发送及监听事件。此外,利用TypeScript的强大类型系统确保事件处理器正确无误。这种方式有助于保持代码整洁、解耦组件,同时提高应用的可维护性和扩展性。不过,在大规模项目中需谨慎使用,以防事件流过于复杂难以管理。
102 1
|
3月前
|
JavaScript 前端开发 安全
解锁Vue3与TypeScript的完美搭档:getCurrentInstance带你高效打造未来前端
【8月更文挑战第21天】Vue3的getCurrentInstance方法作为Composition API的一部分,让开发者能在组件内访问实例。结合TypeScript,可通过定义组件实例类型实现更好的代码提示与类型检查,提升开发效率与代码质量。例如,定义一个带有特定属性(如myData)的组件实例类型,可以在setup中获取并安全地修改这些属性。这种方式确保了一致性和减少了运行时错误,使开发更加高效和安全。
91 0