Как обрабатывать истекшие файлы без обновления браузера при использовании Single Page Application (SPA)?

Я сделал приложение Single Application Application (SPA) с помощью Angularjs.

Пока все хорошо.

Как известно, все файлы javascript загружаются в первый раз. Или, некоторые файлы загружаются в ленивом режиме, когда это необходимо.

До сих пор так хорошо...

Ситуация такова: сервер обновляет все файлы (html partials, javascripts, css), и клиент остается с большим количеством устаревших файлов.

Это будет просто решено обновить браузер, нажать клавишу F5, кнопку управления + f5 или кнопку обновления в браузере. Но эта концепция не существует при работе с SPA.

Я не уверен, как решить эту проблему.

Я мог бы как-то обнаружить (возможно, сделать ping) и просто перезагрузить этот конкретный файл. С помощью стратегии document.write. Но теперь возникает еще одна проблема: у меня есть один файл javascript со всеми javascript, которые были уменьшены.

Я мог бы попытаться полностью перезагрузить браузер или заставить повторно войти (и перезагрузить, потому что логин - часть SPA).

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

Я не уверен, как справиться с этим, если это возможно, с помощью angular.

Интересно, как Google Gmail справляется с этим, потому что я остаюсь включенным в течение многих часов без регистрации.

Ответы

Ответ 1

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

Я предлагаю использовать некоторый инструмент построения, например gulp, grunt или webpack, последний становится все более популярным.

К моменту использования gulp для моих проектов. Однако я перехожу к webpack.

если вас интересует gulp, вы можете посмотреть плагины gulp -rev и gulp -rev-replace.

Что они делают?

скажем, что у нас есть следующий файл в вашем проекте app.js то, что вы получаете после применения gulp -rev к вашему проекту, похоже на app-4j8888dp.js, тогда ваш html файл, в который вводится app.js, все еще указывая на app.js, поэтому вам нужно его заменить. Для этого вы можете использовать плагин gulp -rev-replace.

например. gulp задача, в которой

var gulp = require('gulp');
var rev = require('gulp-rev');
var revReplace = require('gulp-rev-replace');
var useref = require('gulp-useref');
var filter = require('gulp-filter');
var uglify = require('gulp-uglify');
var csso = require('gulp-csso');

gulp.task("index", function() {
  var jsFilter = filter("**/*.js", { restore: true });
  var cssFilter = filter("**/*.css", { restore: true });
  var indexHtmlFilter = filter(['**/*', '!**/index.html'], { restore: true });

  return gulp.src("src/index.html")
    .pipe(useref())      // Concatenate with gulp-useref
    .pipe(jsFilter)
    .pipe(uglify())             // Minify any javascript sources
    .pipe(jsFilter.restore)
    .pipe(cssFilter)
    .pipe(csso())               // Minify any CSS sources
    .pipe(cssFilter.restore)
    .pipe(indexHtmlFilter)
    .pipe(rev())                // Rename the concatenated files (but not index.html)
    .pipe(indexHtmlFilter.restore)
    .pipe(revReplace())         // Substitute in new filenames
    .pipe(gulp.dest('public'));
});

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

https://github.com/sindresorhus/gulp-rev https://github.com/jamesknelson/gulp-rev-replace

Ответ 2

Одностраничное приложение - это одиночный стек, который управляет клиентской логикой вашего приложения. Таким образом, любая навигация, выполняемая через приложение, должна обрабатываться вашим клиентом, а не сервером. Цель состоит в том, чтобы иметь один единственный "толстый" HTTP-запрос, который загружает все, что вам нужно, а затем выполняет небольшие HTTP-запросы.

Вот почему вы можете иметь только один ng-app в своих приложениях. Вы не должны иметь несколько и просто загружать модули, которые вам нужны (хотя команда AngularJS хочет двигаться таким образом). Во всех случаях вы должны обслуживать один и тот же файл с минимальными значениями и обрабатывать все из вашего приложения.

Мне кажется, что вас больше беспокоит состояние вашего приложения. Как сказал Том Дейл (EmberJS) в последнем матче Cage, мы должны стремиться иметь приложения, которые могут отражать одни и те же данные между сервером и клиентом в любой момент времени. У вас есть много способов сделать это, будь то файлы cookie, сеансы или локальное хранилище.

Обычно SPA связывается с сервером на основе REST и, следовательно, выполняет операции idempotent с вашими данными.

tl; dr Вы не должны обновлять что-либо с сервера (например, стили или сценарии), а только данные, которые обрабатывает ваше приложение. Первоначальная одиночная нагрузка - вот что такое SPA.

Ответ 3

