nextjs 构建自己的react组件库(一) - 项目的初始化配置和部署

导读

本文基于以下包和版本配置:

包名 版本号
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

perl 复制代码
npx reate-next-app@14.2.15

使用app router的模式

本地运行

确保你使用了pnpm作为包管理工具,如果没有安装,请使用 npm i -g pnpm安装。

本地运行项目,使用 pnpm dev命令

到这里,一切都是正常的,说明我们的应用没有问题,一切都是纯粹的模样,接下来我们直接打包,保证我们的项目不会半途因为出现不知名的问题无法排查。(笔者在此之前已经用pages router模式搭建几乎完成了,但是打包部署始终无法成功,更要命的是开发模式也无法正常启动了。因此强烈建议每引入新的东西不仅开发模式引入就行了,打包部署尽可能都尝试一遍看看,如何出现发生了错误就能快速定位了。)

当前的next.config.js 文件的配置是

arduino 复制代码
/** @type {import('next').NextConfig} */
const nextConfig = {};
​
export default nextConfig;

可以看到是空的,我们什么都不给尝试打包 npm run build

可以看到,打包是成功了的。

由于我们的项目是一个monorepo的组件库和文档,我们需要pnpm 的workspace(工作空间)提供的能力,

可以在项目根目录中加入一个文件pnpm-workspace.yaml,内容如下:

makefile 复制代码
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命令中增加几条

perl 复制代码
{
  "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 typescript@5.4.4 -r -D

未来该版本可能不可用,如果5.4.4没用的话,可以通过执行 pnpm view typescript versions查看一个可用的版本。

分别查看packages/image-gallery/packages.jsonpackages/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的初始化。()

csharp 复制代码
npx husky-init
# 下面这一句通常执行成功,但是没什么吊用
npx husky add .husky/commit-msg 'npx --no-install commitlint --edit "$1"'

我们需要手动在项目根目录下的.husky目录下 新增一个commit-msg文件

文件内容为:

bash 复制代码
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
​
npx --no-install commitlint --edit
"$1"
​

为了避免执行错误,我们还需要赋予执行的权限

chmod +x .husky/commit-msg

之后,我们需要在项目的根目录添加一个commitlint.config.cjs的文件

css 复制代码
// @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打包配置文件,修改后如下:

arduino 复制代码
/** @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

yaml 复制代码
# 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
​

注意事项:

  1. 需要指定触发的分支,只有指定的分支才可以触发工作流,本文指定了gh-pages分支,main作为开发分支不做部署,在需要部署时才把相关的commit 通过cherry-pickgh-pages分支。因此,可以把工作流文件放置在gh-pages分支中,并从main分支中删除。
  1. 在工作流步骤的第二步中,需要指定node的版本,有时我们的项目需要node版本大等于某个版本,如果不符合要求将会导致工作流执行失败。
  1. 在工作流的第三步,需要指定pnpm的版本号符合package.json中的最低要求,和node版本的要求一致,如不符合也将导致工作流报错。
  1. 在工作流的第四步,需要指定真正的打包命令,一般都是pnpm build,但也有可能是其它的命令,特别是需要多种构建模式的项目中。如:pnpm build:web
  1. 最后,我们需要指定打包输出的文件夹,打包成功后,每次访问github pages 都将从这个目录下访问有关的静态资源。

最后,将gh-pages分支推送到github,即可触发工作流,完成部署。可以在 仓库顶端的actions 里查看所有的构建情况:

绿色是成功,红色是失败,可以点击查看详情:

可以看到失败的原因:因为笔者是从别的项目拷贝过来的工作流配置,导致指定的打包命令并没有在本项目的package.json文件中配置。

完成的成功情况,可以看到每一个过程的执行时间和线上的build阶段的时间,可以后续针对性做一些优化配置

最终部署结果:

小结

本文介绍了next.js搭建一个react 组件库文档的项目的基本目录结果,项目搭建过程;并详细说明了changesets、commitlint的配置, 并完成了github仓库的提交;接着,本文详细阐述了如何使用github 的github pages功能,并集成github 的工作流部署,还做了五点重点说明。

感谢您的阅读,让我们下篇再见。

相关推荐
程序员小寒3 分钟前
前端高频面试题之Vue(初、中级篇)
前端·javascript·vue.js
陈辛chenxin10 分钟前
软件测试大赛Web测试赛道工程化ai提示词大全
前端·可用性测试·测试覆盖率
沿着路走到底11 分钟前
python 判断与循环
java·前端·python
Code知行合壹14 分钟前
AJAX和Promise
前端·ajax
大菠萝学姐24 分钟前
基于springboot的旅游攻略网站设计与实现
前端·javascript·vue.js·spring boot·后端·spring·旅游
心随雨下36 分钟前
TypeScript中extends与implements的区别
前端·javascript·typescript
摇滚侠40 分钟前
Vue 项目实战《尚医通》,底部组件拆分与静态搭建,笔记05
前端·vue.js·笔记·vue
双向3341 分钟前
CANN训练营实战指南:从算子分析到核函数定义的完整开发流程
前端
caleb_52042 分钟前
vue cli的介绍
前端·javascript·vue.js
Swift社区43 分钟前
如何监测 Vue + GeoScene 项目中浏览器内存变化并优化性能
前端·javascript·vue.js