开始发布
如果打包和发布流程你想做到自动化控制,你可以先点个赞,然后直接阅读 从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文件
现在我已经将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
创作不易,你的点赞就是我的动力!如果感觉对自己有帮助的话就请点个赞吧,感谢~
如果你对组件开发感兴趣的话欢迎关注下面的专栏
说明
组件库最新代码导出方式写法有所改变,源码可能和文章有所出入,请注意查看