关于element-ui:Element-Plus-源码分析构建与代码风格

7次阅读

共计 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

应用到的工具有:rollupunbuildesbuildgulpts-morphfast-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 下生成 eslib 两个文件夹,别离为 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.jsontags.jsonattributes.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.cssdist/element-plus/dist/index.css。把残缺的 CSS 款式复制到「残缺构建产物」的目录中,不便 CDN 引入。

3. copyTypesDefinitions 复制 .d.ts 文件

因为有 ESM 与 CJS 两种格局都须要类型申明文件,所以没有一开始就生成到「最终构建产物」目录。最初将「类型申明产物」的所有文件复制到 dist/element-plus/esdist/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 时,将 dependenciespeerDependencies 排除在构建产物之外。

当构建残缺产物时,将 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 中的 parsecompileScriptscript 块中的代码提取进去,并编译 <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 集成。

其余

其余代码局部将在后续更新。

正文完
 0