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 的工作流部署,还做了五点重点说明。

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

相关推荐
哑巴语天雨15 分钟前
React+Vite项目框架
前端·react.js·前端框架
初遇你时动了情28 分钟前
react 项目打包二级目 使用BrowserRouter 解决页面刷新404 找不到路由
前端·javascript·react.js
乔峰不是张无忌3301 小时前
【HTML】动态闪烁圣诞树+雪花+音效
前端·javascript·html·圣诞树
鸿蒙自习室1 小时前
鸿蒙UI开发——组件滤镜效果
开发语言·前端·javascript
m0_748250741 小时前
高性能Web网关:OpenResty 基础讲解
前端·openresty
前端没钱1 小时前
从 Vue 迈向 React:平滑过渡与关键注意点全解析
前端·vue.js·react.js
NoneCoder2 小时前
CSS系列(29)-- Scroll Snap详解
前端·css
无言非影2 小时前
vtie项目中使用到了TailwindCSS,如何打包成一个单独的CSS文件(优化、压缩)
前端·css
我曾经是个程序员2 小时前
鸿蒙学习记录
开发语言·前端·javascript
羊小猪~~2 小时前
前端入门之VUE--ajax、vuex、router,最后的前端总结
前端·javascript·css·vue.js·vscode·ajax·html5