个人网站开发实践

必备:NodeJsNginx

使用Next.js

网站的开发采用 Next.js,Next.js 具有自动代码拆分、预渲染、基于文件系统路由等等便利于开发的特性 ☕

官方在 Github 上列出了许多例子 👉 example ,以 with-ant-design-less 为例,在 cmd 面板下运行以下命令

npm init next-app --example with-ant-design-less projectname
npm install
npm run dev

访问 http://localhost:3000,可以看到如下页面:

Welcome to Next.js 图片来自Next.js官网

使用nginx的gzip压缩功能

为了加快访问网站的速度,必须将网站的 js、css、html等文件尽量变得足够小,网络的传输才能足够快

首先使用 webpack 可视化分析插件: webpack-bundle-analyzer ,并且构建已有项目:npm run build
构建将产生的文件一一罗列并且生成依赖关系图,效果如下:

img

观察构建的文件大小,以 9c3bc3cde28db290887b7e6d1f1907160b18de5e.547bf9fb904ff2a9c3bc.js 为例,大小为 123.61kb,在网络传输中,100+kb算是可以接受的大小了,但幸运的是,还能做到更小!

img

nginx 提供了一个开箱即用的压缩功能 gzip,但默认情况下,gzip 设置是不开启的,在官网下载的 nginx 里,nginx.conf 文件会有这一行代码:

#gzip on;

此时对 gzip 功能不做任何变动,将构建好的静态项目放入 nginx 并且启动本地服务。打开网页,搜索文件名称 9c3bc3cde28db290887b7e6d1f1907160b18de5e.547bf9fb904ff2a9c3bc.js

img

可以看到文件传输的大小为:127kb (左下角 - transferred)

重新打开 nginx.conf 文件并且编辑如下内容:

#开启gzip压缩
gzip on;
#压缩级别1~9,值越大压缩越好,但耗费越多CPU资源
gzip_comp_level 1;
#文件大于1k才进行压缩
gzip_min_length 1k;
#gz后缀文件不压缩
gzip_static off;
#是否在http header中添加Vary: Accept-Encoding
gzip_vary on;
#指定压缩的文件类型
gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript;
#指定压缩缓冲大小
gzip_buffers 2 4k;

保存之后重新启动 nginx:nginx -s reload,再次访问网页

img

响应头增加了 Content-Encoding: gzip,文件也减小了,变成41.6kb!

使用nginx缓存

同样在 nginx.conf 文件里增加如下内容,重启 nginx

#图片缓存时间设置
location ~* \.(gif|jpg|jpeg|png|bmp|swf|ico)$ {
    expires 24h;
    add_header Cache-Control "public";
}
#JS和CSS缓存时间设置
location ~* \.(js|css)$ {
    expires 24h;
    add_header Cache-Control "public";
}

重新查看请求的响应头会多出一行指令: Cache-Control: max-age=86400,这可以告诉客户端将文件存到本地,在某段时间内(86400s)都将使用本地文件,而不是每次都去请求服务器。可减缓服务压力,同时提高页面响应速度

使用compression-webpack-plugin插件

Prepare compressed versions of assets to serve them with Content-Encoding.

该插件可将 webpack 构建生成的文件进行 gzip 压缩,生成对应的 gz 文件

例如 webpack 构建并且生成文件:

xxx.js - 80kb


使用了 compression-webpack-plugin 插件之后:

xxx.js - 80kb

xxx.js.gz - 3kb


该做法旨在提前将文件进行压缩,在推送到服务器之后可直接使用压缩好的 gz 文件,而不是使用服务器的 CPU 资源进行文件的压缩操作。要想 nginx 能够直接利用 gz 文件,需要开启 gzip_static 功能。

gzip_static on;

部署

采用 Jenkins 、Git、Docker 实现快速的版本迭代更新。

img

思路:

  1. 将本地开发的代码提交 github
  2. 启动 Jenkins 流水线
    1. 拉取最新代码:git pull
    2. 下载依赖: npm i
    3. 构建项目:npm run build
    4. 打包必要文件:nginx.conf、start.sh1 、Dockerfile、out2
  3. 将打包好的文件发布到 Cenos 服务器,执行 start.sh
  4. Docker 生成 nginx 镜像,根据镜像构建一个 Docker 容器,并将 nginx.conf、out 文件放入容器指定的位置

start.sh

#!/bin/bash
BASE_PATH=/kiyak/kiyak-web
SERVER_NAME=kiyak-web
KIYAK_CONTAINER=$(docker ps -a | grep "${SERVER_NAME}" | awk '{print $1}')
KIYAK_IMAGE=$(docker images | grep "${SERVER_NAME}" | awk '{print $3}')
KIYAK_NET_WORK=snail-net

# 构建docker镜像
if [ -n "$KIYAK_CONTAINER" ]
then
  echo "存在$SERVER_NAME容器,ID=$KIYAK_CONTAINER"
  echo "停止$SERVER_NAME容器,ID=$KIYAK_CONTAINER"
  docker stop $KIYAK_CONTAINER
  echo "删除$SERVER_NAME容器,ID=$KIYAK_CONTAINER"
  docker rm $KIYAK_CONTAINER
fi

if [ -n "$KIYAK_IMAGE" ]
then
  echo "存在$SERVER_NAME镜像,ID=$KIYAK_IMAGE"
  echo "删除$SERVER_NAME镜像,ID=$KIYAK_IMAGE"
  docker image rm $KIYAK_IMAGE
fi

cd $BASE_PATH
echo "创建$SERVER_NAME镜像......"
docker build -t $SERVER_NAME .
echo "启动$SERVER_NAME容器......"
docker run --name $SERVER_NAME -u root -p 80:80 -p 443:443 -v /etc/localtime:/etc/localtime:ro -v /kiyak/web-log:/etc/nginx/logs --network $KIYAK_NET_WORK -d $SERVER_NAME

# 清理文件
rm -rf $BASE_PATH/*

Dockerfile

FROM nginx
EXPOSE 80 443
ADD kiyak-web.tar.gz /etc/nginx/kiyak-web/
ADD cert.tar.gz /etc/nginx/
COPY nginx.conf /etc/nginx/nginx.conf

参考资料

  • Jeff Posnick, Ilya Grigorik, Prevent unnecessary network requests with the HTTP Cache, web.dev, 2020. 📄
  • Marc Novakowski, Oliver Weichhold, “ETag vs Header Expires”, Stack Overflow, 2014 📄

  1. Shell 脚本,主要集成操作 docker 的各种命令行
  2. webpack 构建生成的文件夹,里面包含项目的所有静态文件:js、css、html
· last updated: ·