若只將 Vue Deploy 到單一 Domain 則比較單純,但若是 Domain 的 Sub-Path,則 Vue CLI 與 Nginx 都需要加上其他設定。
Version
Nginx 1.18
Vue 2.6.11
Chrome
假設我們想將 Vue deploy 到 domain 的 /admin
,Vue CLI 與 Nginx 各該如何設定呢 ?
.env
BASE_URL=admin
在 project 根目錄新增 .env
,設定 BASE_URL
為 admin
。
為什麼要叫
BASE_URL
呢 ? 稍後會看到 Vue 很多檔案已經使用BASE_URL
這個 environment variable
vue.config.js
module.exports = {
publicPath:`/${process.env.BASE_URL}`
}
在 project 根目錄新增 vue.config.js
,設定 publicPath
為 BASE_URL
environment variable。
至此 Webpack 在 build-time 都會加上 admin
sub-path。
Vue CLI 4.x 要在 path 前加上
/
index.html
Vue 對於 public
目錄下的 index.html
的 favicon.ico
已經加上 BASE_URL
修正 href
attribute。
router/index.js
Vue router 也使用了 BASE_URL
environment variable。
這也是為什麼我們在
.env
配合 Vue 繼續使用BASE_URL
原因
dockerfile
FROM nginx:stable-alpine
WORKDIR /usr/share/nginx/html
COPY dist .
COPY nginx/default.conf /etc/nginx/conf.d/default.conf
EXPOSE 8080
第 1 行
FROM nginx:stable-alpine
由 nginx:stable-alpine
為基底建立 Docker image。
第 2 行
WORKDIR /usr/share/nginx/html
設定 /usr/share/nginx/html
為預設目錄,如此當進入 container 內部時,預設就是此目錄方便 debug。
第 3 行
COPY dist .
將 yarn build
下所有檔案複製到 container 內部的 /usr/share/nginx/html
預設目錄內。
第 4 行
COPY nginx/default.conf /etc/nginx/conf.d/default.conf
將 Nginx 的 default.conf
取代 container 內的 default.conf
。
第 5 行
EXPOSE 8080
表示 container 將使用 8080
port。
Nginx Configuration
server {
listen 8080;
server_name localhost;
location /admin {
alias /usr/share/nginx/html;
expires -1;
add_header Pragma "no-cache";
add_header Cache-Control "no-store, no-cache, must-revalidate, post-check=0, pre-check=0";
try_files $uri $uri/ /index.html = 404;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
第 1 行
listen 8080;
設定 Nginx 使用 8080
port,與 dockerfile
的 EXPOSE 8080
相對應。
8080
最關鍵的設定是在 Nginx,dockerfile
的EXPOSE
只是給人寫docker-compose
時參考使用
第 5 行
location /admin {
設定 Nginx 使用 admin
sub-path。
這是本文最關鍵設定,否則 Nginx 無法使用
admin
sub-path
第 6 行
alias /usr/share/nginx/html;
admin
sub-path 相當於 container 內部的 /usr/share/nginx/html
。
注意要使用
alias
而非root
12 行
try_files $uri $uri/ /index.html = 404;
由於 Vue 為 SPA,當 URL 找不到時,Nginx 會自動導到 index.html
,由 Vue router 決定。
docker-compose.yml
version: "3"
services:
nginx:
image: vue-publicpath:0.1.0
container_name: MyNginx
restart: always
ports:
- 80:8080
第 4 行
image: vue-publicpath:0.1.0
使用 vue-publicpath:0.1.0
Docker image。
第 5 行
container_name: MyNginx
自行命名 container 名稱為 MyNginx
。
第 6 行
restart: always
當執行失敗時會自動重啟 container。
第 7 行
ports:
- 80:8080
將 host 的 80
port 對應到 container 的 8080
port。
NPM Script
package.json
{
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint",
"docker:build": "yarn build && docker build -t $npm_package_name:$npm_package_version .",
"docker:login": "docker exec -it MyNginx sh",
"docker:log": "docker logs MyNginx",
"docker:up": "docker-compose up -d",
"docker:down": "docker-compose down",
"docker:rmi": "docker rmi $npm_package_name:$npm_package_version"
}
}
第 3 行
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint",
原本 Vue CLI 所內建的 NPM Script。
第 6 行
"docker:build": "yarn build && docker build -t $npm_package_name:$npm_package_version .",
執行 yarn build
使用 Webpack 打包到 dist
目錄下,並且使用 docker build
根據 dockerfile
建立 Docker image。
直接使用
$npm_package_name
與$npm_package_version
讀取package.json
中的name
與version
,將來改版只要修改version
即可
第 7 行
"docker:login": "docker exec -it MyNginx sh",
進入 container 內 debug 用。
第 9 行
"docker:up": "docker-compose up -d",
根據 docker-compose.yml
啟動 container。
第 10 行
"docker:down": "docker-compose down",
結束 container。
11 行
"docker:rmi": "docker rmi $npm_package_name:$npm_package_version"
刪除 Docker image。
Conclusion
- 要使 Vue 能在 domain 的 sub-path 使用有兩個關鍵:Vue CLI 要使用
BASE_URL
environment variable 且在vue.config.js
使用publicPath
property;Nginx Configuration 則要建立 sub-path rule 並使用alias
Reference
Vue CLI, publicPath
Arne, Serving a vue-cli Production Build on a Sub-Path with Nginx