[Implementación de front-end, parte 5] Uso de Docker para implementar la optimización de la configuración de nginx para aplicaciones de una sola página

¡Continúe creando, acelere el crecimiento! Este es el primer día de mi participación en el "Nuggets Daily New Plan · June Update Challenge", haz clic para ver los detalles del evento

Hola a todos, soy Shanyue, esta es mi columna recién abierta: Serie de implementación de front-end . Incluyendo Docker, CICD, etc., el esquema es el siguiente:

contorno

Además, Bilibili está actualizando videos relacionados, vea la versión de video de la serie de implementación frontal

La serie de implementación front-end se está actualizando : 5/15


En el último artículo, cubrimos la optimización del almacenamiento en caché con el almacenamiento en caché de compilaciones y las compilaciones de varias etapas en Docker.

Pero al implementar aplicaciones de una sola página, todavía hay un problema, y ​​es el enrutamiento del lado del cliente.

En este artículo, Docker react-router-domimplementará .

PD: este proyecto utiliza el almacén cra-deploy como práctica, y el archivo de configuración se encuentra en router.Dockerfile

enrutamiento

Úselo para agregar una ruta react-dompara una aplicación de una sola página. Dado que el enrutamiento no es el contenido principal de esta columna, se omite el uso de enrutamiento. El código final es el siguiente.

El código fuente se encuentra en cra-deploy/src/App.js

import logo from './logo.svg';
import './App.css';
import { Routes, Route, Link } from 'react-router-dom';

function Home() {
  return (
    <div>
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <h1>当前在 Home 页面</h1>
        <Link to="/about" className="App-link">About</Link>
      </header>
    </div>
  )
}

function About() {
  return (
    <div>
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <h1>当前在 About 页面</h1>
        <Link to="/" className="App-link">Home</Link>
      </header>
    </div>
  )
}

function App() {
  return (
    <div>
      <Routes>
        <Route index element={<Home />} />
        <Route path="about" element={<About />} />
      </Routes>
    </div>
  );
}

export default App;
复制代码

En este punto tienes dos rutas:

  1. /,página delantera
  2. /about, acerca de la página

Vuelva a implementar, hay un problema con el enrutamiento

Vuelva a implementar la página según el archivo de docker-composeconfiguración .

$ docker-compose up --build simple
复制代码

En este punto https://localhost:4000/about, se mostrará un 404.

404 No encontrado

其实道理很简单:在静态资源中并没有 about 或者 about.html 该资源,因此返回 404 Not Found。而在单页应用中,/about 是由前端通过 history API 进行控制。

解决方法也很简单:在服务端将所有页面路由均指向 index.html,而单页应用再通过 history API 控制当前路由显示哪个页面。 这也是静态资源服务器的重写(Rewrite)功能。

我们在使用 nginx 镜像部署前端应用时,可通过挂载 nginx 配置解决该问题。

nginx 的 try_files 指令

在 nginx 中,可通过 try_files 指令将所有页面导向 index.html

location / {
    # 如果资源不存在,则回退到 index.html
    try_files  $uri $uri/ /index.html;  
}
复制代码

此时,可解决服务器端路由问题。

除此之外,我们还可以通过 nginx 配置解决更多问题。

长期缓存 (Long Term Cache)

在 CRA 应用中,./build/static 目录均由 webpack 构建产生,资源路径将会带有 hash 值。

$ tree ./build/static
./build/static
├── css
│   ├── main.073c9b0a.css
│   └── main.073c9b0a.css.map
├── js
│   ├── 787.cf6a8955.chunk.js
│   ├── 787.cf6a8955.chunk.js.map
│   ├── main.a3facdf8.js
│   ├── main.a3facdf8.js.LICENSE.txt
│   └── main.a3facdf8.js.map
└── media
    └── logo.6ce24c58023cc2f8fd88fe9d219db6c6.svg

3 directories, 8 files
复制代码

此时可通过 expires 对它们配置一年的长期缓存,它实际上是配置了 Cache-Control: max-age=31536000 的响应头。

那为什么带有 hash 的资源可设置长期缓存呢: **资源的内容发生变更,他将会生成全新的 hash 值,即全新的资源路径。**而旧有资源将不会进行访问。

location /static {
    expires 1y;
}
复制代码

nginx 配置文件