отделяйте свои данные и логику и перезагружайте данные с помощью ajax всякий раз, когда захотите, потому что я предлагаю вам использовать REST API для получения данных с сервера.

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

Ответ 4

Ну, вам нужно будет выгрузить старый существующий код (т.е. старое приложение, модули, контроллеры, службы и приложение) AngularJS. Теоретически вы можете создать собственное (рандомизированное) имя приложения (со всеми модулями есть этот префикс для каждой уникальной сборки!), А затем перестроить ваше приложение в браузере. Но серьезно.. что а) очень сложный и б), вероятно, провалится утечка памяти.

Итак, мой ответ: Do not.

Проблемы кэширования

Я лично рекомендовал бы назвать/префикс всех ресурсов, зависящих от сборки, с уникальным идентификатором; либо идентификатор сборки, либо scm-хэш, временную метку, либо что-то в этом роде. Таким образом, URL-адрес javascript не domain.tld/resources/scripts.js, а domain.tld/resources-1234567890/scripts.js, который гарантирует, что этот контент пути никогда не будет конфликтовать с (более новой) версией. Вы можете выбрать свой путь /url, как вы хотите (в зависимости от структуры подкладки: все это практически, вы можете перенаправить URL-адреса, etcpp). Было бы даже не требоваться, чтобы каждая версия существовала навсегда (т.е. Отобразила все resources-(\d+)/ в resources/, однако это было бы неприемлемо для концепции URL-адресов.

Состояние приложения

Ну, вопрос в том, как часто будет изменяться приложение, что было бы важно, чтобы такие перезагрузки были необходимы. Как долго SPA открывается в браузере? Невозможно ли одновременно поддерживать две версии? Клиент (приложение в браузере) мог даже отправить свою собственную версию в HTTP-запросы.

В начале нового приложения есть много изменений, которые потребуют перезагрузки. Но вскоре после того, как ваше приложение будет иметь твердотельное состояние, изменения будут меньше и не потребуют перезагрузки. Сам пользователь сделает больше обновлений.. больше, чем мы ожидали:/

Ответ 5

Как и все остальные говорят...

Не делайте этого, и пока socket.io может работать с запросом на неприятности, если вы ОЧЕНЬ осторожны.

У вас есть два варианта: при обновлении сервера недействителен любой предыдущий сеанс (я бы также дал пользователям уведомление за полчаса или 5 минут в зависимости от приложения, прежде чем будет выполнено техническое обслуживание.

Второй вариант - это управление версиями. Если они находятся на версии 10, то они общаются с бэкэндом 10. Если вы отпустите версию 11, и они все еще на 10, то они все равно смогут общаться с бэкэнд файлом 10.

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

Ответ 6

используйте $state service. создать состояние во время загрузки страницы с помощью ctor. после указанного времени повторно создайте страницу состояния и загрузки.

function(state) {
  state.stateCtor(action);
  $state.transitionTo(action + '.detail', {}, {
    notify: true
  });
}

Ответ 7

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

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

Вы сделали пример с Gmail, но, возможно, заметили, что изменения в пользовательском интерфейсе всегда происходят после выхода из системы, никогда, пока вы его используете.

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

В противном случае, если вам нужно предоставить доступность 24/24, мое предложение:

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

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

  • Бэкэнд-услуги должны быть обратно совместимы со старой версией интерфейса. Если это невозможно, вы должны также хранить несколько версий бэкэнд-услуг.

Ответ 8

Версии ваших файлов, поэтому при каждом обновлении номера версии и браузера обновит его автоматически.

Ответ 9

Мое решение состоит из нескольких точек.

  • Хотя это не важно, но я отправляю один файл JavaScript на клиентскую сторону, я использую grunt для подготовки моей версии. Тот же файл grunt добавляет к тегу JavaScript запрос с номером версии. Независимо от того, есть ли у вас один файл или много файлов, вам нужно добавить к ним номер версии. Возможно, вам понадобится сделать это и для ресурсов. (проверьте в конце пример)

  • Я отправляю обратно во все свои ответы с сервера (я использую node) номер версии приложения.

  • В Angular, когда я получаю какой-либо ответ, я проверяю номер версии на загруженный номер версии, если он был изменен (это означает, что код сервера обновлен), тогда я предупреждаю пользователя о том, что приложение собирается перезагрузить. Я использую location.reload(true);

  • После перезагрузки браузер снова загрузит все новые файлы, поскольку номер версии в теге script теперь отличается от этого, и поэтому он не получит его из кеша.

Надеюсь, что это поможет.

<script src="/scripts/spa.min.js?v=0.1.1-1011"></script>