前端專案應該如何部署
一個標準的前端專案,必定始於yarn start,它將會經歷babel編譯,webpack構建,server啟動等流程,然後由瀏覽器載入頁面。這是很Dev的開發方式,可生產環境我們卻往往不這麼做。
1.何為前端?
如果按照以前的看法,前後端最本質的區別當然是執行環境了,一個是瀏覽器中所寫即所見
的UI介面,另一個則是藏在背後
的服務。
在這種簡單的區分下,前端往往會被定義為HTML/CSS/Javascript
。沒錯,前端就是這些東西,這就是瀏覽器所需要呈現的;可也不能只有這些東西:前端有時也需要自己的後端server
來充當API的中間層,也需要資料儲存(如localStorage, sessionStorage, indexedDB...)
個人認為,最簡單的區別方法就是用API來劃分:API的處理方如果在Node.js
端,那麼這個JS專案絕對就是後端(Node端如果只作為中間層轉發則不算數);否則,如果只是作為API資料的請求方,並且有UI展現,就算是前端了。
2.有無server?
為什麼要浪費篇幅去講前端的定義,就是因為只有明確定義好前端之後,才能解決一個問題:前端到底要不要server?
,因為它很大程度上決定了如何部署。
一般的前端專案都會有dist
產出,通常是由一個index.html
vendor.js
和其他類似圖片字型等資源構成。
那麼這個產出物是如何被render出來的呢?
- Case1: 利用webpack server
以下為webpack配置啟用webpack server的片段:
var path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
devServer: {
contentBase : path.join(__dirname, "dist"),
compress: true,
port: 3000,
watchOptions: {
poll: true
}
}
};
這種case顯然只是render靜態的html和資源,因此webpack server只在開發使用,生產則根本不需要。
- Case2: 利用靜態伺服器
其實和case1類似,如果只是render靜態html,那麼利用類似Python
:
$ python -m SimpleHTTPServer 3000
或者Nginx
做代理都是很方便實現的。
- Case3: 不必要的Node服務
var express = require("express");
var path = require('path');
var project = require('../project.config');
const app = express();
app.use('*', function (req, res) {
const file = path.resolve(project.basePath, project.outDir, 'index.html');
res.sendFile(file);
});
app.listen(process.env.PORT || 3000, function () {
console.log("Listening on port %d!", this.address().port);
});
如上,只是借用Node服務去render產出物,並未做其他任何請求處理,其實和case2,3沒有本質區別。
- Case4: 將Node服務作為API中間層
router.route('/articles/send')
.post(async (req, res) => {
const {params} = req.body;
const requestUrl = '/x/x/x/x';
const response = await requestArticle(requestUrl, params);
res.status(200).send(response).end();
});
這種情況下,Node服務就必須存在,因為很有可能真正的API處理方不支援跨域,或者有身份驗證,那麼就得在這裡去處理,生產環境自然也得有。
- Case5: Node端有完善的RESTful API
這種情況下,已經可以定義為一個前後端專案了,只是恰好前後端的語言一樣,並且可以共用大部分模組。
參考如上,你的專案,屬於哪種情況呢?
3.如何部署?
終於到了正題,其實部署無非就是執行環境(server)+資源(包),因此才需要搞清楚你的專案到底需不需要server?
,更確切的說是你的專案的生產環境到底需不需要server?
,從而決定如何部署。
- 對於case1,2,3:
可以選擇任意靜態伺服器,執行在生產環境,每次部署只需拉取最新的程式碼或生成最新的包。如果需要多機部署,則推薦docker的node或nginx映象,server只作一層簡單的router和render,並將最新的原始碼打包在內即可。
體總來說這種情況是最簡單的case,一個靜態伺服器就可以,想練手的可以利用Github Page去玩玩。
- 對於case4,5:
單機環境建議有部署指令碼(如ansible,去初始化各種環境依賴);多機部署則考慮node映象,每次部署時都把程式碼打進映象,並且設定啟動命令,最後的部署方式就是一鍵部署
。
BTW,對於這種case,如果部署時就是多機的情況,倒不如一勞永逸,開發環境直接用docker。但開發和生產還有點區別:建議開發時不要把原始碼打進映象,畢竟程式碼總是在變,可以將程式碼作為VOLUMN
每次載入上去,然後手動啟動,如下片段:
Dockerfile:
FROM node:7.2
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -
RUN echo "deb http://dl.yarnpkg.com/debian/ stable main" > /etc/apt/sources.list.d/yarn.list
RUN apt-get update && apt-get install yarn
WORKDIR /app
VOLUME /app
只依賴Node服務和yarn。
Run docker:
docker run --rm -v [your path]:/app -ti -p 3000:3000 image:version /bin/bash
只需將程式碼掛載上去即可,完全的環境程式碼分離模式。
4.寫在最後
說了這麼多,給想實踐的朋友推薦以下資源: