likes
comments
collection
share

react-router hash mode 转为 history mode 踩坑记结果你猜怎么着,点击到某个路由,手动

作者站长头像
站长
· 阅读数 14

今天老板让我把 hash mode 改为 history mode

我想这还不简单吗

import {HashRouter as Router} from 'react-router-dom';
<Router hashType="noslash">
    <App />
</Router>

// ----- 转化为----

import {BrowserRouter as Router} from 'react-router-dom';
<Router>
    <App />
</Router>

结果你猜怎么着,点击到某个路由,手动刷新后白屏了。 react-router hash mode 转为 history mode 踩坑记结果你猜怎么着,点击到某个路由,手动

  • Q:为啥会白屏呢?
  • A:是因为 html 里引用的 js 找不到了
  • Q:为啥 hash router 找得到对应的 js 文件,history router 就找不到呢?

hash 模式下,当前路由为http://localhost::8080/#/square/publish react-router hash mode 转为 history mode 踩坑记结果你猜怎么着,点击到某个路由,手动 其查找的是根路径下的文件,所以能正确命中对应的资源。

而在 history 模式下,当前路由为http://localhost::8080/square/publish

react-router hash mode 转为 history mode 踩坑记结果你猜怎么着,点击到某个路由,手动

经测试,http://localhost::8080/square/publish 路径下放的资源,它会在http://localhost::8080/square/ 这个路径下查找。也就是说,在这个设置下,资源路径为相对于当前目录的地址,我们需要将其变为相对于根路径的地址

那么这个经过 webpack 编译后html 文件中 scriptsrc 是哪里来的呢,让我们看看 webpack 源码

  // eslint-disable-next-line no-unused-vars
  function hotDownloadUpdateChunk(chunkId) {
      var script = document.createElement("script");
      script.charset = "utf-8";
      script.src = $require$.p + $hotChunkFilename$;
      if ($crossOriginLoading$) script.crossOrigin = $crossOriginLoading$;
      document.head.appendChild(script);
  }

  ...

  const publicPath = this.getPublicPath({
            hash: hash
        });
        buf.push("");
        buf.push("// __webpack_public_path__");
        buf.push(`${this.requireFn}.p = ${JSON.stringify(publicPath)};`); // 这里就是上面的 $require$.p
        return Template.asString(buf);
    });

  this.requireFn = "__webpack_require__";

由源码可知,script.src 是经由 $require$.p + $hotChunkFilename$ 拼接而来的,查找 $require$.p 赋值的位置可得,其来源于 publicPath ,由此可得我们修改 webpack 配置

output: {
    publicPath: '/',
},

就可将 <script src="[name].[hash:8].bundle.js" /> 转化为 <script src="/[name].[hash:8].bundle.js" />,那么它查找的路径便是相对于根路径,就能正确找到对应的 js 资源了。 react-router hash mode 转为 history mode 踩坑记结果你猜怎么着,点击到某个路由,手动

==================== 更新 2020.1.19 ===================

嗯,这件事还有后续,

由于发现项目中的多入口配置跟 history mode 冲突了,也就是说当寻找 0.0.0.0:8080/entry.html/main?id=${md5} 的时候,刷新了仍然是 GET 404

SO AWAFUL !!!

于是只好在 html 中设置

<base href="/">

这个设置跟上面 webpack 的作用是一致的,设置静态资源的路径为根路由。

然后,在 webpack 设置

devServer: {
	historyApiFallback: {
    	verbose: true,
        rewrites: [
        	{from: /^\/entry\/.*$/, to: '/entry.html'},
        ],
    },
}

介个设置的意思是,在 urllocalhost:8080/entry/main, 它会重定向到 localhost:8080/entry.html/main

然后

当部署到服务器的时候,同样需要修改 nginx 配置,

location / {
    rewrite ^/entry/(.+?) /entry.html/$1 last
}

===================== 我是卖萌的分界线 =====================

react-router hash mode 转为 history mode 踩坑记结果你猜怎么着,点击到某个路由,手动

转载自:https://juejin.cn/post/6917551174375702535
评论
请登录