如何处理使用代码拆分的 Docker webpack 应用程序的新版本部署?

Dim*_*iwa 9 javascript docker webpack create-react-app webpack-splitchunks

在 Docker 中部署我的应用程序的新版本后,

我看到console以下错误会破坏我的应用程序

Uncaught SyntaxError: Unexpected token '<'
Run Code Online (Sandbox Code Playgroud)

webpack 块丢失时出错

在此屏幕截图中,缺少的源称为:10.bbfbcd9d.chunk.js,该文件的内容如下所示:

Uncaught SyntaxError: Unexpected token '<'
Run Code Online (Sandbox Code Playgroud)

发生此错误的原因是:

  1. 在每次发布时,我们都会构建一个包含最新版本块的新Docker镜像
  2. 一些客户端运行的是过时的版本,并且由于(1)服务器无法解析旧块

块是.js由 生成的文件,webpack有关详细信息,请参阅代码拆分

重新加载应用程序会将版本更新为最新版本,但对于使用过时版本的所有用户来说,它仍然会破坏应用程序。

我尝试过的一个可能的解决方法是刷新应用程序。如果请求的块在服务器上丢失,如果对.js文件的请求最终出现在通配符路由中,我将发送重新加载信号。

通配符服务于index.htmlWeb 应用程序,这用于在用户刷新其页面的情况下将路由委托给客户端路由

(this.webpackJsonp=this.webpackJsonp||[]).push([[10],{1062:function(e,t,n){"use strict";var r=n(182);n.d(t,"a",(function(){return r.a}))},1063:function(e,t,n){var ...{source:Z[De],resizeMode:"cover",style:[Y.fixed,{zIndex:-1}]})))}))}}]);
//# sourceMappingURL=10.859374a0.chunk.js.map
Run Code Online (Sandbox Code Playgroud)

这似乎是一个糟糕的修复,尤其是在 Android 版 Google Chrome 上,我看到我的应用程序在无限循环中刷新。(是的,这也是一个丑陋的修复!)

由于它对我的最终用户来说不是一个可靠的解决方案,如果用户客户端已过时,我正在寻找另一种方法来重新加载应用程序。

我的 Web 应用程序是使用 构建的webpack,就好像它是一个create-react-app应用程序一样,分布式构建目录包含许多.js块文件。

这些是我在 webpack 问题跟踪器上提供的一些可能的修复,有些是由 webpack 创建者本身提供的:

  • 不要删除旧版本。 <= 我正在构建一个 Docker 镜像,所以这有点挑战
  • 捕获import()错误并重新加载。您也可以通过在__webpack_load_chunk__某处打补丁来全局执行此操作。 <= 我没有得到那个补丁或在哪里使用import(),我不是自己生产这些块,它只是一个生产功能
  • 让服务器发送window.location.reload(true)不存在的 js 文件,但这是一个非常奇怪的 hack。 <= 它使我的应用程序在 chrome android 上循环重新加载
  • 不要为.js请求发送 HTML ,即使它们不存在,这只会导致奇怪的错误 <= 不能解决我的问题

相关问题

如何实施可以防止此错误的解决方案?

Igo*_*aev 5

如果我正确理解了这个问题,那么解决这个问题有几种方法,我将从最简单的到更复杂的列出它们:

使用以前的版本来构建新版本

这是迄今为止最简单的方法,只需要为新版本更改基础映像。

Dockerfile构建应用程序的版本 2 时请考虑以下事项:

FROM version1

RUN ...
Run Code Online (Sandbox Code Playgroud)

然后使用以下命令构建它:

docker build -t version2 .
Run Code Online (Sandbox Code Playgroud)

然而,这种方法有一个问题——所有旧的块都会累积在新的图像中。它可能是可取的,也可能是不可取的,但需要考虑。

另一个问题是您无法轻松更新基础映像。

使用多阶段构建

多阶段构建允许您运行多个阶段并将每个阶段的结果包含到最终图像中。每个阶段可能会使用不同的 Docker 映像和不同的工具,例如 GCC 来编译一些本机库,但您的最终映像中并不真正需要 GCC。

为了使其能够进行多阶段构建,您需要能够创建第一个图像。让我们考虑一下下面的内容Dockerfile,它正是这样做的:

FROM alpine

RUN mkdir -p /app/latest && touch /app/latest/$(cat /proc/sys/kernel/random/uuid).chunk.js
Run Code Online (Sandbox Code Playgroud)

它使用随机名称的新块创建一个新的 Docker 映像,并将其放入名为 的目录中latest- 这对于建议的方法很重要!

为了创建后续版本,我们需要一个Dockerfile.next如下所示的版本:

FROM version2 AS previous
RUN rm -rf /app/previous && mv /app/latest/ /app/previous

FROM alpine

COPY --from=previous /app /app
RUN mkdir -p /app/latest && touch /app/latest/$(cat /proc/sys/kernel/random/uuid).chunk.js
Run Code Online (Sandbox Code Playgroud)

在第一阶段,它通过删除版本previouslatest移至previous.

在第二阶段,它复制第一阶段中剩余的所有版本,创建一个新版本并将其放入latest.

使用方法如下:

FROM version1

RUN ...
Run Code Online (Sandbox Code Playgroud)

请注意块是如何从 移动latest到 的previous

此解决方案要求您的服务器能够发现不同目录中的静态文件,但这可能会使本地开发变得复杂,因为该逻辑可能是基于环境的条件。

或者,您可以在容器启动时将所有文件复制到一个目录中。这可以在 Docker 本身的脚本中或在您的服务器代码中完成ENTRYPOINT- 这完全取决于您,取决于哪种更方便。

此外,此示例仅查看一个版本,但可以通过更复杂的轮换脚本将其扩展到多个版本。例如,要保留 3 个最新版本,您可以执行以下操作:

RUN rm -rf /app/version-0; \
    [ -d /app/version-1 ] && mv /app/version-1 /app/version-0; \
    [ -d /app/version-2 ] && mv /app/version-2 /app/version-1; \
    mv /app/latest /app/version-2; 
Run Code Online (Sandbox Code Playgroud)

或者可以使用 Docker 对其进行参数化,ARG并指定要保留的版本数量。

您可以在官方文档中阅读有关多阶段构建的更多信息。