React-router4和webpack中output的publicPath相關關係

背景

在使用react-router4的BrowserHash,設置webpack中publicPath為./之後,將前端打包給php後端進行部署;部署完之後,頁面首頁可以正常打開,但是在打開二級路由之後,報錯

Uncaught SyntaxError: Unexpected token <

這就很奇怪了,明明在本地跑的很正常啊,這種錯誤很莫名其妙。

基本知識點補充

webpack中的publicPath,按照官方理解:

對於按需載入(on-demand-load)或載入外部資源(external resources)(如圖片、文件等)來說,output.publicPath 是很重要的選項。如果指定了一個錯誤的值,則在載入這些資源時會收到 404 錯誤。

此選項指定在瀏覽器中所引用的「此輸出目錄對應的公開 URL」。相對 URL(relative URL) 會被相對於 HTML 頁面(或 <base> 標籤)解析。相對於服務的 URL(Server-relative URL),相對於協議的 URL(protocol-relative URL) 或絕對 URL(absolute URL) 也可是可能用到的,或者有時必須用到,例如:當將資源託管到 CDN 時。

太抽象了!

簡單來說就是項目中依賴的開發資源,當部署到線上機器之後,被引用的線上路徑。

Eg.在本地開發環境中,某個css文件引用了圖片文件test.png,然而在生產環境下,test.png文件可能需要從CDN中獲取。這時候你就可以將output中publicPath設置為對應CDN的路徑。比如:xyzsosjfos/

// 開發環境:localhost(域名)下 .image { background-image: url(./test.png); }// 生產環境:圖片在CDN上 .image { background-image: url(https://xyzsosjfos/test.png); }

React-router中兩種模式:HashRouter和BrowserRouter

根據官網的解釋:

  • HashHistory 常用於舊款瀏覽器。

http://abc/#/home/xxx

  • BrowserHistory 使用於現代瀏覽器,支持H5 history API。也就是常見的URL格式,例如

http://abc/home/xxx

看起來browserHistory更符合我們用戶看到的網址樣式,但是它需要後端server的支持。

使用hashHistory的時候,因為 url 中 # 符號的存在,從 /#/ 點擊切換到 /#/home/xxx 瀏覽器並不會去發送一次 request,react-router 自己根據 url 去 render 相應的模塊;

如果這時候url切換到了/#/home/xxx,然後直接刷新頁面;後端server會根據/#/之前的路徑進行路由匹配,#後面的永遠走前端匹配。

使用 browserHistory 的時候,瀏覽器從 / 到 /home/xxx ,如果只是通過前端頁面功能進行跳轉,瀏覽器也不會向server發送請求;直接走前端路由;

如果這時候url切換到了/home/xxx,然後直接刷新頁面;後端server會根據/home及之前的路徑一起進行路由匹配,所以 server 端是要做特殊配置,來匹配對應的路由請求。

原因

Unexpected token <,是因為頁面在載入拆分生成的js的bundle模塊時候出錯導致的。

這裡的react-router4使用的是browserHash模式,publicPath設置為./;

當剛開始載入頁面的時候,index.html中引入的js文件(通過webpack進行動態載入打包,會根據路由生成多個js文件),

當然這裡的引入都是通過相對路徑(因為webpack的publicPath設置為./)

<script type="text/javascript" src="./static/js/main.5ac627ca.js"></script>

首次載入index.html之後,會引入當前路徑下面static/js/下的main.js文件;當點擊切換到其他路由,或是二級路由的時候,main.js中也是通過相對路徑載入靜態的js資源;這是main.js中的一個片段:

s.src=t.p+"static/js/"

然而main.js和需要引用的其他js文件在同一個目錄下,這時候通過這種相對路徑引用,明顯獲取不到相應的js文件,所以直接報錯。

解決方法

  1. 更改react-router的模式;使用HashRouter的方式,這樣更改路由,點擊切換到二級路由的時候,前端直接根據url去render相應的展示模塊。
  2. 更改webpack中output的publicPath為』/『;首次載入進行server匹配規則時,會將root根路徑定位到一個存放前端資源的項目路徑下;類似

root /home/xxx/xxxx/webroot;

這樣每次index.html中請求資源就會變為絕對路徑,然後在引用相應的js資源的時候,都會通過絕對路徑來獲取;

<script type="text/javascript" src="/static/js/main.78e5182b.js"></script>

當點擊切換路由的時候,會根據前端的路由匹配規則,main.js中通過絕對路徑載入靜態的js資源;

因為是根據絕對路徑獲取,所以總是可以定位到static/js/下面的資源,而不會報錯。

這裡還需要解決一個問題:

當切換到二級路由的時候,用戶刷新了頁面,這時候會根據頁面url向server發送請求,獲取對應的資源;

比如現在打開了頁面的二級路由,abc/home/xxx,然後直接刷新;需要伺服器進行相應的配置;

Nginx伺服器,加上:

location / { try_files $uri /index.html}

具體伺服器需要做的配置,可參考:

React-Router browserHistory瀏覽器刷新出現頁面404解決方案 - Thinktxt

~done


推薦閱讀:

TAG:reactrouter | webpack | React |