导读
本文基于以下包和版本配置:
包名 |
版本号 |
next |
14.2.15 |
react |
18.2.0 |
react-dom |
18.2.0 |
tailwindcss |
3.4.1 |
@changesets/cli |
2.27.9 |
@commitlint/cli |
19.5.0 |
@commitlint/config-conventional |
19.5.0 |
husky |
9.1.6 |
typescript |
5.4.4 |
本文介绍的开发环境是****Macbook Pro M1 MacOS 14.6.1。
项目启动与打包验证
创建项目
创建项目,使用next 14.2.15
使用app router的模式
本地运行
确保你使用了pnpm
作为包管理工具,如果没有安装,请使用 npm i -g pnpm
安装。
**本地运行项目,使用 **pnpm dev
命令
到这里,一切都是正常的,说明我们的应用没有问题,一切都是纯粹的模样,接下来我们直接打包,保证我们的项目不会半途因为出现不知名的问题无法排查。(笔者在此之前已经用pages router模式搭建几乎完成了,但是打包部署始终无法成功,更要命的是开发模式也无法正常启动了。因此强烈建议每引入新的东西不仅开发模式引入就行了,打包部署尽可能都尝试一遍看看,如何出现发生了错误就能快速定位了。)
本地打包
当前的next.config.js 文件的配置是
1 2 3 4
| /** @type {import('next').NextConfig} */ const nextConfig = {};
export default nextConfig;
|
**可以看到是空的,我们什么都不给尝试打包 **npm run build
可以看到,打包是成功了的。
由于我们的项目是一个monorepo的组件库和文档,我们需要pnpm 的workspace(工作空间)提供的能力,
可以在项目根目录中加入一个文件pnpm-workspace.yaml
,内容如下:
1 2
| packages: - "packages/*"
|
这表示我们的子应用(有自己的package.json),也就是之后的每一个组件存放在根目录的packages
子目录之下,如图所示:
需要注意的是,我们的根目录也是存在tsconfig.json
文件,nextjs应用打包时,也会去检查packages下的typescript配置,这功能应该交给各个组件库包决定,因此我们需要排除packages
目录:,在tsconfig.json
文件中的exclude
中配置:
该项目最终目的是部署到githua pages,我们需要1)集成changesets 实现monorepo的包管理、2)commitlint实现git commit提交的规范验证和代码格式化检查,我们每上线一个功能都希望能够3)结合github pages的 工作流实现项目的一键部署。下面一节将介绍这些。
集成部署
changesets
我们通过命令pnpm add -Dw @changesets/cli
安装changesets
。
**再通过 **pnpm changeset init
初始化我们的 changeset
项目的根目录下多出一个.changeset
目录。
接着我们需要在项目根目录下的packages.json
文件中的 scripts
命令中增加几条
1 2 3 4
| { "compile": "pnpm --filter=@zerotower/* run build", "pub": "pnpm compile && pnpm --recursive --registry=https://registry.npmjs.org/ publish --access public", }
|
第一条命令用来对packages
下的组件执行编译打包命令,pub用来将我们的仓库发布到npm。
为了测试,我们先新增两个组件目录用来测试。
两个组件都是支持typescript
的,我们需要同时安装 5.4.4
版本。(更高的版本在笔者的使用中经常会导致奇怪的问题),在项目的根目录下执行以下命令
pnpm add [email protected] -r -D
未来该版本可能不可用,如果5.4.4
没用的话,可以通过执行 pnpm view typescript versions
查看一个可用的版本。
分别查看packages/image-gallery/packages.json
和packages/color-picker/packages.json
,发现都安装了指定的typescript
。
改造一下
所有的组件库包都将拥有一个统一的前缀@zerotower
,而我们也仅仅需要编译这些库包,根目录的next.js不参与编译。
接着,将这两个添加到根目录的package.json
文件中,之后执行pnpm install -w
重新安装依赖。
打开项目根目录的node_modules
,@zerotower
有两个字目录,它们都有红框框选的一个小图标,这表示两个目录都是软链接创建的,是将packages/**
软链接到了/node_modules/@zerotower/**
,底层其实就是 ln packages/** node_modules/@zerotower/**
,使用的ln
命令。
添加commilint
一键安装三个库包,在项目的根目录下执行:
pnpm add —D @commitlint/{config-conventional,cli} husky -w
执行以下的~~husky~~
命令,完成husky的初始化。()
1 2 3
| npx husky-init # 下面这一句通常执行成功,但是没什么吊用 npx husky add .husky/commit-msg 'npx --no-install commitlint --edit "$1"'
|
我们需要手动在****项目根目录下的.husky目录下新增一个commit-msg
文件
文件内容为:
1 2 3 4 5 6
| #!/usr/bin/env sh . "$(dirname -- "$0")/_/husky.sh"
npx --no-install commitlint --edit "$1"
|
为了避免执行错误,我们还需要赋予执行的权限
chmod +x .husky/commit-msg
之后,我们需要在项目的根目录添加一个commitlint.config.cjs
的文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
| // @see: https://cz-git.qbenben.com/zh/guide /** @type {import('cz-git').UserConfig} */ module.exports = { ignores: [commit => commit.includes('init')], extends: ['@commitlint/config-conventional'], rules: { // @see: https://commitlint.js.org/#/reference-rules 'body-leading-blank': [2, 'always'], 'footer-leading-blank': [1, 'always'], 'header-max-length': [2, 'always', 108], 'subject-empty': [2, 'never'], 'type-empty': [2, 'never'], 'subject-case': [0], 'type-enum': [ 2, 'always', [ 'feat', 'fix', 'docs', 'style', 'refactor', 'perf', 'test', 'build', 'ci', 'chore', 'revert', 'wip', 'workflow', 'types', 'release' ] ] }, prompt: { messages: { // 中文版 type: '选择你要提交的类型 :', scope: '选择一个提交范围(可选):', customScope: '请输入自定义的提交范围 :', subject: '填写简短精炼的变更描述 :\n', body: '填写更加详细的变更描述(可选)。使用 "|" 换行 :\n', breaking: '列举非兼容性重大的变更(可选)。使用 "|" 换行 :\n', footerPrefixsSelect: '选择关联issue前缀(可选):', customFooterPrefixs: '输入自定义issue前缀 :', footer: '列举关联issue (可选) 例如: #31, #I3244 :\n', confirmCommit: '是否提交或修改commit ?' }, types: [ // 中文版 { value: 'feat', name: '特性: 🚀 新增功能', emoji: '🚀' }, { value: 'fix', name: '修复: 🧩 修复缺陷', emoji: '🧩' }, { value: 'docs', name: '文档: 📚 文档变更', emoji: '📚' }, { value: 'style', name: '格式: 🎨 代码格式(不影响功能,例如空格、分号等格式修正)', emoji: '🎨' }, { value: 'refactor', name: '重构: ♻️ 代码重构(不包括 bug 修复、功能新增)', emoji: '♻️' }, { value: 'perf', name: '性能: ⚡️ 性能优化', emoji: '⚡️' }, { value: 'test', name: '测试: ✅ 添加疏漏测试或已有测试改动', emoji: '✅' }, { value: 'build', name: '构建: 📦️ 构建流程、外部依赖变更(如升级 npm 包、修改 webpack 配置等)', emoji: '📦️' }, { value: 'ci', name: '集成: 🎡 修改 CI 配置、脚本', emoji: '🎡' }, { value: 'chore', name: '回退: ⏪️ 回滚 commit', emoji: '⏪️' }, { value: 'revert', name: '其他: 🔨 对构建过程或辅助工具和库的更改(不影响源文件、测试用例)', emoji: '🔨' }, { value: 'wip', name: '开发: 🕔 正在开发中', emoji: '🕔' }, { value: 'workflow', name: '工作流: 📋 工作流程改进', emoji: '📋' }, { value: 'types', name: '类型: 🔰 类型定义文件修改', emoji: '🔰' } ], useEmoji: true, customScopesAlign: 'bottom', emptyScopesAlias: 'empty', customScopesAlias: 'custom', allowBreakingChanges: ['feat', 'fix'] } };
|
我们尝试一个错误的提交:
git commit -m "apx: test commit"
果真失败了,让我们尝试正确的提交
git commit -m "ci: 项目初始化,完成基本构建配置"
如果依然碰到**<u>.husky/commit-msg</u>**
执行权限的问题,你可能需要重新删除并创建它。
添加github工作流
项目最终需要部署到github pages,我们需要搭建工作流环境。
首先,在github 创建一个仓,该仓库不可以是私有的。
在本地项目的根目录下添加仓库
git remote add github <仓库url>
接着,我们需要进一步修改next.config.js
打包配置文件,修改后如下:
1 2 3 4 5 6 7 8 9 10 11 12 13
| /** @type {import('next').NextConfig} */ const nextConfig = { output:"export", images:{ //github pages 无法对图像优化 unoptimized:true }, //都是对应仓库名<reposity-name> basePath:"/react-components", assetPrefix:"/react-components" };
export default nextConfig;
|
再接着,我们再在项目根目录下创建一个github工作流文件,.github/workflows/deploy.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| # 1. 为工作流定义名字 name: Building React Components for github pages
# 2. 触发条件修改为: 当 指定的分支, 有 push 的时候, 执行任务 on: push: branches: - gh-pages # 这个选项可以使你手动在 Action tab 页面触发工作流 workflow_dispatch:
# 设置 GITHUB_TOKEN 的权限,以允许部署到 GitHub Pages。 permissions: contents: read pages: write id-token: write
# 允许一个并发的部署 concurrency: group: 'pages' cancel-in-progress: true
# 3. 创建工作流 jobs: deploy: #单次部署的工作描述 # Deploy to the github-pages environment environment: name: github-pages url: ${{ steps.deployment.outputs.page_url }} runs-on: ubuntu-latest # 依赖环境
steps: # 工作流步骤 # step 1. 获取源码, 拉取仓库代码 - name: Checkout 🛎️ # 步骤名 uses: actions/checkout@v3 # 使用插件 => https://github.com/actions/checkout
# step 2. 使用指定版本 node - name: Use Node 📦 # 步骤名 uses: actions/setup-node@v3 # 使用插件 => https://github.com/actions/setup-node with: # 插件携带参数 node-version: 18.19.0 # 指定 node 版本 # step 3. 安装pnpm - name: Install pnpm uses: pnpm/action-setup@v2 with: version: '8.10.0' # step 4. 安装依赖并打包 - name: Install dependencies run: pnpm install - name: Build run: pnpm build
- name: Setup Pages uses: actions/configure-pages@v3 - name: Upload artifact uses: actions/upload-pages-artifact@v1 with: # next 打包输出的文件夹 path: './out' - name: Deploy to GitHub Pages id: deployment uses: actions/deploy-pages@v2 #使用插件 => https://github.com/actions/deploy-pages
|
注意事项:
- 需要指定触发的分支,只有指定的分支才可以触发工作流,本文指定了
gh-pages
分支,main
作为开发分支不做部署,在需要部署时才把相关的commit 通过cherry-pick
到gh-pages
分支。因此,可以把工作流文件放置在gh-pages
分支中,并从main
分支中删除。
- 在工作流步骤的第二步中,需要指定node的版本,有时我们的项目需要node版本大等于某个版本,如果不符合要求将会导致工作流执行失败。
- 在工作流的第三步,需要指定
pnpm
的版本号符合package.json中的最低要求,和node版本的要求一致,如不符合也将导致工作流报错。
- 在工作流的第四步,需要指定真正的打包命令,一般都是
pnpm build
,但也有可能是其它的命令,特别是需要多种构建模式的项目中。如:pnpm build:web
- 最后,我们需要指定打包输出的文件夹,打包成功后,每次访问github pages 都将从这个目录下访问有关的静态资源。
最后,将gh-pages
分支推送到github,即可触发工作流,完成部署。可以在 仓库顶端的actions 里查看所有的构建情况:
绿色是成功,红色是失败,可以点击查看详情:
可以看到失败的原因:因为笔者是从别的项目拷贝过来的工作流配置,导致指定的打包命令并没有在本项目的package.json
文件中配置。
完成的成功情况,可以看到每一个过程的执行时间和线上的build阶段的时间,可以后续针对性做一些优化配置
最终部署结果,和本地运行的一致
小结
本文介绍了next.js搭建一个react 组件库文档的项目的基本目录结果,项目搭建过程;并详细说明了changesets、commitlint的配置, 并完成了github仓库的提交;接着,本文详细阐述了如何使用github 的github pages功能,并集成github 的工作流部署,还做了五点重点说明。
感谢您的阅读,让我们下篇再见。