文章目录
- 前言
- monorepo架构
- 1.monorepo架构的优势
- 2.使用pnpm搭建monorepo架构
- (1)全局安装pnpm
- (2)初始化项目
- (3)新建workspace.yaml文件
- 4.不同包之间的相互引用
- TypeScript支持
- 1.安装TypeScript
- 2.初始化TypeScript
- 3.配置TypeScript
- play环境搭建
- docs环境搭建
- 通用包和工程化工具安装
- 总结
- 参考资料
前言
组队大项目选择了组件库开发,一开始决定选题时候,大家都觉得这个题目会很难写,等到实际上手开发的时候,才发现这个项目确实没那么好写。
开发组件库的第一步就是要确定组件库的整体架构和技术选型,这方面我主要参考了Element-plus。架构方面使用基于pnpm实现的monorepo架构,对项目的代码进行组织和管理;css预处理器选择了Sass,定义了classname的BEM规范、cssvar变量的一系列utils和一些其他的样式处理工具;测试工具采用vitest;组件库文档采用vitepress。
monorepo架构
monorepo指的是在一个仓库中,存在多个不同的项目。这些项目可能是相关联的,但在逻辑上它们是独立的。
1.monorepo架构的优势
monorepo可以使多个项目共用一套基础配置,且有依赖的项目之间的调试会变得非常方便,并且可以统一管理第三方库的版本。
2.使用pnpm搭建monorepo架构
关于pnpm的优势在这里就不过多赘述了(用过的都说好)。这里使用pnpm的主要原因是,pnpm它内置了对monorepo的支持,并且实现方式也非常简单。
(1)全局安装pnpm
npm install pnpm -g
(2)初始化项目
在项目目录下使用pnpm init命令,初始化package.json文件。
pnpm init
删除name属性,并添加一个private属性,因为根文件夹是不需要发布的。
{
"private": true,
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
(3)新建workspace.yaml文件
在项目根目录下创建pnpm-workspace.yaml文件,用于指定不同工作区的文件夹。
packages:
- play # 组件测试代码
- docs # 组件文档
- packages/* # 组件包
packages包下通常会包含各类组件相关的文件夹,比如components、theme-chalk和utils等,以components为例,我们去到components的文件夹下使用pnpm init
命令初始化工作区的package.json文件。并将package.json的name属性改为@组件名+工作区名。其他两个工作区theme-chalk和utils也是如此。
// components
{
"name": "@voile-ui/components",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
至此,我们当前的项目目录结构如下:
4.不同包之间的相互引用
我们先将packages下的包都安装到项目的根目录中。
pnpm i @voile-ui/components -D -w
pnpm i @voile-ui/theme-chalk -D -w
pnpm i @voile-ui/utils -D -w
-w表示将包安装到公共模块,也就是根目录下。然后,我们就可以在不同的包之间相互进行引用了。
TypeScript支持
1.安装TypeScript
pnpm i typescript -D -w
2.初始化TypeScript
pnpm tsc --init
3.配置TypeScript
在tsconfig.json中,有一个顶级属性references,它可以将项目进一步划分为更小的子模块,分别进行类型检查和编译,从而提升整体的性能。
"references": [
{ "path": "./tsconfig.web.json" }, // 组件包
{ "path": "./tsconfig.play.json" } // 组件 play
],
然后分别创建这些配置文件。
// tsconfig.base.json
{
"compilerOptions": {
"outDir": "dist", // 指定输出目录
"target": "es2018", // 目标语言的版本
"module": "esnext", // 生成代码的模板标准
"baseUrl": ".", // 解析非相对模块的基地址,默认是当前目录
"sourceMap": false, // 是否生成相应的Map映射的文件,默认:false
"moduleResolution": "node", // 指定模块解析策略,node或classic
"allowJs": false, // 是否允许编译器编译JS,JSX文件
"strict": true, // 是否启动所有严格检查的总开关,默认:false,启动后将开启所有的严格检查选项
"noUnusedLocals": true, // 是否检查未使用的局部变量,默认:false
"resolveJsonModule": true, // 是否解析 JSON 模块,默认:false
"allowSyntheticDefaultImports": true, // 是否允许从没有默认导出的模块中默认导入,默认:false
"esModuleInterop": true, // 是否通过为所有导入模块创建命名空间对象,允许CommonJS和ES模块之间的互操作性,开启改选项时,也自动开启allowSyntheticDefaultImports选项,默认:false
"removeComments": false, // 删除注释
"rootDir": ".", // 指定输出文件目录(用于输出),用于控制输出目录结构
"types": [],
"paths": {
// 路径映射,相对于baseUrl
"@voile-ui/*": ["packages/*"]
}
}
}
// tsconfig.web.json
{
"extends": "./tsconfig.base.json",
"compilerOptions": {
"composite": true, // 是否开启项目编译,开启该功能,将会生成被编译文件所在的目录,同时开启declaration、declarationMap和incremental,默认:false
"jsx": "preserve", // 指定JSX代码生成用于的开发环境
"lib": ["ES2018", "DOM", "DOM.Iterable"], // 指定项目运行时使用的库
"types": ["unplugin-vue-define-options","unplugin-vue-define-options/macros-global"], // 用来指定需要包含的模块,并将其包含在全局范围内
"skipLibCheck": true // 是否跳过声明文件的类型检查,这可以在编译期间以牺牲类型系统准确性为代价来节省时间,默认:false
},
"include": ["packages"], // 使用 include 来指定应从绝对类型中使用哪些类型
"exclude": [
// 提供用于禁用 JavaScript 项目中某个模块的类型获取的配置
"node_modules",
"**/dist",
"**/__tests__/**/*",
"**/gulpfile.ts",
"**/test-helper",
"packages/test-utils",
"**/*.md"
]
}
// tsconfig.play.json
{
"extends": "./tsconfig.base.json",
"compilerOptions": {
"composite": true, // 是否开启项目编译,开启该功能,将会生成被编译文件所在的目录,同时开启declaration、declarationMap和incremental,默认:false
"jsx": "preserve", // 指定JSX代码生成用于的开发环境
"lib": ["ES2018", "DOM", "DOM.Iterable"], // 指定项目运行时使用的库
"types": ["unplugin-vue-define-options","unplugin-vue-define-options/macros-global"], // 用来指定需要包含的模块,并将其包含在全局范围内
"skipLibCheck": true // 是否跳过声明文件的类型检查,这可以在编译期间以牺牲类型系统准确性为代价来节省时间,默认:false
},
"include": ["packages"], // 使用 include 来指定应从绝对类型中使用哪些类型
"exclude": [
// 提供用于禁用 JavaScript 项目中某个模块的类型获取的配置
"node_modules",
"**/dist",
"**/__tests__/**/*",
"**/gulpfile.ts",
"**/test-helper",
"packages/test-utils",
"**/*.md"
]
}
play环境搭建
play环境搭建其实就是在根目录下创建了一个名为play的vue项目。
pnpm create vite play --template vue
docs环境搭建
docs环境同样是在根目录下创建一个名为docs的vitepress项目
pnpm i vitepress -D -w
通用包和工程化工具安装
pnpm i vue, sass, prettier, husky, @vueuse/core, eslint,
总结
至此,一个基本的组件库开发环境就已经搭建好了,接下来就要对代码书写规范、git提交规范、公共样式属性、命名风格等这些规定做详细的设置,然后就可以开始开发组件了。
参考资料
https://github.com/element-plus/element-plus
https://juejin.cn/post/7146183222425518093