共计 5451 个字符,预计需要花费 14 分钟才能阅读完成。
我的项目概述
- 官网:https://element-plus.org/
- GitHub 仓库:https://github.com/element-pl…
- 包治理:pnpm workspace
- 组件代码:TypeScript、Vue SFC(Vue 单文件组件)
- 款式:Scss、CSS var
- 单元测试:Jest、Vitest
- 构建:Rollup、esbuild、TypeScript、Gulp
- 代码格调:ESLint、Prettier
本文章基于 Element Plus v2.1.4。如有谬误之处,欢送斧正。
构建
- Keywords:
Vue SFC
,Rollup
,Bundleless
,TypeScript
,ESM
,CommonJS
/CJS
,UMD
这部分在一个独自的包 @element-plus/build
,代码位于 /internal/build
。
应用到的工具有:rollup
、unbuild
、esbuild
、gulp
、ts-morph
、fast-glob
等。如需深度了解,倡议先自行理解这些包后浏览本章节。
目录构造
源码
internal/build
├── build.config.ts # unbuild 配置文件
├── dist # 构建产物
├── gulpfile.ts # 构建脚本
├── package.json
├── src
│ ├── build-info.ts # 构建信息
│ ├── constants.ts # 一些常量
│ ├── index.ts # 入口文件
│ ├── plugins # 插件
│ │ └── element-plus-alias.ts # 导入别名
│ ├── tasks
│ │ ├── full-bundle.ts # 构建残缺产物
│ │ ├── helper.ts # 生成 WebStorm 提醒文件
│ │ ├── index.ts
│ │ ├── modules.ts # 构建 bundleless 产物
│ │ └── types-definitions.ts # 生成 d.ts 文件
│ ├── type-safe.json #「类型平安」列表
│ └── utils # 工具函数
│ ├── gulp.ts
│ ├── index.ts
│ ├── log.ts
│ ├── paths.ts
│ ├── pkg.ts
│ ├── process.ts
│ └── rollup.ts
├── tsconfig.json
└── vue-jest-transformer.js
构建产物
在线预览
dist/
├── element-plus # 最终构建产物
│ ├── README.md
│ ├── attributes.json
│ ├── dist # 残缺构建产物
│ ├── es # bundleless 构建产物,ESM 格局
│ ├── global.d.ts # 供 Volar 应用的全局组件类型
│ ├── lib # bundleless 构建产物,CJS 格局
│ ├── package.json
│ ├── tags.json
│ ├── theme-chalk # 款式产物
│ └── web-types.json
└── types # 类型申明产物
构建流程
首先能够看到在 package.json
文件中的 start
脚本,启动 Gulp 运行 gulpfile.ts
文件。这将运行 gulpfile
的默认导出。在 gulpfile.ts
文件中找到 export default
相干代码就是构建流程了。
0. clean
清理产物
调用一个 run
函数,将会在我的项目根目录运行 pnpm run clean
,其作用为删除根目录下的 dist
文件夹,并且运行 /packages
目录下每个包的 clean
脚本。
1. createOutput
创立构建产物的目录
创立 /dist/element-plus
文件夹。在上一步中,咱们把 dist
目录整个删掉了,为了保障目录存在,须要把之前的 dist
目录创立回来。
2. parallel
这是多个并行的工作,因为构建每种不同类型的产物是能够同时进行的。
2.1 buildModules
构建 Bundless 产物
将开启一个新过程开始执行 ./src/tasks/modules.ts
中的 buildModules
函数。最初将在 /dist/element-plus
下生成 es
与 lib
两个文件夹,别离为 ESM 与 CJS 两种格局。
2.2 buildFullBundle
构建残缺产物
与上一步相似,将执行 ./src/tasks/full-bundle.ts
中的 buildFullBundle
函数。但这步比上一步多一个构建 locale
,因为须要思考在 CDN 场景下导入不同语言。另外,用户导入完整包能够不须要应用构建工具(Vite、Webpack 等),须要咱们须要还须要提供压缩版本,以便可能节俭加载工夫。
buildFull
函数就提供了一个参数 minify
,以便能够并行执行两个工作——一个压缩版本和一个不压缩的版本。
buildFullEntry
函数就是构建残缺产物的函数。除了没有应用 preserveModules
选项,与 buildModules
基本一致。提供了 UMD 与 ESM 两种格局。
buildFullLocale
函数用来构建语言包。为 packages/locale/**/*.ts
下的每个文件同时构建 UMD 与 ESM 两种格局的产物。
同时,开启 minify
参数时会开启 sourceMap
选项,为开发时提供原始源码用来调试。
2.3 generateTypesDefinitions
生成 .d.ts
文件
为了用户开发时提供类型反对,还须要同时生成 .d.ts
。将执行 ./src/tasks/types-definitions.ts
中的 generateTypesDefinitions
函数。最初将 .d.ts
写入到 /dist/types
目录中。
2.4 buildHelper
生成 IDE 反对
对于 WebStorm 与 Vetur,须要生成 web-types.json
与 tags.json
、attributes.json
文件供插件剖析,最终提供代码提醒。应用了 components-helper 剖析文档 Markdown 生成。
开发 Vue 3 利用还是举荐应用 VSCode + Volar,这部分可能当前会被移除。因为用文档生成上述文件并不牢靠。
2.5 buildThemeChalk
copyFullStyle
构建并复制款式
buildThemeChalk
:这步将先执行 buildThemeChalk
,从 Sass 源代码构建为 CSS 产物。相干代码位于 packages/theme-chalk/gulpfile.ts
。最终把产物从 packages/theme-chalk/dist
复制到 dist/element-plus/theme-chalk
。
copyFullStyle
:将复制 dist/element-plus/theme-chalk/index.css
到 dist/element-plus/dist/index.css
。把残缺的 CSS 款式复制到「残缺构建产物」的目录中,不便 CDN 引入。
3. copyTypesDefinitions
复制 .d.ts
文件
因为有 ESM 与 CJS 两种格局都须要类型申明文件,所以没有一开始就生成到「最终构建产物」目录。最初将「类型申明产物」的所有文件复制到 dist/element-plus/es
与 dist/element-plus/lib
中即可。
以上就是所有流程。
Rollup 插件
「残缺构建产物」与「bundleless 构建产物」都应用到了 Rollup。
Rollup 是不能解析像 TypeScript、Vue SFC 这些非 JavaScript 的代码,所以须要借助各种插件,来帮忙 Rollup 将其转换为 JavaScript 代码。Rollup 也不能解析 CommonJS 格局的代码,还须要插件来帮忙 Rollup 解决这些问题。
unplugin-vue-define-options
这是我集体写的一个插件。通过这个插件就能够在 Vue 的 <script setup>
中应用 Options API
。Element Plus 须要定义组件 name
属性,这个就能够防止两个 script
标签了。
@vitejs/plugin-vue
Vite 官网插件,把 Vue SFC 编译为 JavaScript 代码。
@vitejs/plugin-vue-jsx
Vite 官网插件,反对 Vue JSX 语法。
@rollup/plugin-node-resolve
Rollup 官网插件,让 Rollup 反对 Node.js 的解析算法,用于解析 node_modules
。
extensions
选项:默认是不蕴含 .ts
后缀名的,所以须要手动加上。
@rollup/plugin-commonjs
Rollup 官网插件,用于将 CommonJS 模块转换为 ES6,这样就能够被 Rollup 解析。
rollup-plugin-esbuild
一个弱小、高效、好用的插件!用于把 TypeScript 转换为 JavaScript,并能够用于压缩代码、转换语法。基于 ESBuild,速度极快。
minify
选项:是否压缩代码。
target
选项:向下兼容低版本浏览器。Element Plus 最低兼容 ES2018
,但在开发中会应用到一些新语法(比方 Optional chaining 等),所以须要借助 ESBuild 的能力,把语法糖转换为能兼容 ES2018 的代码。
loaders
选项:通过 @vitejs/plugin-vue
插件编译后,Vue SFC 就是一般的 JavaScript 代码了,然而其后缀还是 .vue
。所以须要增加 '.vue': 'ts',
,把 .vue
文件看作一般的 .js
文件。
Rollup 配置
external
当构建 bundless 时,将 dependencies
和 peerDependencies
排除在构建产物之外。
当构建残缺产物时,将 peerDependencies
(也就是 vue
)排除在构建产物之外。
preserveModules
开启后,构建产物将放弃与源码一样的文件构造。
能够了解为仅把 Vue SFC、TypeScript 等转换成了 JavaScript 代码,其余不变。
其余代码
build.config.ts
应用 unbuild 生成开发时 stub,开发调试用。这样就不必 watch 始终监听文件构建。
src/type-safe.json
因为 Element Plus 的代码目前还有 TypeScript 类型产物,但曾经重构实现了局部文件。这个文件就是记录已重构实现的列表。为了在生成 .d.ts
是针对这部分文件做异样解决。
src/build-info.ts
将构建的配置集中写在这个文件中,包含门路、构建格局、后缀名等。
src/constants.ts
一些常量。如果想自行构建并批改一些参数,能够批改此文件。
src/plugins/element-plus-alias.ts
解析款式导入的门路。把 "@element-plus/theme-chalk"
替换为 "element-plus/theme-chalk"
。
生成 .d.ts
类型定义
代码位于在 generateTypesDefinitions
步骤中。这里应用了 ts-morph
简化 TypeScript 编译调用。首先创立一个 Project
并指定配置,用于笼罩 tsconfig.json
的配置。skipAddingFilesFromTsConfig
设置为 false
的目标是,咱们须要手动抉择文件到编译器中。通过 glob
匹配所有源码文件,并过滤掉仅用于测试与开发的文件。获取到文件列表后,须要把文件增加到 TypeScript 编译器中。
值得注意的是 Vue SFC 不能够间接增加到编译器中,因为 TypeScript 无奈解析它。所以须要应用 vue/compiler-sfc
中的 parse
和 compileScript
把 script
块中的代码提取进去,并编译 <script setup>
的代码。之后再增加到编译器中。
另外,因为构建产物的目录构造与咱们理论的源码目录构造不一样。所以这里要非凡解决下——手动读取文件内容并增加到编译器中。
还须要工具「类型平安」列表中的文件进行匹配,如果列表中的文件有类型谬误,则间接报错。能够避免意外造成的 TypeScript 谬误。后续将陆续实现代码重构,保障 0 TypeScript 谬误。
最初就是把编译好的 .d.ts
文件写入到构建目录即可。
将来
我写了一个新的构建流程,未来可能在 Element Plus 3 中应用到。全程应用 ESBuild 构建,速度应该会快很多。另外,将来可能将只构建 ESM 和 IIFE 格局的版本。因而,Bundleless 构建产物也能够去掉。
代码格调
这部分在一个独自的包 @element-plus/eslint-config
,代码位于 /internal/eslint-config
。
如果想给 Element Plus 奉献代码,请务必确保代码格调没有问题。能够运行 pnpm run lint
来查看是否存在问题,并应用 pnpm run lint:fix
主动修复问题。
ESLint
Element Plus 应用 ESLint 来治理代码格调,同时应用了多个插件来反对不同的文件类型。反对的文件类型有:JavaScript、TypeScript、JSX/TSX、Vue SFC、Markdown、JSON、JSON5,详见 .vscode/settings.json
的配置项 eslint.validate
。
Prettier
总体上应用 Prettier 来束缚代码格调,详见 Prettier 配置文件。并应用 Prettier 插件和预设规定与 ESLint 集成。
其余
其余代码局部将在后续更新。