Nuxt3 通过 Github Action 部署 Github Pages 的最佳实践

引言

我最近学习 Nuxt3,开发了一个个人主页,部署在 Github Pages 上面。感兴趣的朋友可以点开看看😜,gumplingo.github.io

Nuxt3 是一个全栈框架,可以用来开发全栈应用,既能开发服务端渲染(SSR)应用 、也能作为静态站点生成器(SSG)。

我把 Nuxt3 文档整个看了一遍,大概知道怎么开发了,但是没有开发目标,就简单做了个个人主页,之后就想着部署到 Github Pages 上。这我做过,以前就在仓库设置里,选择哪个分支个哪文件夹,之后 Github 就会部署你文件夹里面的文件了。

我隐约知道可以通过 Github Action 来自动部署更新 Github Pages, 于是进行了实践。如果一切顺利,那没什么好写,但就是不顺利,才有值得记录的点。希望以后遇到相同问题的人能从这篇文章得到启发。

准备工作

我们先来按照官网指引,创建一个 Nuxt3 项目。Node 环境要求18以上,我是20,采用 pnpm。

bash 复制代码
corepack enable && pnpm dlx nuxi@latest init nuxt-github-pages

跑起来看看:

bash 复制代码
cd nuxt-github-pages && pnpm dev

网页打开,没问题

Nuxt3 开发有几个命令,如下:

分别是 build 构建、dev 开发、generate 生成静态站点、preview 预览。 我们分别执行一下 build 和 generate 看看

首先是build命令,有两个构建,先构建 client, 然后构建 Server, 之后产物放在 .output下面,通过 执行 node .output/server/index.mjs启动应用。

接着是 generate 命令(先停掉前面的pnpm dev,会冲突导致报错),结果如下, 会在 .output/public生成静态文件, 这回没有server的构建了:

现在我们有一个 Nuxt3 项目了,具体怎么开发,大家可以自己上官网学习,我们直接进入主题:部署到 Github Pages。

初始化仓库

首先,我们在 Github 上面新建一个跟项目同名的远程仓库,按照说明将本地项目代码提交的远程仓库,我们的示例的项目名是 nuxt-github-pages

我们先把项目下的代码提交保存下 然后按照说明同步到远程仓库 我们刷新 Github 仓库看看 项目已经正常推送到远程仓库了

Github Pages

我们来看看 Github Pages 在哪里,以及如何设置: 我们点击 settings tab, 然后选择 pages 菜单项,就到了 Github Pages 相关的设置页面了: Github Pages 的部署的文件来源,有两个,分别是 Github Action 和 Branch 分支,默认是Branch 分支,在没有选择哪个分支,哪个文件夹之前,Github Pages 是默认不启用的。

我们先看看怎么在没有配合 Github Action 的情况下将 Github Pages 启用起来,可以访问。

当我想要选择文件夹的时候,可以看到,文件夹只有两个,只能是 /(root) 或者 /docs, 然而我们构建的静态文件产物是在 .output/public 目录下面的 此时,聪明的你,一定想到了,那就是改变打包时,放构建产物的文件名就好了,改为 docs 就行,我们如下改变生成构建产物的目录,执行pnpm generate 可以看到,左侧目录确实生成了docs文件夹,并且构建的产物也在里面。

我们提交一下代码,然后设置这个目录作为 Github Pages 的部署来源

在点击 Save 之后,Github 提示保存成功,并且 Github Pages 提供的文件会来自 docs 目录

注意!!这里并不是直接将 docs 文件夹作为静态目录提供页面访问服务,而是将这个目录的文件交给 Github 去打包处理,提供静态服务。因为我们保存设置之后,github 其内部自己跑了一个 Github Action 去部署了,我们点开 Actions tab 看看: 可以看到,有个工作流不久前执行过了,再点击进入工作流详情看看: 我们看到,确实打包和部署了,并且还把部署之后的地址给我们了。点开链接地址看看Github Pages是不是部署起来了 是起来了,但没完全起来 有些文件没加载到,这是因为我们部署的 publicPath 是 nuxt-github-pages, Github Pages 默认部署到跟仓库名一样的路径中,但打包的默认配置是 /

所以我们得改改打包构建的路径并重新构建pnpm generate

ts 复制代码
// nuxt.config.ts
export default defineNuxtConfig({
    ...
    app: {
        baseURL: '/nuxt-github-pages/'
    }
    ...
})

可以看到,产物的PublicPath都改了 我们提交代码,看看 github 又开始构建部署了 很快,大概40s就完成了 我们刷新 Github Pages 看看请求资源路径对不对 可以看到,请求路径对了,但是还是404,找不到文件,这是为什么呢?

经过Google,才知道,Github Pages 构建部署时候,会忽略隐藏文件比如.开头文件,_开头的文件也会忽略,而我们的构建产物,刚好是在_nuxt目录下面,还有个 _payload.json文件,这些都被忽略,导致文件找不到。