总结缓存策略如下:

  1. 带有 hash 的资源一年长期缓存
  2. 非带 hash 的资源,需要配置 Cache-Control: no-cache,避免浏览器默认为强缓存

Control de caché

nginx.conf 文件需要维护在项目当中,经过路由问题的解决与缓存配置外,最终配置如下:

该 nginx 配置位于 cra-deploy/nginx.conf

server {
    listen       80;
    server_name  localhost;

    root   /usr/share/nginx/html;
    index  index.html index.htm;

    location / {
        # 解决单页应用服务端路由的问题
        try_files  $uri $uri/ /index.html;  

        # 非带 hash 的资源,需要配置 Cache-Control: no-cache,避免浏览器默认为强缓存
        expires -1;
    }

    location /static {
        # 带 hash 的资源,需要配置长期缓存
        expires 1y;
    }
}
复制代码

Dockerfile 配置文件

此时,在 Docker 部署过程中,需要将 nginx.conf 置于镜像中。

修改 router.Dockerfile 配置文件如下:

PS: 该 Dockerfile 配置位于 cra-deploy/router.Dockerfile

FROM node:14-alpine as builder

WORKDIR /code

# 单独分离 package.json,是为了 yarn 可最大限度利用缓存
ADD package.json yarn.lock /code/
RUN yarn

# 单独分离 public/src,是为了避免 ADD . /code 时,因为 Readme/nginx.conf 的更改避免缓存生效
# 也是为了 npm run build 可最大限度利用缓存
ADD public /code/public
ADD src /code/src
RUN npm run build

# 选择更小体积的基础镜像
FROM nginx:alpine
ADD nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=builder code/build /usr/share/nginx/html
复制代码

PS: 该 docker compose 配置位于 cra-deploy/router.Dockerfile

version: "3"
services:
  route:
    build:
      context: .
      dockerfile: router.Dockerfile
    ports:
      - 3000:80
复制代码

使用 docker-compose up --build route 启动容器。

  • 访问 http://localhost:3000 页面成功。
  • 访问 http://localhost:3000/about 页面成功。

检验长期缓存配置

访问 https://localhost:3000 页面,打开浏览器控制台网络面板。

此时对于带有 hash 资源, Cache-Control: max-age=31536000 响应头已配置。

此时对于非带 hash 资源, Cache-Control: no-cache 响应头已配置。

Ver la configuración del encabezado de respuesta

百尺竿头更进一步

在前端部署流程中,一些小小的配置能大幅度提升性能,列举一二,感兴趣的同学可进一步探索。

构建资源的优化:

  1. 使用 terser 压缩 Javascript 资源
  2. 使用 cssnano 压缩 CSS 资源
  3. 使用 sharp/CDN 压缩 Image 资源或转化为 Webp
  4. 使用 webpack 将小图片转化为 DataURI
  5. 使用 webpack 进行更精细的分包,避免一行代码的改动使大量文件的缓存失效

小结

其实,从这里开始,前端部署与传统前端部署已逐渐显现了天壤之别。

La implementación front-end tradicional está dominada por la operación y el mantenimiento. Cada vez que se conecta, notificará la operación y el mantenimiento de los pasos en línea del front-end del proyecto, que se completa con la operación y el mantenimiento, y el front-end tiene menos libertad para la implementación.

Por ejemplo, la apertura de la gzip/brotlicompresión , Cache-Controlel control de los encabezados de respuesta y la estrategia de almacenamiento en caché de diferentes rutas deben ser notificados de que la operación y el mantenimiento se han completado, y es difícil tener una gestión de versiones .

La extensión de la libertad de implementación de front-end se refleja en los siguientes dos aspectos:

  1. Contenga el front-end a través de Docker, ya no es necesario notificar los pasos de operación y mantenimiento en línea por correo electrónico
  2. Configure nginx en el front-end a través de los archivos de configuración de Docker y nginx, algunas configuraciones pequeñas y triviales que están fuertemente relacionadas con el proyecto no requieren intervención de operación y mantenimiento

En este punto, el capítulo sobre cómo implementar el front-end en Docker ha terminado y, en la práctica, los recursos estáticos a menudo se colocan en CDN.

Entonces, ¿cómo lidiar con eso?

Supongo que te gusta

Origin juejin.im/post/7102057861320015885
Recomendado
Clasificación