代码

架子包括:

  • 定义项目结构(Mono-repo)
  • 定义开发规范(lint、代码风格、commit、tsc)
  • 选择打包工具(rollup)

项目结构

Multi-repo VS. Mono-repo

  • Multi-repo:每个项目有自己独立的仓库,逻辑清晰,相对独立,难以共享代码
  • Mono-repo:一个仓库中包含多个相关联的项目,可以很方便的共享代码,协同管理不同项目的生命周期,但会有更高的架构难度和操作复杂度

一般 Mono-repo 的目录如下所示,在 packages 存放多个子项目,并且每个子项目都有自己的 package.json

├── packages
|   ├── pkg1
|   |   ├── package.json
|   ├── pkg2
|   |   ├── package.json
├── package.json

参考资料:现代前端工程为什么越来越离不开 Monorepo?

我们要实现的 React 分为很多包,如:reactreact-domreact-reconciler 等,它们关系密切,需要互相调用,所以采用 Mono-repo 组织项目。

Mono-repo 技术选型

简单工具:

专业工具:

pnpm 相比其他打包工具的优势:

  • 依赖安装快(软链接)
  • 更规范(处理幽灵依赖问题)

参考资料:pnpm 是凭什么对 npm 和 yarn 降维打击的?

我们采用 pnpm 作为包管理工具,Mono-repo 落地选用 pnpm workspace

初始化项目

git init # 初始化 git 仓库
 
npm install -g pnpm
pnpm init # 创建 package.json

.gitignore

.DS_Store
node_modules
dist

初始化 pnpm-workspace.yaml

# pnpm-workspace.yaml
 
packages:
  - 'packages/*'

定义开发规范

lint 工具:ESLint

安装:pnpm i -D -w eslint

初始化:

pnpm exec eslint --init # 或:npx eslint --init
 
? How would you like to use ESLint?
# To check syntax and find problems
# ESLint 只做检查语法 + 发现问题,代码风格交给 Prettier
 
? What type of modules does your project use?
# JavaScript modules (import/export)
 
? Which framework does your project use?
# None of these
 
? Does your project use TypeScript?
# Yes
 
? Where does your code run?
# Browser ✅
# Node ✅
 
? Would you like to install them now?
# No
# 我们自己安装,因为它安装不加 -w,会报错
 
pnpm i -D -w globals @eslint/js typescript-eslint

生成的 eslint.config.mjs

import globals from 'globals'
import pluginJs from '@eslint/js'
import tsEslint from 'typescript-eslint'
 
export default [
  { languageOptions: { globals: { ...globals.browser, ...globals.node } } },
  pluginJs.configs.recommended,
  ...tsEslint.configs.recommended,
]

lint 增加对应的执行脚本:

"lint": "eslint --fix --quiet ./packages"

代码风格:Prettier

安装:pnpm i -D -w prettier

新建配置文件 .prettierrc.json

{
  "semi": false,
  "singleQuote": true,
  "printWidth": 120,
  "useTabs": false,
  "tabWidth": 2,
  "bracketSpacing": true,
  "trailingComma": "all",
  "arrowParens": "avoid"
}

style 增加对应的执行脚本:

"format": "prettier --write ./packages"

安装 Prettier 与 ESLint 的 VSCode 插件,并设置为保存后自动执行:Format On Save

commit 规范检查:CommitLint

通过 commitlintgit commit 提交信息进行检查,安装必要的库:

pnpm i -D -w @commitlint/cli @commitlint/config-conventional

新建配置文件 commitlint.config.mjs

export default {
  extends: ['@commitlint/config-conventional'],
}

conventional 规范集意义:

type(scope?): subject
# 类型(范围): 主题
# 范围是可选的,支持多个范围,用 "/"、"\"、"," 分割

type 值:

  • feat:添加新功能
  • fix:修复 Bug
  • docs:文档的修改
  • style:不影响代码含义的更改
  • refactor:代码重构
  • perf:性能方面的优化
  • test:添加缺失的测试或更正现有测试
  • build:影响构建系统或外部依赖项的更改
  • ci:更改 CI 配置文件和脚本
  • chore:一些不影响功能的更改(杂项)
  • revert:恢复之前的提交

提交时自动运行

安装:pnpm i -D -w husky lint-staged

  • husky:用于拦截 git commit 命令
  • lint-staged:只对暂存区代码进行检查

初始化 husky:

pnpm exec husky init

.husky/pre-commit

pnpm exec lint-staged

.husky/commit-msg

npx --no-install commitlint --edit "$1"

package.json

{
  "scripts": {
    "prepare": "husky",
    "lint": "eslint --fix --quiet ./packages",
    "format": "prettier --write ./packages"
  },
  "lint-staged": {
    "./packages/**/*.{js,jsx,ts,tsx}": [
      "prettier --write",
      "eslint --fix --quiet"
    ]
  },
}

打包工具

比较不同打包工具的区别,我们要开发的项目的特点:

  • 是库,而不是业务项目
  • 希望工具尽可能简洁、打包产物可读性高
  • 原生支持 ESM

所以选择 rollup,安装:pnpm i -D -w rollup

参考资料:Overview | Tooling.Report