之前很少接觸前端專案的部署,這次為了更全面的學習就在本機上裝了一個虛擬機器上,在虛擬機器上練習瞭如何把一個 react
寫的 spa
專案部署到這個虛擬機器的伺服器上。由於 linux
也是剛接觸不久,所以整個過程還是遇到了很多坑,這裡記錄下。
目標
我有一個用 react
寫的單頁面應用,然後希望部署到伺服器上,通過 ip
如 192.168.1.240/config
這種路徑下訪問到我的應用。這個 react
專案依賴一個 node.js
的一個 api
服務,我需要在 nginx
上配置代理使得我的 react
應用能夠訪問到我的 api
服務。
準備
首先要準備的就是打包好的的 react
應用,然後在伺服器上裝一個 nginx
和一個 node.js
。
針對我這個專案, 我把 react
打包好的專案全部放到了 /root/html/pageConfig
這個路徑下。
nginx配置
修改 nginx
安裝目錄下的 ./conf/nginx.conf
檔案:
#user nodody;
# 1. 由於我的 react 專案打包出來放在 root 目錄下,需要設定user 為 root 時內容才能夠被訪問
user root;
worker_processes 1;
#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
#log_format main `$remote_addr - $remote_user [$time_local] "$request" `
# `$status $body_bytes_sent "$http_referer" `
# `"$http_user_agent" "$http_x_forwarded_for"`;
#access_log logs/access.log main;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 65;
#gzip on;
server {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
root html;
index index.html index.htm;
}
# 2. 對我的/api請求轉發到8989埠下node.js服務
location /api {
proxy_pass http://127.0.0.1:8989;
}
# 3. 在/config下的請求都指向到我放在root下的configPage裡的內容
location /config {
alias /root/html/configPage;
index index.html index.htm;
#rewrite /config /root/html/configPage/index.html;
try_files $uri $uri/ /config/index.html;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
複製程式碼
這裡就是隻修改了預設配置檔案的三個地方,來滿足我的要求:
- 修改
user
為root
,使得root
下的內容能夠被訪問 - 新增
location /api
設定proxy_pass
使得/api
下的請求都被轉發到proxy_pass
設定的node.js
服務處,滿足我的前端頁面api
介面代理的問題 - 新增
location /config
的配置,使得/config
下請求都轉發至我react
打包檔案所在的路徑。這樣我訪問192.168.1.240/config
就能看到我的頁面。這裡我當初是複製的location /
的配置,用的也是root
指向路徑,結果一直不行,查了資料,發現應該要寫成alias
才行
這裡的配置檔案可能需要更改多次,才能成功,需要注意的是,每次修改完 nginx
配置,需要重啟下 nginx
:
nginx -s reload
複製程式碼
靜態資源路徑問題
把打包好的檔案傳到伺服器上的時候,可能出現靜態資原始檔找不到的情況。
資源路徑找不到的原因
可能的原因是當 react
應用打包的時候,生成 index.html
檔案中插入 style
和 script
標籤的路徑不對,從而找不到靜態資源。
靜態資源找不到的解決方法
需要在 webpack
的配置檔案中去修改一下 publicPath
這個屬性,這個屬性會影響你的靜態資原始檔插入到 index.html
中的路徑。像我這個專案設定 publicPath: `./`
就可以了,具體可以多修改幾次多打包幾次試試就行了。
前端路由
前端路由分類
前端路由分為兩種實現,一種就是 hashRouter
,另一種就是用 H5
新的 History API
實現的 browserRouter
。由於 hashRouter
的路徑帶一個 #
不是特別好看,一般還是用 browserRouter
較多。
前端路由的問題
前端路由說白了就是路徑變了,不去請求伺服器,而是用 js
去改變頁面的方式。這樣的話,用 browserRouter
的話這裡就存在一個問題,我用前端路由跳轉到某一個路徑下 /xxx
,這是我重新整理頁面,這時候就會去伺服器上拿資源,這個前端路由路徑下肯定找不到資源,所以就會出現 404
報錯。
解決方案
解決頁面重新整理 404
這個問題,只需要把所有的請求全部返回 index.html
,可以搜尋 history fallback
這個關鍵詞檢視相關資料。
針對我的這個 nginx
配置而言,只需要加入 try_files $uri $uri/ /config/index.html;
,就能把前端路由路徑傳送給伺服器時全部返回 index.html
,這樣就解決了 404
問題。
Route路徑匹配問題
配置好上述的 nginx
以及把打包好的檔案放到對應的目錄,再把我的 api
服務啟動,再訪問 192.168.1.240/config
時,已經能夠正常的顯示頁面,並且介面也能正常代理請求到了。但是涉及到路由的頁面卻沒有被渲染出來。
Route路徑匹配的原因
回想一下,在 react-router-dom
的 Route
標籤裡傳遞一個 path={`/xx`}
的屬性時,前端路由會根據這個 path
來渲染對應的 Route
上傳遞過去的 Component
元件。那麼在我的 nginx
的設定中,我設定的是 location /config
,也就是說我實際訪問路徑都是加上了字首 /config
,所以每個 Route
標籤中傳過去的路徑都因為缺少了 /config
字首導致所以的匹配都不成立,所以 Route
的頁面都沒有辦法渲染。
Route路徑匹配修改方法
方法很簡單,在 BrowserRouter
上加一個 basename
的屬性,給這屬性傳遞 config
(具體是什麼值,依據你給 nginx
設定 location
時的字首,我的例子中是 config
),這樣 Route
在匹配路徑的時候會加上 basename
,這樣就能和對應路徑匹配上,然後渲染對應頁面。
總結
對 linux
不熟悉,nginx
也不熟悉,依靠著百度,摸爬滾打嘗試修改了好多次 nginx
配置,終於能夠 react
打包好的檔案部署上去了, vue
專案的部署也是沒什麼區別的。