醉丶春风的Blog

千里之行, 始于足下



React项目在 GitHub Page 上使用History route 部署的方法


React项目在 GitHub Page 上使用History route 部署的方法

前言

前段时间用React+TS+antd写了一个后台模板, 传送门
准备部署在GitHub page上当做demo方便查看, 在部署的过程中就遇到了这个一个问题, 折腾了一段时间, 最后通过曲线救国的方式解决了

分析

ghpage是不支持配置rewrite规则的, 因此访问一个不存在的目录时, 并不会给我们做重定向的功能, 所以此时就会看到404页面, 如果是hashRoute自然不会有这个问题.

这样看来, 这个问题岂不是无解了, 也不尽然, 虽然不会重定向, 但是他会优先从我们的ghpage根目录寻找404.html这个文件, 如果找到了,就是用这个文件当做404的模板页面

所以, 我们可以通过创建一个404.html文件的方式, 在这个页面中写js来做一些跳转

比如, 当访问https://xstnet.github.io/react-admin-template/dashboard 这个url的时候,由于我们的项目中不存在 dashboard这个文件, 也不存在dashboard这个目录, 因此Git就会返回一个404页面出来

404.html

创建一个404.html文件, 这个文件必须要位于项目的根目录, 也就是说假如我们的项目打包后生成了一个dist文件夹, 把dist这个文件夹当做gh-page的根目录的话, 那404.html的路径就是dist/404.html, 它和index.html是同级的

下面来看看应该怎么去写一个跳转逻辑

控制页面跳转

还是以https://xstnet.github.io/react-admin-template/dashboard 这个链接举例
已知我们能成功跳转的页面地址只有ghpage项目的首页, 也就是https://xstnet.github.io/react-admin-template,
但是光往这个地址跳没有意义啊, 又回到首页了, 因此我们要加东西, 加什么呢, 自然是加路由参数了, 不过要怎么加呢?

我采用的是吧页面路由部分当做参数跳回到首页, 也就是下面的规则:

原url: https://用户名.github.io/仓库名[/route]
跳转url: https://用户名.github.io/仓库名?ghpage=route

不管现在访问的是几级路由, 甚至可能后面还有参数, 不过不用管, 统一放到 ghpage参数中

不过这里还有个坑, 那就是在含有参数时, url中会含有?这个字符, 放到跳转地址中就会出现多个?, 不是一个标准的url了, 因此我们对ghpage=route部分再做一层处理, 如下伪代码
ghpage=encodeURIComponent(route);
使用 encodeURIComponent 转义一次就没有这个问题了

现在就可以往这个地址跳转了

代码实现

如下是我的404.html的代码
我采用的是动态获取仓库名的方式, 也就是取 location.pathname中第一个/字符前的所有字符串当做仓库名, 而第一个/之后的所有字符都当做参数传给ghpage

<!DOCTYPE html>
<html>
  <head>
        <title>Redirecting...</title>
        <script>
              const path = location.pathname;
              const pos = path.indexOf('\/', 1);
              const repo = path.substring(0, pos);
              const ghpage = path.substring(pos);
              const redirectUrl = location.origin+repo+'/?ghpage='+encodeURIComponent(ghpage+location.search);
              window.location.replace(redirectUrl);
            </script>
      </head>
  <body>
    Redirecting...
  </body>
</html>

例子

源url:
https://xstnet.github.io/react-admin-template/dashboard?a=1&b=2
经过代码处理后的跳转地址:
https://xstnet.github.io/react-admin-template?ghpage=dashboard%3Fa%3D1%26b%3D2

组件内路由处理

上面说完了跳转, 虽然最后带着参数跳转过来了, 但是组件内不处理的话, 带不带参数有什么区别吗?

下面开始处理, 只需要在我们的布局组件内监听一下即可

import { useNavigate, useSearchParams } from 'react-router-dom';

const [searchParams] = useSearchParams();

useEffect(() => {
  // 借助 gh-page 404.html的功能跳转回来, 解析路由并加载相应的页面
  if (searchParams.has('ghpage')) {
    const ghpage = decodeURIComponent(searchParams.get('ghpage')!);
      // 这里要注意如果跳转失败了要看看是否需要加上'/'前缀
      navigate(ghpage);
        return;
      }
}, [])

上面的代码使用useEffect时不需要依赖项, 因为从别的页面跳转过来肯定是全部页面都要重新加载的

这个时候再查看一下我的页面, 会发现中间有个短暂的重定向中转, 就是通过上面的方法实现的传送门

缺点

  • 刷新页面时会有一个重定向, 但是在页面内由navigage方法控制的跳转是不会有问题的
  • 组件内增加了对ghpage这个路由参数的监听

进阶

很多时候我们并不想在除了gh-pages分支上去创建一个404.html文件, 也没有必要, 但要使用上面的方法跳转必须要有一个404.html文件, 那还有别的方法吗?

答案无疑是确定的, 那就是使用Github Action 提供的workflow配置文件来生成

当我们使用Github Action来发布GitHub Page时, 就可以使用这种方法, 那就是把创建404.html文件这一步骤放到配置文件中
以下是我的.github/workflows/gh-pages.yml文件内容, 供参考

name: Publish To Github Page

on:
  push:
    branches:
      - master
  workflow_dispatch:

permissions:
  contents: write

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout 
        uses: actions/checkout@v2 # If you're using actions/checkout@v2 you must set persist-credentials to false in most cases for the deployment to work correctly.
        with:
          persist-credentials: false

      - name: Install and Build  # This example project is built using npm and outputs the result to the 'build' folder. Replace with the commands required to build your project, or remove this step entirely if your site is pre-built.
        run: |
          npm i -g pnpm
          pnpm install --no-frozen-lockfile
          pnpm run gh-pages

      - name: Generate 404 Page # This example project is built using npm and outputs the result to the 'build' folder. Replace with the commands required to build your project, or remove this step entirely if your site is pre-built.
        run: |
          echo "<!DOCTYPE html>" > dist/404.html
          echo "<html>" >> dist/404.html
          echo "  <head>" >> dist/404.html
          echo "    <title>Redirecting...</title>" >> dist/404.html
          echo "    <script>" >> dist/404.html
          echo "      const path = location.pathname;" >> dist/404.html
          echo "      const pos = path.indexOf('\/', 1);" >> dist/404.html
          echo "      const repo = path.substring(0, pos);" >> dist/404.html
          echo "      const ghpage = path.substring(pos);" >> dist/404.html
          echo "      const redirectUrl = location.origin+repo+'/?ghpage='+encodeURIComponent(ghpage+location.search);" >> dist/404.html
          echo "      window.location.replace(redirectUrl);" >> dist/404.html
          echo "    </script>" >> dist/404.html
          echo "  </head>" >> dist/404.html
          echo "  <body>" >> dist/404.html
          echo "    Redirecting..." >> dist/404.html
          echo "  </body>" >> dist/404.html
          echo "</html>" >> dist/404.html

      - name: Deploy 
        uses: JamesIves/github-pages-deploy-action@releases/v3
        with:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          BRANCH: gh-pages # The branch the action should deploy to.
          FOLDER: dist # The folder the action should deploy.

结束

至此, 折腾终于结束了, 也算是圆满解决了HistoryRouteGithub Page上发布的问题了

感谢阅读, 再见


作者: 徐善通
地址: https://xstnet.com/article-162.html
声明: 除非本文有注明出处,否则转载请注明本文地址


我有话说



最新回复


正在加载中....

Copyrights © 2016-2019 醉丶春风 , All rights reserved. 皖ICP备15015582号-1