Как обрабатывать истекшие файлы без обновления браузера при использовании 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>