Создание прогрессивного веб-приложения (PWA) с использованием HTML и Vanilla JavaScript
Создание прогрессивного веб-приложения (PWA) с использованием HTML и ванильного JavaScript с mp3-аудиоплеером может стать удивительным занятием.
Мы рассмотрим базовый пример того, как сервис-воркеры можно использовать для кэширования в PWA. Наше приложение представляет собой MP3-плеер, но приведенные здесь принципы применимы к любому PWA.
Manifest.json
Начнем с manifest.json
:
{
"short_name": "PWA MP3 Player",
"name": "Progressive Web Application MP3 Player",
"description": "An MP3 Player built as a Progressive Web Application",
"start_url": "/",
"display": "standalone",
"background_color": "#fff",
"theme_color": "#3f51b5",
"icons": [
{
"src": "icon.png",
"sizes": "192x192",
"type": "image/png"
}
]
}
Manifest.json предоставляет информацию о приложении (такую как название, автор, значок и описание) в текстовом файле JSON.
Цель файла manifest.json
- предоставить централизованное место для размещения метаданных, связанных с веб-приложением.
Вот разбивка каждого объекта недвижимости:
short_name
: Short_name — это более короткая версия имени приложения, которое используется на домашнем экране пользователя и везде, где место ограничено.name
: Полное имя приложения.description
: Описание приложения.start_url
: Это URL-адрес, с которого запустится PWA, когда пользователь запустит приложение. В этом случае он настроен на открытие домашней страницы приложения.display
: Свойство display определяет предпочтительный режим отображения веб-сайта разработчиком. Значение "standalone" означает, что приложение будет выглядеть и чувствовать себя как автономное приложение. Это может включать в себя приложение, имеющее другое окно, свой собственный значок в панели запуска приложений и т.д.background_color
: Это цвет фона приложения, который используется при отображении заставки при запуске приложения с плитки на главном экране.theme_color
: Определяет цвет темы по умолчанию для приложения, который влияет на цвет панели инструментов и цвет в переключателе задач.icons
: Это свойство представляет собой массив файлов изображений, которые можно использовать в качестве значка приложения. Каждый объект в массиве является изображением, и вы можете указать путь, размеры и тип изображения. Ключsrc
- это путь к файлу изображения, ключsizes
- это разделенный пробелами список размеров изображения, а ключtype
- это MIME-тип для файла изображения.
Таким образом, файл manifest.json
- это файл конфигурации для вашего PWA, который содержит подробную информацию о том, как должно вести себя ваше приложение при установке на устройство.
Сервис Worker
Далее, давайте настроим базового сервисного работника (sw.js
):
const cacheName = 'pwa-mp3-player-v1';
const assetsToCache = [
'./',
'index.html',
'main.js',
'styles.css',
'icon.png'
];
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(cacheName)
.then((cache) => {
return cache.addAll(assetsToCache);
})
);
});
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request)
.then((response) => {
return response || fetch(event.request);
})
);
});
Когда мы говорим о прогрессивных веб-приложениях (PWA), часто появляется термин «Service Workers». Service Workers, настоящая движущая сила PWA, выполняют различные важные функции, одной из наиболее важных из которых является обработка стратегий кэширования.
Давайте разберем этот фрагмент кода JavaScript:
const cacheName = 'pwa-mp3-player-v1';
Здесь мы объявляем константу cacheName
для обозначения версии нашего кеша. Версии наших кэшей — обычная практика, потому что это упрощает управление ими. Если мы обновляем какие-либо файлы в нашем проекте, мы можем изменить имя кеша, что затем заставит сервис-воркера кэшировать новые файлы.
const assetsToCache = [
'./',
'index.html',
'main.js',
'styles.css',
'icon.png'
];
В assetsToCache
мы перечисляем файлы, которые хотим кэшировать. Обычно это включает в себя все статические файлы, необходимые для оболочки вашего приложения (минимальный HTML, CSS и JavaScript, необходимый для работы пользовательского интерфейса прогрессивного веб-приложения).
В части self.addEventListener
происходит волшебство. Service Workers могут прослушивать несколько событий жизненного цикла. Двумя наиболее часто используемыми являются «install» и «fetch».
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(cacheName)
.then((cache) => {
return cache.addAll(assetsToCache);
})
);
});
Событие install
срабатывает при первой установке сервисного работника. Здесь мы говорим сервис-воркеру открыть кэш с помощью caches.open()
, а затем кэшировать все необходимые активы с помощью cache.addAll()
. event.waitUntil()
используется для гарантии того, что сервис-воркер не прекратит установку до тех пор, пока код внутри waitUntil
не завершится.
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request)
.then((response) => {
return response || fetch(event.request);
})
);
});
После процесса установки и кэширования событие fetch
срабатывает всякий раз, когда запрашивается любой ресурс (указанный в assetsToCache
). Метод event.respondWith()
позволяет нам перехватить запрос и предоставить ответ.
Внутри responseWith
мы спрашиваем кеш, есть ли там запрошенный ресурс. Если да (caches.match(event.request
) возвращает ответ, мы отвечаем кешированной версией, если нет, мы получаем ее из сети, используя fetch(event.request)
.
Эту стратегию часто называют Cache Falling Back to Network. Идея состоит в том, чтобы вернуть кешированный контент, когда он доступен, в противном случае вернуться к сетевому запросу.
Это может обеспечить скорость, если содержимое кэшируется, и доступность, если нет.
Большие возможности
Это только верхушка айсберга, когда речь заходит о service worker и их возможностях.
Вы можете настроить более сложные стратегии кэширования, обрабатывать почтовые запросы, фоновую синхронизацию и многое другое. service worker — это мощный инструмент в современной веб-разработке, обеспечивающий функции, подобные приложениям, в браузере.
Работает на JavaScript
Теперь давайте создадим простой аудиоплеер (main.js
):
class AudioPlayer {
constructor(audioElement) {
this.audioElement = document.querySelector(audioElement);
}
play() {
this.audioElement.play();
}
pause() {
this.audioElement.pause();
}
togglePlay() {
this.audioElement.paused ? this.play() : this.pause();
}
}
document.addEventListener('DOMContentLoaded', () => {
const player = new AudioPlayer('#audioElement');
document.querySelector('#playButton').addEventListener('click', () => {
player.togglePlay();
});
});
Давайте проанализируем это и поймем, как мы можем использовать возможности объектно-ориентированного программирования на JavaScript для создания интерактивных веб-компонентов.
class AudioPlayer {
constructor(audioElement) {
this.audioElement = document.querySelector(audioElement);
}
В начале мы определяем класс с именем AudioPlayer
. Классы — это схема создания объектов с определенными методами и свойствами в JavaScript. Наш класс AudioPlayer
принимает параметр audioElement
в своем конструкторе. Этот параметр должен быть селектором аудиоэлемента HTML, которым должен управлять проигрыватель. Он использует document.querySelector
для получения первого HTML-элемента, соответствующего этому селектору, и присваивает его this.audioElement
.
play() {
this.audioElement.play();
}
pause() {
this.audioElement.pause();
}
Затем мы определяем два метода play
и pause
внутри класса. Эти методы, при вызове, используют встроенные методы play
и pause
в HTMLAudioElement
для управления воспроизведением.
togglePlay() {
this.audioElement.paused ? this.play() : this.pause();
}
}
Далее у нас есть метод togglePlay
. Это проверяет, приостановлен ли звук в данный момент (свойство paused
имеет значение true
, когда звук не воспроизводится). Если он приостановлен, он вызывает метод play
, а если он воспроизводится, он вызывает метод pause
. Это простой способ переключаться между воспроизведением и паузой с помощью одной функции.
document.addEventListener('DOMContentLoaded', () => {
const player = new AudioPlayer('#audioElement');
document.querySelector('#playButton').addEventListener('click', () => {
player.togglePlay();
});
});
Наконец, вне класса у нас есть код, который использует наш AudioPlayer
. Во-первых, мы ждем события DOMContentLoaded
, чтобы убедиться, что наш HTML полностью загружен, прежде чем мы попытаемся взаимодействовать с ним.
Затем мы создаем новый экземпляр нашего класса AudioPlayer
, передавая селектор для нашего аудиоэлемента.
Мы также добавляем прослушиватель событий к кнопке воспроизведения (#playButton
). Когда кнопка нажата, метод togglePlay
вызывается для нашего экземпляра аудиоплеера.
Это позволяет нам запускать или приостанавливать воспроизведение звука, нажав кнопку.
Передовая практика
Этот пример является прекрасной иллюстрацией того, как мы можем создавать повторно используемый, организованный код в JavaScript, используя классы. Класс AudioPlayer
абстрагируется от деталей того, как воспроизводить, приостанавливать и переключать звук, предоставляя простой в использовании интерфейс, который мы можем использовать в нашем приложении.
Это позволяет нам сделать наш код более модульным, ремонтопригодным и управляемым.
Важная заметка
Пожалуйста, обратите внимание, что service workers и Cache API работают только по протоколу HTTPS или localhost по соображениям безопасности. Если вы разрабатываете локально, это должно сработать, но как только вы будете готовы к развертыванию, вам нужно будет убедиться, что ваш сервер использует HTTPS.
HTML загружает все
Вот базовый файл index.html
, который работает с предоставленным вами кодом JavaScript:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PWA MP3 Player</title>
<link rel="manifest" href="manifest.json">
<style>
/* Add your CSS styles here */
</style>
</head>
<body>
<div class="player">
<audio id="audioElement" src="song.mp3" controls></audio>
<button id="playButton">Play/Pause</button>
</div>
<script src="main.js"></script>
<script>
if ('serviceWorker' in navigator) {
window.addEventListener('load', function() {
navigator.serviceWorker.register('/sw.js').then(function(registration) {
console.log('ServiceWorker registration successful with scope: ', registration.scope);
}, function(err) {
console.log('ServiceWorker registration failed: ', err);
});
});
}
</script>
</body>
</html>
В этом HTML-файле:
- У нас есть тег
<audio>
сid="audioElement"
. Это аудиоплеер, которым будет управлять классAudioPlayer
. Атрибутsrc
должен быть путем к вашему mp3 файлу. - У нас есть
<button>
сid="playButton"
. Когда эта кнопка нажата, она вызывает методtogglePlay
для экземпляраAudioPlayer
, запуская или приостанавливая воспроизведение звука. - Мы включаем файл
main.js
, содержащий классAudioPlayer
. - У нас также есть скрипт для регистрации нашего service worker (
sw.js
), если браузер его поддерживает. Сервисный работник будет контролировать сетевые запросы, чтобы обеспечить бесперебойную работу в автономном режиме.
Занимаясь разработкой приложений, вы часто сталкиваетесь с такой задачей, как увеличить границы использования вашего приложения. Предлагаем вам изучить статью об использовании нескольких языков в вашем приложении. Тем самым вы увеличите возможности расширения вашего приложения и это может быть выгодно пользователю. Спасибо за внимание.