首页 > 其他分享 >从0开始搭建一个包含文档的组件库

从0开始搭建一个包含文档的组件库

时间:2024-11-18 18:18:05浏览次数:3  
标签:dist YButton ts 文档 install 组件 import 搭建

初始化项目

使用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', // 指定输出文件名称
        },
      ],
    },
  }

如果想要测试是否实现了按需加载,在开发环境下是无法测试的,为了模拟真实的场景,我们需要构建后测试。此时,我们使用两款工具来进行测试:yalcrollup-plugin-visualizer

yalc

对标npm/yarn link,但是模拟的是真实发布的场景,不会存在link中存在的软链接和文件系统引发的其他各种奇怪的问题,以及node_modules中原本的组件库包和全局的组件库包。

  1. 全局安装:pnpm i yalc -g
  2. 构建发布产物:pnpm build
  3. 发布:进入到需要发布的组件库里,执行:yalc publish
  4. 进入到使用的项目:yalc add test-ui ,当前项目会在package.json中添加:"test-ui": "file:.yalc/test-ui",
  5. 如果需要从使用项目中删除该组件库,执行:yalc remove test-ui
  6. 更新和推送:yalc publish --push 可以简写为: yalc push,最新的包直接在你使用的项目中生效,而且还能实现hrm
  7. 从本地商店中删除组件库: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

相关文章

  • 循序渐进搭建复杂B端系统整洁架构
    作者:京东零售赵嘉铎前言:信息时代技术更迭和传播速度不断加快,技术变得泛娱乐化,大数据、云计算、区块链、元宇宙、大模型,一代代技术热点在社会舆论的裹挟之下不断地吸引着资本的眼球,技术人员为了不被时代所淘汰也不得不时刻追赶潮流。在这样一个时代背景下,软件工程作为一门不起眼......
  • 构建企业级 Agent 系统:核心组件设计与优化
    引言构建企业级AIAgent系统需要仔细考虑组件设计、系统架构和工程实践。本文将探讨构建稳健可扩展的Agent系统的关键组件和最佳实践。1.Prompt模板工程1.1模板设计模式fromtypingimportProtocol,Dictfromjinja2importTemplateclassPromptTemplate(Protocol......
  • 移动开发技术——基本框架搭建
     一、实现效果二、功能说明主界面有上中下三个结构,包含四个界面:联系人、聊天、发现、我的。从聊天可以点击进入列表页面,点击列表的某一行可以进入详情页面,列表的每一行对应不同的数据,列表可以上下滚动,要用到recycleview。需要实现以下功能:activity之间的跳转,数据的绑......
  • js给同一组件同一请求的调用加锁
    我开发的一个页面,同时多次使用了同一个组件,但是这个组件一加载就会调用同一个方法,最终同时调用同一接口。但是我们后端对于同一接口的调用频率进行了限制,不允许短时间内重复提交,需要在一个时间间隔后提交才能请求成功。原代码为:onMounted(()=>{constcode=item.value.c......
  • WVP-pro 搭建相关的坑注意
    Wvp-pro是一个开源的gb28181平台## 一些知识点网址 https://doc.wvp-pro.cn/#/相关的另一个开源的  一个基于C++11的高性能运营级流媒体服务框架ZLMediaKitjava,sprinboot,npmmysqredisdocker坑位wvp部署时,需要设置zlmediakit的secret,这个secret需要在do......
  • 使用ProxyPool搭建代理IP池并获取代理IP示例
    安装ProxyPool首先确保已经安装了 pip 工具(Python的包管理工具),在命令行执行以下命令安装 proxypool:配置ProxyPoolProxyPool的配置文件通常是 config.py,可以根据需求修改配置项,比如设置代理IP的来源、验证周期等。以下是一个简单示例配置(部分关键配置项示意):启动ProxyP......
  • Flutter项目实战(1):通用项目框架搭建
    下面介绍Flutter最基本的通用项目框架搭建,同时实现了一个登录界面图标和登录界面。先看下效果图:使用ScreenUtilInit自适应界面大小;使用Stack支持多个子界面在同一个全屏主界面上选择显示;使用Get插件实现界面之间的跳转和国际化翻译;界面都通过Transform实现了鼠标移动......
  • linux(统信)下搭建electron开发环境
    1.安装vscode下载地址https://vscode.download.prss.microsoft.com/dbazure/download/stable/f1a4fb101478ce6ec82fe9627c43efbf9e98c813/code-stable-x64-1731511985.tar.gz下载后拷贝压缩包到安装目录下解压缩.点击code就可以启动.2.安装githttps://git-scm.com/downlo......
  • catia零部件装配结构搭建
    catia零部件装配结构搭建ProductCatia的product文件保存装配结构和各个零部件之间的参数关系与约束关系,不保存三维实体本身。装配结构搭建通常在装配结构搭建的时候不考虑零部件之间的约束关系,只保留装配结构与位置关系(零部件的三维坐标与当前的姿态)。程序思路一般情况下,会......
  • 基于SpringBoot + Vue的红色旅游网站的设计与实现(源码+文档+部署)
    文章目录1.前言2.系统演示录像3.论文参考4.代码运行展示图5.技术框架5.1SpringBoot技术介绍5.2Vue技术介绍6.可行性分析7.系统测试7.1系统测试的目的7.2系统功能测试8.数据库表设计9.代码参考10.数据库脚本11.找我做程序,有什么保障?12.联系我们1.前......