使用monorepo发布vue3组件库
安装pnpm
npm install pnpm -g
初始化package.json
pnpm init
新建配置文件 .npmrc
- 在根目录下新建.npmrc文件,并写入如下内容
shamefully-hoist = true
::: tip 注意
如果某些工具仅在根目录的node_modules时才有效,可以将其设置为true来提升那些不在根目录的node_modules,就是将你安装的依赖包的依赖包的依赖包的...都放到同一级别(扁平化)。说白了就是不设置为true有些包就有可能会出问题。
:::
安装依赖包:vue@next、typescript、sass
pnpm i vue@next typescript sass -D -w
::: tip 注意
我们开发环境中的依赖一般全部安装在整个项目根目录下,方便下面我们每个包都可以引用,所以在安装的时候需要加个 -w ,-w 代表工作区(workspace)
:::
初始化tsconfig.json
- 初始化
npx tsc --init
- 配置tsconfig.json
//tsconfig.json
{
"compilerOptions": {
"baseUrl": ".",
"jsx": "preserve",
"strict": true,
"target": "ES2015",
"module": "ESNext",
"skipLibCheck": true,
"esModuleInterop": true,
"moduleResolution": "Node",
"lib": ["esnext", "dom"]
}
}
monorepo实现
介绍
一个仓库多个项目
新建pnpm-workspace.yaml
-
根目录下新建pnpm-workspace.yaml
-
配置yaml
# pnpm-workspace.yaml
packages:
- 'packages/**'
- 'examples'
::: tip 注意
为了我们各个项目之间能够互相引用我们要新建一个pnpm-workspace.yaml文件将我们的包关联起来
:::
搭建utils包
介绍
utils是公共库包
创建utils目录
- 手动创建utils目录
进入utils文件夹
cd utils
初始化package.json
pnpm init
- 配置package.json
{
"name": "@quick-vue3-ui/utils",//utils修改为@quick-vue3-ui/utils
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
待完善
搭建components库包
介绍
components是组件包
创建packages目录
- 手动创建packages目录
创建components包
- 手动在packages目录下创建components文件夹
进入components文件夹
cd components
初始化package.json
pnpm init
- 配置package.json
{
"name": "@quick-vue3-ui/components",//components修改为@quick-vue3-ui/components
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
开发一个button组件 (正式进入核心区)
-
在components目录下新建src目录
-
在src目录下新建button目录
-
button目录下新建button.vue文件
<!-- button/button.vue 此处使用的是vue3.0方式,为了是增加组件名称方便。3.2需要特殊处理才可以增加组件名称 -->
<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
name:'QuickButton'
})
</script>
<template>
<button>我是按钮</button>
</template>
- button目录下新建index.ts文件,(局部导出)
// button/index.ts
import Button from './button.vue'
export default Button
导出所有组件,供局部导入使用(局部导出)
// components/src/index.ts
import Button from "./button";
export { Button as QuickButton };
导出增加版本及相关信息(全局导出)
- components目录下新建index.ts
// components/index.ts
import pack from '../../package.json'
import * as components from './src/index'
export * from './src/index'
const install =(app: any) => {
for (const comkey in components) {
app.component((components as any)[comkey].name, (components as any)[comkey])
}
}
export default {
name: pack.name,
version: pack.version,
install,
}
暂时告一段落,如下测试
----------------------------------------
## 搭建examples包
### 介绍
examples基于vite+vue3,目的用于调试组件
### 创建examples包
- 手动创建examples文件夹
### 进入examples文件夹
```sh
cd examples
初始化package.json
pnpm init
安装vite、@vitejs/plugin-vue
pnpm install vite @vitejs/plugin-vue -D -w
配置vite.config.ts
//vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
plugins:[vue()]
})
创建入口html文件
- 手动创建index.html
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>examples</title>
</head>
<body>
<div id="app"></div>
<script src="src/main.ts" type="module"></script>
</body>
</html>
创建src目录
创建根组件
-
手动创建app.vue文件
-
配置app.vue
<!-- src/app.vue -->
<template>
<div>
测试
</div>
</template>
创建入口ts
-
手动创建main.ts文件
-
配置main.ts
//src/main.ts
import {createApp} from 'vue'
import App from './app.vue'
const app = createApp(App)
app.mount('#app')
配置启动命令
// package.json
...
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "vite"//新增
},
...
运行
pnpm run dev
::: tip 注意
如上没有问题才能按照下面的进行
包之间本地调试(全局安装)由于组件库是基于ts的,所以需要安装esno来执行ts文件便于测试包之间的引入情况
npm i esno -g
# 哪里用就切换到那个包下执行,例如:examples要用那么就 cd examples 然后执行安装依赖命令即可
pnpm install @quick-vue3-ui/utils
pnpm install @quick-vue3-ui/components
:::
安装组件库的依赖
pnpm i @quick-vue3-ui/components
全局导入
- main.ts中导入
//examples/src/main.ts
import {createApp} from 'vue'
import quickVue3UI from '@quick-vue3-ui/components' //++
import App from './app.vue'
const app = createApp(App)
app.use(quickVue3UI) //++
app.mount('#app')
局部导入
- app.vue中导入
//examples/src/app.vue
<script lang="ts" setup>
import {QuickButton} from '@quick-vue3-ui/components'
</script>
<template>
<div>
<quick-button></quick-button>
</div>
</template>
发布到npm
打包组件库
::: tip 注意
vite提供了库模式,下面我们来配置。
:::
打包配置
::: tip 注意
这里我们选择打包cjs(CommonJS)和esm(ESModule)两种形式,cjs模式主要用于服务端引用(ssr),而esm就是我们现在经常使用的方式,它本身自带treeShaking而不需要额外配置按需引入(前提是你将模块分别导出)。
:::
-
在components包下新建vite.config.ts文件
-
配置vite.config.ts
//components/vite.config.ts
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue"
export default defineConfig(
{
build: {
target: 'modules',
//打包文件目录
outDir: "es",
//压缩
minify: false,
//css分离
//cssCodeSplit: true,
rollupOptions: {
//忽略打包vue文件
external: ['vue'],
input: ['src/index.ts'],
output: [
{
format: 'es',
//不用打包成.es.js,这里我们想把它打包成.js
entryFileNames: '[name].js',
//让打包目录和我们目录对应
preserveModules: true,
//配置打包根目录
dir: 'es',
preserveModulesRoot: 'src'
},
{
format: 'cjs',
entryFileNames: '[name].js',
//让打包目录和我们目录对应
preserveModules: true,
//配置打包根目录
dir: 'lib',
preserveModulesRoot: 'src'
}
]
},
lib: {
entry: './index.ts',
formats: ['es', 'cjs']
}
},
plugins: [
vue()
]
}
)
打包
- 配置package.json
...
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build":"vite build"//++
},
...
- 打包命令
pnpm run build
- 打包后
::: tip 注意
其实到这里就已经可以直接打包了;components下执行: pnpm run build你就会发现打包了es和lib两个目录。
到这里其实打包的组件库只能给js项目使用,在ts项目下运行会出现一些错误,而且使用的时候还会失去代码提示功能,这样的话我们就失去了用ts开发组件库的意义了。所以我们需要在打包的库里加入声明文件(.d.ts)。
:::
- 配置d.ts
那么如何向打包后的库里加入声明文件呢? 其实很简单,只需要引入vite-plugin-dts
pnpm i vite-plugin-dts -D -w
- 再次配置vite.config.ts
//components/vite.cofig.ts
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue"
import dts from 'vite-plugin-dts'
export default defineConfig(
{
build: {...},
plugins: [
vue(),
dts({
//指定使用的tsconfig.json为我们整个项目根目录下掉,如果不配置,你也可以在components下新建tsconfig.json
tsConfigFilePath: '../../tsconfig.json'
}),
//因为这个插件默认打包到es下,我们想让lib目录下也生成声明文件需要再配置一个
dts({
outputDir:'lib',
tsConfigFilePath: '../../tsconfig.json'
})
]
}
)
::: tip 注意
因为这个插件默认打包到es下,我们想让lib目录下也生成声明文件需要再配置一个dts插件,暂时没有想到其它更好的处理方法.
然后执行打包命令你就会发现你的es和lib下就有了声明文件
:::
发布组件库
::: tip 注意
其实后面就可以进行发布了,发布之前更改一下我们components下的package.json如下:
:::
{
"name": "quick-vue3-ui",
"version": "1.0.1",
"private": false,//这个很关键,如果为true,不能发布
"description": "quick-vue3--ui组件库",
"main": "lib/index.js",
"module":"es/index.js",
"typings": "lib/index.d.ts",
"files": [
"es",
"lib"
],
"scripts": {
"build":"vite build"
},
"keywords": [
"quick-vue3-ui",
"quick-vue3--ui组件库"
],
"author": "zhanglp",
"license": "MIT"
}
- 如果是第一次
::: tip 注意
-
去npm官网注册、登录及相关信息修改
-
使用pnpm登录、发布
-
发布使用镜像必须是npm(如果是淘宝镜像恢复回npm)
-
发布前修改package.json版本并执行build命令。
::: -
注册
- 登录
pnpm login
Username: 迷的账号
Password: 你的密码
Email: (this IS public) 你的邮箱
Enter one-time password: 邮箱验证码
- 发布
- 非第一次
pnpm publish 即可
常见错误
-
错误:
::: tip 注意
ERROR --workspace-root may only be used inside a workspace
::: -
解决方案:
比如:去掉 后面的 -w
pnpm i vue@next typescript sass -D -w
暂时忽略,找解决方案中。。。
- 错误
::: tip 注意
找不到模块“./app.vue”或其相应的类型声明。ts
:::
- 解决方案:
//src/env.d.ts
declare module '*.vue' {
import type { DefineComponent } from 'vue'
const component: DefineComponent<{}, {}, any>
export default component
}