- Published on
前端项目应该如何部署
- Authors
- Name
- Pursue
一个标准的前端项目,必定始于 yarn start,它将会经历 babel 编译,webpack 构建,server 启动等流程,然后由浏览器加载页面。这是很 Dev 的开发方式,可生产环境我们却往往不这么做。
1.何为前端?
如果按照以前的看法,前后端最本质的区别当然是运行环境了,一个是浏览器中所写即所见
的 UI 界面,另一个则是藏在背后
的服务。
在这种简单的区分下,前端往往会被定义为HTML/CSS/Javascript
。没错,前端就是这些东西,这就是浏览器所需要呈现的;可也不能只有这些东西:前端有时也需要自己的后端server
来充当 API 的中间层,也需要数据存储(如localStorage, sessionStorage, indexedDB...)
,甚至 JS 也快支持多线程了。所以现今,绝对不能用语言运行时(别给我说 JS 只在浏览器内运行)或者某项技术(ESX 已经在草案了)来去定义前端。
个人认为,最简单的区别方法就是用 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.写在最后
说了这么多,给想实践的朋友推荐以下资源: