От автора: на прошлой неделе я закончил раздел слайдов для презентации на конференции Performance.Now(). В нем я рассмотрел шаблоны, которые позволяют браузеру как можно быстрее отображать страницу, включая код с исходным HTML, чтобы браузер имел все необходимое для начала такого процесса, как рендеринг страниц без дополнительных запросов.
Два доступных варианта — это встраивание и Server Push, но у каждого есть свои недостатки: вложение позволяет обойтись без кэширования файла для повторного использования, а Server Push все еще немного эксперименталty, и некоторые ошибки браузеров по-прежнему находятся в процессе исправления. Поскольку я готовился описать эти оговорки, я подумал: «Интересно, может ли новый Service Worker и Caching API использовать кэширование для встраивания кода». Как оказалось, могут!
Кэширование встроенного файла
Начнем с примера. Следующий фрагмент кода имеет элемент style, содержащий некоторые встроенные стили CSS. Я добавил атрибут ID в элемент style, так что его легко найти с помощью JavaScript. После элемента style небольшая часть JavaScript находит этот CSS и использует новый API Cache для хранения его в локальном кэше браузера (с типом контента text / css) для использования на других страницах.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<style id="css"> .header { background: #09878} h1 { font-size: 1.2em; col… } h2 { margin: 0; } … </style> <script> if( "caches" in window ){ var css = document.getElementById("css").innerHTML; if( caches ){ caches.open('static').then(function(cache) { cache.put("site.css", new Response( css, {headers: {'Content-Type': 'text/css'}} )); }); } } </script> |
После этого встроенный CSS будет храниться в файле с именем site.css в локальном кэше service worker. Но чтобы использовать этот файл на последующих страницах, нам нужно еще кое-что сделать.
Оформление с помощью Worker
Вы можете определить, работал ли Caches API выше с Service Workers. Хотя Caches близок к Service Workers, он на самом деле доступен в глобальном пространстве имен window, поэтому, в отличие от Workers, мы можем использовать Caches, имея доступ к контенту из DOM. Тем не менее, чтобы обеспечить, чтобы следующая страница на сайте получала этот локальный файл site.css, если браузер запрашивает его, все равно будет необходим Service Workers.
Вот общий сниппет Service Worker, который, возможно, уже запущен на вашем сайте: когда файл запрашивается браузером, Service Worker проверяет локальные кэши, прежде чем отправлять запросы в сеть. Когда этот Worker работает, любые будущие запросы к site.css найдут его в локальном кэше и это позволит обойтись без сетевых запросов.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
(function(){ 'use strict'; self.addEventListener('fetch', event => { let request = event.request; let url = new URL(request.url); // Ignore non-GET requests if (request.method === 'GET') { // try local cache first, then go to network event.respondWith( caches .match(request) .then(response => { return response || fetch(request); }) ); } }); })(); |
Теперь мы готовы обрабатывать запросы к site.css на последующих страницах сайта.
Здесь стоит отметить, что для того, чтобы действительно использовать эту модель в шаблонах сайта, на последующих страницах вместо вложения файлов нужно будет ссылаться на них во вне (используя ссылку на таблицу стилей, тег скрипта и т. д.). Чтобы реализовать это в HTML-шаблоне, мы часто устанавливаем файл cookie при первом посещении сайта. Затем, при последующих просмотрах страниц, сервер может проверить этот файл cookie, чтобы сделать предположение, что браузер уже имеет файлы, находящиеся в кэше. Если это так, он может ссылаться на файлы извне.
Концептуальная демо-версия
Чтобы продемонстрировать шаблон в действии, я создал простую демонстрационную страницу.
Вот как это работает: страница по ссылке ниже включает некоторые встроенные CSS и функцию кэширования, аналогичную приведенной выше. Она также устанавливает код service worker, чтобы при выполнении запросов проверять файлы в локальных кэшах. Эта первая демонстрационная страница содержит ссылку на вторую страницу, которая ссылается на site.css с использованием регулярного элемента <link rel=»stylesheet» href=»site.css»>. Если site.css загружен локально, что должно произойти в любом поддерживающем service worker браузере, вторая страница будет иметь зеленый фон. Если site.css загружен с сервера, фон будет красным.
Вы можете найти демо-версию здесь.
Дальнейшая оптимизация
Есть некоторые моменты, которые сразу приходят на ум, когда мы говорим о том, как улучшить приведенный выше пример.
Оптимизация для повторного использования
Одно из усовершенствований, которое мы можем выполнить — настроить скрипт для поиска нескольких встроенных элементов style и script с использованием общего селектора и применить к этим элементам специальные атрибуты, чтобы объявить их тип содержимого, имя и путь к файлу кэша для сохранения их содержимого. С помощью этих атрибутов скрипт может находить и кэшировать многие из встроенных файлов в один прием.
Это может выглядеть так:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
<style data-cache="static" data-type="text/css" data-path="/css/site.css"> body { background: green; color: #fff; } a { color: #fff; } </style> <script data-cache="static" data-type="text/javascript" data-path="/js/head.js"> alert( "This script ran from head.js, which was inlined and local." ); </script> <script> if( "caches" in window ){ function cacheFile( file ){ caches.open( file.filecache ).then(function( cache ) { cache.put( file.filepath, new Response( file.filetext, {headers: {'Content-Type': file.filetype }} )); }); } var toCache = document.querySelectorAll( "[data-cache]" ); for( var i = 0; i < toCache.length; i++ ){ var elem = toCache[ i ]; cacheFile({ filepath: elem.getAttribute( "data-path" ), filetype: elem.getAttribute( "data-type" ), filecache: elem.getAttribute( "data-cache" ), filetext: elem.innerHTML }); } } </script> |
А это вторая демо-версия, которая делает то, что мы рассмотрели выше, для CSS и Javascript (снова перейдите на вторую страницу, чтобы увидеть, как она работает).
Оптимизация подхода к критическому CSS
Мы могли бы также рассмотреть способы использования этого шаблона для улучшения существующих шаблонов критического CSS. Например, мы часто вставляем критический CSS страницы, а затем позже загружаем полный CSS сайта. В этом рабочем процессе полный CSS-файл обычно перекрывает многие правила CSS с помощью «критического» подмножества, которое мы уже доставляли. Лучшим подходом может быть загрузка полной версии CSS, которая вообще не содержит критических правил, а затем использовать Cache API для объединения критических и полных CSS-файлов для создания полной записи CSS сайта в локальном кэше.
Доставка всего сайта через HTML?
Если бы мы захотели это сделать, мы могли бы даже попытаться использовать этот шаблон для доставки всей front-end базы кода в одном HTML-ответе, имитируя причудливый формат веб-упаковки. Будет ли это хорошей идеей? Возможно нет! Но было бы интересно поэкспериментировать.
На данный момент мы будем проводить мозговой штурм по поводу других потенциальных возможностей использования… и, возможно, обновлять наш сайт! Спасибо за уделенное внимание.
Источник: //www.filamentgroup.com/
Редакция: Команда webformyself.