知道原因之后,你肯定也想到怎么解决了,就是改配置,不要用下划线开头作为产物文件夹哩!

ts 复制代码
// nuxt.config.ts
export default defineNuxtConfig({
    ...
    app: {
        baseURL: '/nuxt-github-pages/',
        buildAssetsDir: 'nuxt_assets',
    }
    ...
})

重新pnpm generate 改成功了,那还有一个_payload.json文件呢?暂时没有找到改名的方法,就只能把抽离的关闭了,这是一个实验性的配置,文档在这里

ts 复制代码
// nuxt.config.ts
export default defineNuxtConfig({
    ...
    experimental: {
        payloadExtraction: false
    },
    ...
})

再次打包下,pnpm generate,没有 _payload.json 文件了 经过上面的更改,产物没有特殊文件名的文件了,我们再次提交代码看看 一推上去远程仓库,又触发了 Github Pages 默认的部署工作流了 等待打包部署之后,我们再刷新页面看看 可以看到,所有的资源都正常加载了🥳

问题分析

以上,我们就算是部署了Nuxt3项目的 Github Pages 页面了,这个过程,有两个问题:

  • 不优雅!------ 打包是在我们本地完成的!打包产物是提交到远程仓库的。
  • 太折腾!------ 我们为了"迎合" Github Pages Branch 分支文件夹的部署方法,改了构建产物输出的目录为 /docs,改了构建产物的文件夹名以防止特殊文件名_开头。

期待的效果是:用Nuxt3默认的打包构建方式就好了,不需要改什么东西!其次,打包的过程应该得在远程打包的,构建产物不应该放在仓库里面的。

Github Action 打包 Nuxt3 项目

首先来解决本地打包的问题。

我们将打包 Nuxt3 项目成静态文件的过程,交给 Github Action 来做。

先恢复产物输出目录,前面我们将构建产物输出到 /docs下面,是为了可以选择该目录进行部署。我们先注释掉这个配置。用原来默认的输出目录就好 .output/public

在项目根目录(仓库根目录)添加目录 .github/workflows/deploy.yml配置文件,新增如下内容:

yml 复制代码
name: Deploy Nuxt3 App to GitHub Pages by branch

on:
  push:
    branches:
      - main # 根据实际的主分支名称修改

permissions:
  contents: write # 给予权限

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout Repository
        uses: actions/checkout@v4 # 从仓库复制一份代码

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20' # 使用适合的 Node.js 版本

      - name: Enable pnpm
        run: corepack enable # 启用 pnpm 或 yarn

      - name: Install Dependencies
        run: pnpm install # 或 yarn install,根据你的偏好选择

      - name: Generate Static Site
        run: pnpm generate # 生成静态站点的命令

      - name: Deploy to GitHub Pages
        uses: JamesIves/github-pages-deploy-action@v4 # 这个 action 能将你的构建产物,作为新增内容提交到 gh-pages 分支
        with:
          folder: .output/public # Nuxt3 生成的静态文件夹名称

Github Action 是根据这个配置文件干活的,以上配置文件每一步都写了注释。这里需要解释一下JamesIves/github-pages-deploy-action@v4 这个 action 是别人封装好了,它的作用就是将产物的某个文件夹内容,提交的你当前仓库的某个分支。我们上面用了默认配置,它默认是 gh-pages 有了以上配置,那么 Nuxt3项目打包的过程就可以放到 Github 远程来做了。

我们提交一下代码看看 提交之后触发了两个 workflow, 其中一个是我们前面配置的 Github Pages 默认的部署行为,只要你提交代码都会有,另一个才是我们配置的打包 workflow 等打包完成之后,我们点击 Code tab,查看一下分支 会发现多了一个 gh-pages分支,我们切换看看里面有什么内容 确实我们项目打包出来的静态代码没错了,那么到这里,我们就把打包的过程放到了远程了

然后我们改一下 Github Pages 的设置就行了,我们不再用 main分支的 /docs作为部署目录了,我们设置为 gh-pages/(root) 分支了 改完之后,会触发重新部署的 workflow 刷新一下页面,看到所有资源都正常加载了,改造成功🥳

到这里,我们把打包的过程放到了远程做,并且也不会把产物代码放到仓库的主分支了。

然而,事情并不完美。我们更新页面,需要两个 workflow 才能完成,一个是我们自己的打包 workflow, 一个是 Github Pages 本身的 workflow。

我们提交代码,触发自己的工作流,打包完成会提交到 gh-pages分支,之后由于 Github Pages 监听这个分支,然后触发了 Github Pages 的重新部署。这里依然要经过 Github Pages 默认的分支打包部署,所有上面提到问题依然存在,产物文件不能是_开头文件、.开头文件,所以还是不能用 Nuxt3 默认的打包配置。

能不能一步到位,不要经过分支啊?直接从 Github Action 就部署到 Github Pages 呢?

可以的。

Github Action 打包 Nuxt3 项目并部署 Github Pages

我们将配置文件里面改产物目录的配置注释掉(baseURL得留着) 执行 pnpm generate看看构建产物是否恢复成默认的样子 没问题。我们把上面的workflow备份下放到根目录,重新编写一份吧 新的 workflow 内容如下:

yaml 复制代码
name: Deploy Nuxt3 App site to Pages by action

on:
  # 在针对 `main` 分支的推送上运行。如果你
  # 使用 `master` 分支作为默认分支,请将其更改为 `master`
  push:
    branches: [main]

  # 允许你从 Actions 选项卡手动运行此工作流程
  workflow_dispatch:

# 设置 GITHUB_TOKEN 的权限,以允许部署到 GitHub Pages
permissions:
  contents: read
  pages: write
  id-token: write

# 只允许同时进行一次部署,跳过正在运行和最新队列之间的运行队列
# 但是,不要取消正在进行的运行,因为我们希望允许这些生产部署完成
concurrency:
  group: pages
  cancel-in-progress: false

jobs:
  # 构建工作
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Repository
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20' # 使用适合的 Node.js 版本

      - name: Enable pnpm
        run: corepack enable

      - name: Install Dependencies
        run: pnpm install # 或 yarn install,根据你的偏好选择

      - name: Generate Static Site
        run: pnpm generate # 或者其他生成静态站点的命令,具体取决于你的 Nuxt.js 配置 # 或 pnpm docs:build / yarn docs:build / bun run docs:build

      - name: Upload artifact
        uses: actions/upload-pages-artifact@v3
        with:
          path: .output/public

  # 部署工作
  deploy:
    environment: # 部署环境
      name: github-pages # 部署到 GitHub Pages
      url: ${{ steps.deployment.outputs.page_url }} # 部署后的 URL
    needs: build # 郈接到构建工作
    runs-on: ubuntu-latest # 运行环境
    name: Deploy # 工作名称
    steps: # 步骤
      - name: Deploy to GitHub Pages # 部署到 GitHub Pages
        id: deployment # 步骤 ID
        uses: actions/deploy-pages@v4 # 使用的 action

和前面的工作流的差异在这一部分,详见文档

后面两个就是直接部署到 Github Pages 的两个必要动作。

我们来到远程仓库的 Github Pages 设置页面,改成从 action 部署 现在我们来提交代码,看看会触发几个 workflow 点进去看看详情 结果如预期,只有一个工作流触发了 Github Pages 的部署。 我们来改改代码页面,整体看一下是不是这样的流程:提交代码-打包代码- Github Pages 部署更新。

添加一行字,提交代码 查看 Action Tab, 看到触发了workflow 打包完成之后,看看是否更新了 Github Pages 我们看看 Network 面板,特殊开头的文件也能正常加载到。

Hooray!!!🥳 完美

总结

本文从实际需求出发,讲解如何通过 Github Action 优雅部署 Github Pages。

我们先讲解了单独设置 Github Pages 从分支和目录部署的方法,分析这样做的问题

  • 不优雅!打包在本地完成的,还得把产物推到远程仓库
  • 太折腾!得改打包配置迎合 Github Pages 默认打包忽略特殊文件(_.开头)

然后我们用 Github Action 尝试在远程打包,然后将产物提交到单独的分支,这样就不会影响主分支有打包产物了,这样只解决了一个问题,还是得迎合,因为还得经过 Github Pages 默认的分支部署

于是,根据文档说明,改成采用 Github Action 直接部署 Github Pages, 完美又优雅~

本文示例代码仓库在这里, 访问页面在这里

我的主页代码仓库在这里, 访问页面在这里

最后,点赞投币加关注,追番不迷路~ 咳咳...串台了,求点赞收藏~

相关推荐
爱喝水的小鼠1 小时前
Vue3(一) Vite创建Vue3工程,选项式API与组合式API;setup的使用;Vue中的响应式ref,reactive
前端·javascript·vue.js
小晗同学1 小时前
Vue 实现高级穿梭框 Transfer 封装
javascript·vue.js·elementui
forwardMyLife1 小时前
element-plus的面包屑组件el-breadcrumb
javascript·vue.js·ecmascript
计算机学姐2 小时前
基于python+django+vue的影视推荐系统
开发语言·vue.js·后端·python·mysql·django·intellij-idea
luoluoal2 小时前
java项目之基于Spring Boot智能无人仓库管理源码(springboot+vue)
java·vue.js·spring boot
mez_Blog2 小时前
个人小结(2.0)
前端·javascript·vue.js·学习·typescript
深情废杨杨3 小时前
前端vue-插值表达式和v-html的区别
前端·javascript·vue.js
GHUIJS3 小时前
【vue3】vue3.3新特性真香
前端·javascript·vue.js
众生回避3 小时前
鸿蒙ms参考
前端·javascript·vue.js
洛千陨3 小时前
Vue + element-ui实现动态表单项以及动态校验规则
前端·vue.js