初始化项目
使用vue-press作为文档框架,使用vue3+ts+vite作为组件库和测试项目框架,Pnpm Workspaces 作为 Monorepo 项目的依赖管理工具
新建一个文件夹,根据vue-press的官方文档,在根目录下安装了vue-press,同时使用vite初始化组件库项目。
修改组件库项目package.json
修改name字段为组件库名字 修改入口文件字段mian为组件库项目入口文件。
// package.json部分配置
{
"name": "test-ui",
"private": true,
"version": "1.0.0",
"type": "module", // 指定当前包的模块类型。当设置为 "module" 时,Node.js 会将所有 .js 文件视为 ES 模块(ESM),而不是 CommonJS 模块(CJS)。
"files": [
"dist" // 指定发布到 npm 时,包含在包中的文件和目录。
],
"main": "./main.ts", // 定义该包的入口文件,用于 CommonJS 规范。项目中有代码使用 require('your-package-name') 引入此包时,会加载 main 字段指定的文件。
"types": "./main.ts", // 指定 TypeScript 的类型声明文件路径。告诉 TypeScript 编译器在使用该包时引用的 .d.ts 文件位置,以便在使用此包时提供类型提示。ps: 针对打包后的文件地址,开发环境可以不指定。
"module": "./main.ts" // 定义该包的 ES Module 入口文件。项目中使用 import 语法引入此包(如 import something from 'your-package-name'),会加载 module 字段指定的文件。
}
配置workspace
根目录新建一个 pnpm-workspace.yaml
,将组件库目录作为包进行管理,该文件里的项目都可以被共享
packages:
# all packages in direct subdirs of packages/
- 'lib/*'
需要注意的是:
在任意一个目录下,安装库时,如果不添加--filter参数,会安装工作区根目录下,并且就算其它项目没有在package.json里指定使用这个库,也能正常使用。
组件库配置
全局导入
建立一个Components文件夹用来存放组件,main.ts里导出组件,需要提供一个install方法,以便于使用项目全局注册 使用app.copmponent方法全局注册组件。
import './style.css'
import YButton from './components/YButton/install'
import YInput from './components/YInput/install'
import { App } from 'vue'
const components = [
{ name: 'YButton', component: YButton },
{ name: 'YInput', component: YInput },
]
const install = (app: App): void => {
components.forEach((component) => {
app.component(component.name, component.component)
})
}
export default { install }
类型声明 (开发模式下)
如果希望组件库能有类型声明,我这里是使用了unplugin-vue-components帮我自动生成了全局组件的类型文件components.d.ts
/* eslint-disable */
// @ts-nocheck
// Generated by unplugin-vue-components
// Read more: https://github.com/vuejs/core/pull/3399
export {}
/* prettier-ignore */
declare module 'vue' {
export interface GlobalComponents {
YButton: typeof import('./components/YButton/index.vue')['default']
YInput: typeof import('./components/YInput/index.vue')['default']
}
}
需要在vite.config.ts里写上:
import Components from 'unplugin-vue-components/vite'
export default defineConfig({
plugins: [
Components({
dts: true,
})
]
})
并且希望在工作区中组件库的类型声明正常的话,需要在使用项目中的tsconfig.json中,为types字段添加属性:
compilerOptions: {
"types": ["test-ui/components.d.ts"] // 或者使用相对路径也是可以的
}
类型声明(生产模式下)待验证
这里使用vite-plugin-dts插件来生成类型文件
import dts from 'vite-plugin-dts'
export default defineConfig({
plugins: [
dts({
outDir: 'dist', // 输出目录
insertTypesEntry: true, // 自动插入 types 入口
tsconfigPath: './tsconfig.json', // 如果是vite生成的项目,需要指明为./tsconfig.app.json
}),
]
})
并且package.json中的types字段需要指明为dist下的路径。会生成一个总的.d.ts文件以及根据目录也会生成一个目录级的type文件
按需加载
按需引用目前是依赖于esm的treeshaking。所以想要支持按需引入那么必然使用的是module
入口,module
入口它是个统一的入口,这个文件中显然导出了所有组件,那么比如我们只导出Button
组件,其他没有用到的组件最终是不是不会被打包进去呢,实际上并没有这么简单,因为有的文件它会存在副作用,比如修改了原型链、设置了全局变量等,所以虽然没有显式的被使用,但是只要引入了该文件,副作用就生效了,所以不能被删除,要解决这个问题需要在package.json
中再配置一个sideEffects
字段,指明哪些文件是存在副作用的,没有指明的就是没有副作用的,那么构建工具就可以放心的删除了。
目前我的vite.config.ts中的构建配置为:
build: {
outDir: './dist',
lib: {
entry: resolve(__dirname, './src/main.ts'),
name: 'test-ui',
fileName: 'test-ui',
formats: ['es', 'cjs'], // 输出不同格式
},
}
这样打出来的包会生成两种格式:js和cjs,而且是一个大的文件。我们需要按需加载肯定不能只要一个大文件。这个时候,得重新改下打包的配置:
build: {
outDir: './dist',
lib: {
entry: resolve(__dirname, './src/main.ts'),
name: 'test-ui',
fileName: 'test-ui',
},
rollupOptions: {
external: ['vue'],
output: [
{
format: 'es', // ES Module 格式
dir: 'dist/es', // 输出目录
preserveModules: true, // 保持模块独立
entryFileNames: '[name].mjs',
},
{
format: 'cjs', // CJS 格式
dir: 'dist/cjs', // 输出到 dist/cjs 目录
preserveModules: true, // 保持模块独立
entryFileNames: '[name].cjs', // 指定输出文件名称
},
],
},
}
如果想要测试是否实现了按需加载,在开发环境下是无法测试的,为了模拟真实的场景,我们需要构建后测试。此时,我们使用两款工具来进行测试:yalc
和rollup-plugin-visualizer
yalc
对标npm/yarn link,但是模拟的是真实发布的场景,不会存在link中存在的软链接和文件系统引发的其他各种奇怪的问题,以及node_modules中原本的组件库包和全局的组件库包。
- 全局安装:
pnpm i yalc -g
- 构建发布产物:
pnpm build
- 发布:进入到需要发布的组件库里,执行:
yalc publish
- 进入到使用的项目:
yalc add test-ui
,当前项目会在package.json中添加:"test-ui": "file:.yalc/test-ui",
- 如果需要从使用项目中删除该组件库,执行:
yalc remove test-ui
- 更新和推送:
yalc publish --push
可以简写为:yalc push
,最新的包直接在你使用的项目中生效,而且还能实现hrm - 从本地商店中删除组件库:
yalc installations clean my-package
rollup-plugin-visualizer
可视化并分析Rollup包,以查看哪些模块占用了空间
npm install --save-dev rollup-plugin-visualizer
import { visualizer } from "rollup-plugin-visualizer";
import { defineConfig, type PluginOption } from 'vite'
export default defineConfig({
plugins: [visualizer({
emitFile: false,
open: true,
filename: 'test.html' //分析图生成的文件名
}) as PluginOption],
})
除此之外,目前配置中,使用项目被打出的包是一个整体,为了更方便观察,我们对静态资源分类打包:
build: {
rollupOptions: {
// 静态资源分类打包
output: {
// 在 UMD 构建模式下为这些外部化的依赖提供一个全局变量
globals: {},
chunkFileNames: 'static/js/[name]-[hash].js',
entryFileNames: 'static/js/[name]-[hash].js',
assetFileNames: 'static/[ext]/[name]-[hash].[ext]',
manualChunks: (id): any => {
// 静态资源分拆打包
if (id.includes('node_modules')) {
return id.toString().split('node_modules/')[1].split('/')[0].toString()
}
}
}
}
}
因为之前是在pnpm workspace下进行测试的,因此还需要修改组件库的package.json文件,指明dist路径的文件输出:
"main": "./dist/cjs/main.cjs",
"module": "./dist/es/main.mjs",
"types": "./dist/test-ui.d.ts",
按需加载方式一:利用treeshaking
首先在使用项目中的main.ts里导入样式文件:
import 'test-ui/dist/es/style.css'
在组件中使用:
import { YButton } from 'test-ui'
但是发现,按需加载并没有成功,打出来的包仍然将input组件打进去了。
后查看element-plus的导出方式以及各种排查发现,问题居然出现在导出组件的install文件:
import YButton from './index.vue'
import type { App } from 'vue'
const install = function (app: App) {
app.component(YButton.name || 'YButton', YButton)
}
YButton.install = install
这里直接在YButton上添加了一个install属性,方便按需加载的时候,也能在全局使用,但是正是因为这个操作,导致按需加载失败。
如果去掉installl属性,直接导出组件,是可以按需加载的,这里我暂时没有找到解决方法,模仿element-plus包装了几层,也是失败。这里如果有大佬了解原因的话可以指点一下。
按需加载方式二:使用exports字段明确模块导出内容
"exports": {
".": {
"import": "./dist/es/main.mjs",
"require": "./dist/cjs/main.cjs",
"types": "./dist/main.d.ts"
},
"./YButton": {
"import": "./dist/es/components/YButton/install.mjs",
"require": "./dist/cjs/components/YButton/install.cjs",
"types": "./dist/src/components/YButton/install.d.ts"
},
"./YInput": {
"import": "./dist/es/components/YInput/install.mjs",
"require": "./dist/cjs/components/YInput/install.cjs",
"types": "./dist/src/components/YInput/install.d.ts"
}
}
这样导出的组件库的使用方法如下:
import YButton from 'test-ui/YButton'
如果需要类型声明,使用项目中的types字段可以为如下,如果仍旧报错的话,重启一下vscode。
"types": ["test-ui/dist/main.d.ts"],
// 或者
"types": ["test-ui/dist/src/components/YButton/install.d.ts"],
打包使用项目后发现可以正常按需导出,查看分析结果,Y-input并没有被打包,但是会报错Missing "./dist/es/style.css" specifier in "test-ui" package
。样式文件无法找到。在package.json的exports字段中加入以下代码可以解决css文件未被找到的问题:
"./style": {
"import": "./dist/es/style.css",
"require": "./dist/cjs/style.css"
},
或者在package.json中使用sideEffects字段,指明css文件不可被忽略:
"sideEffects": [
"*.css",
"*.scss",
"./dist/es/**/*.css",
"./dist/cjs/**/*.css"
]
欢迎关注工种号【码界交流圈】。好文第一时间分享不迷路!~
标签:dist,YButton,ts,文档,install,组件,import,搭建 From: https://blog.csdn.net/2401_87546826/article/details/143709703