前端部署发展史
前端一说起刀耕火种,那肯定紧随着前端工程化这一话题。随着 react/vue/angular,es6+,webpack,babel,typescript 以及 node 的发展,前端已经在逐渐替代过去 script 引 cdn 开发的方式了,掀起了工程化这一大浪潮。得益于工程化的发展与开源社区的良好生态,前端应用的可用性与效率得到了很大提高。
前端以前是刀耕火种,那前端应用部署在以前也是刀耕火种。那前端应用部署的发展得益于什么,随前端工程化带来的副产品?
这只是一部分,而更重要的原因是 devops的崛起。
为了更清晰地理解前端部署的发展史,了解部署时运维和前端(或者更广泛地说,业务开发人员)的职责划分,当每次前端部署发生改变时,可以思考两个问题
缓存,前端应用中http 的 response header 由谁来配?得益于工程化发展,可以对打包后得到带有 hash 值的文件可以做永久缓存
跨域,/api 的代理配置由谁来配?在开发环境前端可以开个小服务,启用 webpack-dev-server 配置跨域,那生产环境呢
这两个问题都是前端面试时的高频问题,但话语权是否掌握在前端手里
时间来到 React 刚刚发展起来的这一年,这时已经使用 React 开发应用,使用 webpack 来打包。但是前端部署,仍是刀耕火种
原文地址: 前端部署演化史
系列文章: 个人服务器运维指南
如果本篇文章能够对你有所帮助,可以帮我在 shfshanyue/op-note 上点个 star
如果你是新人的话,目前在阿里云买机器会有优惠,可以点击 链接 购买。你可以跟着我的笔记 服务器运维指南 来开始维护服务器并搭建应用。
邀请你一起 86元/年 购买云服务器
刀耕火种
一台跳板机
一台生产环境服务器
一份部署脚本
前端调着他的 webpack,开心地给运维发了部署邮件并附了一份部署脚本,想着第一次不用套后端的模板,第一次前端可以独立部署。想着自己基础盘进一步扩大,前端不禁开心地笑了
运维照着着前端发过来的部署邮件,一遍又一遍地拉着代码,改着配置,写着 try_files, 配着 proxy_pass。
这时候,前端静态文件由 nginx 托管,nginx 配置文件大致长这个样子
server { listen 80; server_name shanyue.tech; location / { # 避免非root路径404 try_files $uri $uri/ /index.html; } # 解决跨域 location /api { proxy_pass http://api.shanyue.tech; } # 为带 hash 值的文件配置永久缓存 location ~* \.(?:css|js)$ { try_files $uri =404; expires 1y; add_header Cache-Control "public"; } location ~ ^.+\..+$ { try_files $uri =404; } }
不过...经常有时候跑不起来
运维抱怨着前端的部署脚本没有标好 node版本,前端嚷嚷着测试环境没问题
这个时候运维需要费很多心力放在部署上,甚至测试环境的部署上,前端也要费很多心力放在运维如何部署上。这个时候由于怕影响线上环境,上线往往选择在深夜,前端和运维身心俱疲
不过向来如此
鲁迅说,向来如此,那便对么。
这个时候,无论跨域的配置还是缓存的配置,都是运维来管理,运维不懂前端。但配置方式却是前端在提供,而前端并不熟悉 nginx
使用 docker 构建镜像
docker 的引进,很大程度地解决了部署脚本跑不了这个大BUG。dockerfile 即部署脚本,部署脚本即 dockerfile。这也很大程度缓解了前端与运维的摩擦,毕竟前端越来越靠谱了,至少部署脚本没有问题了 (笑
这时候,前端不再提供静态资源,而是提供服务,一个 http 服务
前端写的 dockerfile 大致长这个样子
FROM node:alpine # 代表生产环境 ENV PROJECT_ENV production # 许多 package 会根据此环境变量,做出不同的行为 # 另外,在 webpack 中打包也会根据此环境变量做出优化,但是 create-react-app 在打包时会写死该环境变量 ENV NODE_ENV production WORKDIR /code ADD . /code RUN npm install && npm run build && npm install -g http-server EXPOSE 80 CMD http-server ./public -p 80
单单有 dockerfile 也跑不起来,另外前端也开始维护一个 docker-compose.yaml,交给运维执行命令 docker-compose up -d 启动前端应用。前端第一次写 dockerfile 与 docker-compose.yaml,在部署流程中扮演的角色越来越重要。想着自己基础盘进一步扩大,前端又不禁开心地笑了
version: "3" services: shici: build: . expose: - 80
运维的 nginx 配置文件大致长这个样子
server { listen 80; server_name shanyue.tech; location / { proxy_pass http://static.shanyue.tech; } location /api { proxy_pass http://api.shanyue.tech; } }
运维除了配置 nginx 之外,还要执行一个命令: docker-compose up -d
这时候再思考文章最前面两个问题
缓存,由于从静态文件转换为服务,缓存开始交由前端控制 (但是镜像中的 http-server 不太适合做这件事情)
跨域,跨域仍由运维在 nginx 中配置
前端可以做他应该做的事情中的一部分了,这是一件令人开心的事情
当然,前端对于 dockerfile 的改进也是一个慢慢演进的过程,那这个时候镜像有什么问题呢?
构建镜像体积过大
构建镜像时间过长
使用多阶段构建优化镜像
这中间其实经历了不少坎坷,其中过程如何,详见我的另一篇文章: 如何使用 docker 部署前端应用。
其中主要的优化也是在上述所提到的两个方面
构建镜像体积由 1G+ 变为 10M+
构建镜像时间由 5min+ 变为 1min (视项目复杂程度,大部分时间在构建时间与上传静态资源时间)
FROM node:alpine as builder ENV PROJECT_ENV production ENV NODE_ENV production WORKDIR /code ADD package.json /code RUN npm install --production ADD . /code # npm run uploadCdn 是把静态资源上传至 oss 上的脚本文件,将来会使用 cdn 对 oss 加速 RUN npm run build && npm run uploadCdn # 选择更小体积的基础镜像 FROM nginx:alpine COPY --from=builder code/public/index.html code/public/favicon.ico /usr/share/nginx/html/ COPY --from=builder code/public/static /usr/share/nginx/html/static
那它怎么做的
先 ADD package.json /code, 再 npm install --production 之后 Add 所有文件。充分利用镜像缓存,减少构建时间
多阶段构建,大大减小镜像体积
另外还可以有一些小优化,如
npm cache 的基础镜像或者 npm 私有仓库,减少 npm install 时间,减小构建时间
npm install --production 只装必要的包
前端看着自己优化的 dockerfile,想着前几天还被运维吵,说什么磁盘一半的空间都被前端的镜像给占了,想着自己节省了前端镜像几个数量级的体积,为公司好像省了不少服务器的开销,想着自己的基础盘进一步扩大,又不禁开心的笑了
这时候再思考文章最前面两个问题
缓存,缓存由前端控制,缓存在oss上设置,将会使用 cdn 对 oss 加速。此时缓存由前端写脚本控制
跨域,跨域仍由运维在 nginx 中配置
CI/CD 与 gitlab
此时前端成就感爆棚,运维呢?运维还在一遍一遍地上线,重复着一遍又一遍的三个动作用来部署
拉代码
docker-compose up -d
重启 nginx
运维觉得再也不能这么下去了,于是他引进了 CI: 与现有代码仓库 gitlab 配套的 gitlab ci
CI,Continuous Integration,持续集成
CD,Continuous Delivery,持续交付
重要的不是 CI/CD 是什么,重要的是现在运维不用跟着业务上线走了,不需要一直盯着前端部署了。这些都是 CI/CD 的事情了,它被用来做自动化部署。上述提到的三件事交给了 CI/CD
.gitlab-ci.yml 是 gitlab 的 CI 配置文件,它大概长这个样子
deploy: stage: deploy only: - master script: - docker-compose up --build -d tags: - shell
CI/CD 不仅仅更解放了业务项目的部署,也在交付之前大大加强了业务代码的质量,它可以用来 lint,test,package安全检查,甚至多特性多环境部署,我将会在我以后的文章写这部分事情
我的一个服务器渲染项目 shfshanyue/shici以前在我的服务器中就是以 docker/docker-compose/gitlab-ci 的方式部署,有兴趣的可以看看它的配置文件
shfshanyue/shici:Dockerfile
shfshanyue/shici:docker-compose.yml
shfshanyue/shici:gitlab-ci.yml
如果你有个人服务器的话,也建议你做一个自己感兴趣的前