Как справиться с развертыванием новой версии для Docker приложения webpack, использующего разделение кода? - PullRequest
3 голосов
/ 28 апреля 2020

После развертывания новой версии моего приложения в Docker,

я вижу, что у моего console есть следующая ошибка, которая ломает мое приложение :

Uncaught SyntaxError: Unexpected token '<'

error when webpack chunk is missing

На этом снимке экрана отсутствует источник, который называется: 10.bbfbcd9d.chunk.js, содержимое этого файла выглядит следующим образом:

(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

Эта ошибка возникает из-за:

  1. В каждом выпуске мы создаем новый Docker образ, который только включает фрагменты из последней версии
  2. Некоторые клиенты используют устаревшую версию, и сервер не будет иметь разрешение для старого блока из-за (1)

Куски - это .js файл, созданный webpack, см. Разделение кода для , дополнительная информация

Перезагрузка приложения обновит версию до последней, но она по-прежнему нарушает работу приложения для всех пользователей, использующих устаревшую версию.

Возможное исправление I ha Я пытался обновить приложение. Если на сервере отсутствовал запрошенный фрагмент, я отправлял сигнал перезагрузки, если запрос файла .js оказался в маршруте с подстановочными знаками.

Подстановочный знак обслуживает index.html из веб-приложение, предназначенное для делегирования маршрутизации на клиентскую маршрутизацию в случае, если пользователь обновляет свою страницу

// Handles any requests that don't match the ones above
app.get('*', (req, res) => {
  // prevent old version to download a missing old chunk and force application reload
  if (req.url.slice(-3) === '.js') {
    return res.send(`window.location.reload(true)`);
  }
  return res.sendFile(join(__dirname, '../web-build/index.html'));
});

Это было плохое исправление, особенно в Google Chrome для Android Я видел, как мое приложение обновлялось в бесконечном количестве l oop. (И да, это тоже ужасное исправление!)

Поскольку это не надежное решение для моих конечных пользователей, я ищу другой способ перезагрузить приложение, если пользовательский клиент устарел.

Мое веб-приложение построено с использованием webpack, оно точно такое же, как если бы оно было create-react-app приложением, каталог распределенной сборки содержит множество .js файлов чанков.

Вот некоторые возможные исправления Мне предложили на трекере выпусков веб-пакетов , некоторые предлагались самим создателем веб-пакетов:

  • Не удалять старые сборки. <= Я построение Docker изображения, так что это немного сложнее </em>
  • перехватить import() ошибок и перезагрузить. Вы также можете сделать это глобально, исправив __webpack_load_chunk__ где-то. <= Я не получаю этот патч или где использовать <code>import(), я сам не производю эти куски, и это просто производственная функция
  • разрешить серверу отправлять window.location.reload(true) для несуществующих js файлов, но это действительно странный хак. <= это заставляет мое приложение перезагрузиться в l oop on chrome android</em>
  • Не отправлять HTML для .js запросов, даже если они не существуют, это приводит только к странным ошибкам <= это не решает мою проблему </em>

Связанные проблемы

Как реализовать решение, предотвращающее эту ошибку?

1 Ответ

1 голос
/ 08 мая 2020

Если я правильно понял проблему, то есть несколько подходов к этой проблеме, и я перечислю их от самого простого до более сложного:

Использование предыдущей версии для создания новой версии из

Это, безусловно, самый простой подход, который требует только изменения базового образа для вашей новой версии.

Рассмотрим следующее Dockerfile для создания версии 2 приложения:

FROM version1

RUN ...

Затем создайте его with:

docker build -t version2 .

Этот подход, однако, имеет проблему - все старые куски будут накапливаться в новых изображениях. Это может или не может быть желательно, но что-то нужно учитывать.

Другая проблема заключается в том, что вы не можете легко обновить базовый образ.

Использовать многоступенчатые сборки

Многоступенчатый сборки позволяют запускать несколько этапов и включать результаты каждого этапа в окончательное изображение. На каждом этапе могут использоваться различные Docker изображения с различными инструментами, например, G CC для компиляции некоторой нативной библиотеки, но вам на самом деле не нужно G CC в конечном изображении.

Для того, чтобы сделать это работает с многоступенчатой ​​сборкой, вам нужно будет иметь возможность создать самый первый образ. Давайте рассмотрим следующее Dockerfile, которое делает именно это:

FROM alpine

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

Создает новое новое изображение 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

На первом этапе он поворачивает версию, удаляя previous версия и перемещение latest в previous.

На втором этапе он копирует все версии, оставшиеся на первом этапе, создает новую версию и помещает ее в latest.

Вот как это использовать:

docker build -t image:1 -f Dockerfile .

>> /app/latest/99cfc0e6-3773-40a0-82d4-8c8643cc243b.chunk.js

docker build -t image:2 --build-arg PREVIOUS_VERSION=1 -f Dockerfile.next .

>> /app/previous/99cfc0e6-3773-40a0-82d4-8c8643cc243b.chunk.js
>> /app/latest/2adf34c3-c50c-446b-9e85-29fb32011463.chunk.js

docker build -t image:3 --build-arg PREVIOUS_VERSION=2 -f Dockerfile.next 

>> /app/previous/2adf34c3-c50c-446b-9e85-29fb32011463.chunk.js
>> /app/latest/2e1f8aea-36bb-4b9a-ba48-db88c175cd6b.chunk.js

docker build -t image:4 --build-arg PREVIOUS_VERSION=3 -f Dockerfile.next 

>> /app/previous/2e1f8aea-36bb-4b9a-ba48-db88c175cd6b.chunk.js
>> /app/latest/851dbbf2-1126-4a44-a734-d5e20ce05d86.chunk.js

Обратите внимание, как чанки перемещаются с latest на previous.

Это решение требует, чтобы ваш сервер мог обнаруживать данные c файлов в разных каталогах, но это может усложнить локальную разработку, хотя эта логика c может быть условной в зависимости от среды.

В качестве альтернативы вы можете скопировать все файлы в один каталог при обращении Инер начинается. Это можно сделать с помощью сценария ENTRYPOINT в самом Docker или в коде вашего сервера - это зависит только от вас, зависит от того, что удобнее.

Также в этом примере рассматривается только одна версия назад, но его можно масштабировать до нескольких версий с помощью более сложного сценария вращения. Например, чтобы сохранить 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; 

Или его можно параметризовать, используя Docker ARG с количеством сохраняемых версий.

Вы Подробнее о многоэтапных сборках можно прочитать в официальной документации .

...