- PVSM.RU - https://www.pvsm.ru -
От переводчика: Это восьмая статья из цикла о Node.js [1] от команды Mozilla Identity, которая занимается проектом Persona [2].
Connect-fonts [10] — это middleware для Connect, которое улучшает производительность @font-face
, раздавая клиентам подобранные специально для их языка подмножества шрифтов, уменьшая тем самым их размер. Connect-fonts также генерирует специфические для локали и браузера стили @font-face
и CORS-заголовки для Firefox и IE9+. Для раздачи подмножеств шрифтов создаются так называемые font packs — поддиректории с подмножествами шрифтов плюс простой конфигурационный файл JSON. Некоторые наборы распространённых open source-шрифтов доступны в готовом виде в пакете npm [11], впрочем, создавать свои пакеты совсем нетрудно.
Если вы не слишком хорошо ориентируетесь в работе со шрифтами в интернете, мы собрали небольшую коллекцию [12] ссылок по теме @font-face
. [От переводчика: а на Хабре очень кстати статья [13], посвящённая производительности веб-шрифтов]
Когда вы просто отдаёте один большой шрифтовой файл всем пользователям, всё довольно просто:
@font-face
в вашем файле CSS;Это несложные шаги. Первые два можно сделать ещё легче с помощью, например, FontSquirrel [14] — онлайн генератора шрифтов, который автоматически создаст файлы шрифтов и код CSS. Для добавления заголовков CORS придётся почитать документацию Apache или Nginx, но и это не слишком трудно.
Но если вы хотите использовать все преимущества подмножеств шрифтов, всё усложняется. Вам нужны будут отдельные файлы шрифтов для каждой локали, и будет нужно динамически менять декларации @font-face
, чтобы они указывали на правильные URL. Так же придётся разбираться и с CORS. Именно эти проблемы решает connect-fonts.
По умолчанию, каждый шрифт содержит множество символов — латиницу, диакритические знаки для таких языков как французский или немецкий, дополнительные алфавиты, такие как греческий или кириллица. Многие шрифты также содержат символы, особенно если поддерживают Юникод (например, символ снеговика — ☃ [15]). Есть и шрифты с поддержкой иероглифов. Всё это содержится в файле шрифта, чтобы он был полезен максимально широкой аудитории. Такая гибкость ведёт к большим размерам файлов. Microsoft Arial Unicode, который содержит все символы Uncode 2.1, весит невероятные 22 мегабайта!
В то же время типичная веб-страница использует щрифт для одной конкретной задачи — отображения контента, обычно на одном языке и без экзотических символов. Ограничивая шрифт этим небольшим подмножеством, мы можем очень сильно сэкономить.
Давайте сравним размеры полных файлов распространённых шрифтов с подмножествами для нескольких локалей. Даже если ваш сайт работает только на английском языке, вы можете очень сильно сэкономить, выдавая локализованное подмножество.
Меньший размер файлов шрифтов означает более быструю загрузку и появление шрифтов на экране. Это особенно важно для мобильных устройств. Если пользователю доведётся зайти на сайт через 2G-соединение, уменьшение веса страницы на 50 килобайт может ускорить загрузку на 2-3 секунды. Ещё один момент — кеш в мобильных устройствах часто невелик, и у маленького шрифта больше шансов в нём задержаться.
Сравнение размеров полного шрифта Open Sans Regular с подмножествами для разных локалей:
То же самое в сжатом gzip виде:
Даже с учётом сжатия можно уменьшить размер шрифта на 80%, с 63 до 13 килобайт, в случае использования только английского подмножества Open Sans. И это только один шрифт — большинство сайтов используют несколько. Огромный потенциал для оптимизации!
Используя connect-fonts, мы в Mozilla Persona добились уменьшения на 85%, c 300 до 45 килобайт. Это эквивалентно паре секунд времени загрузки на типичном 3G-соединении и десятку секунд на 2G.
Если вы хотите избавиться от каждого лишнего байта, можно настроить connect-fonts так, чтобы он возвращал CSS не в виде файла, а виде строки, которую можно будет включить в общий файл. Кроме того, connect-fonts по умолчанию генерирует минимальную декларацию @font-face
, не включая в неё файлы в форматах, которые не принимает конкретный браузер.
Предположим, что у нас есть простое приложение на Express, которое сообщает клиенту текущее время:
// app.js
const
ejs = require('ejs'),
express = require('express'),
fs = require('fs');
var app = express.createServer(),
tpl = fs.readFileSync(__dirname, '/tpl.ejs', 'utf8');
app.get('/time', function(req, res) {
var output = ejs.render(tpl, {
currentTime: new Date()
});
res.send(output);
});
app.listen(8765, '127.0.0.1');
используя самый примитивный шаблон:
// tpl.ejs
<!doctype html>
<p>the time is <%= currentTime %>
Подключим connect-fonts, чтобы отдавать локализованное подмножество Open Sans — одного из нескольких включённых в пакеты готовых наборов.
Сначала установим нужные пакеты:
$ npm install connect-fonts
$ npm install connect-fonts-opensans
Подключим middleware:
// app.js с изменениями для использования connect-fonts
const
ejs = require('ejs'),
express = require('express'),
fs = require('fs'),
// добавлено:
connect_fonts = require('connect-fonts'),
opensans = require('connect-fonts-opensans');
var app = express.createServer(),
tpl = fs.readFileSync(__dirname, '/tpl.ejs', 'utf8');
Инициализируем модуль:
// продолжение app.js
// добавим этот вызов app.use:
app.use(connect_fonts.setup({
fonts: [opensans],
allow_origin: 'http://localhost:8765'
})
connect_fonts.setup()
принимает следующие аргументы:
fonts
— массив необходимых шрифтовallow_origin
— источник, из которого берём шрифты; connect-fonts использует эту информацию для установки заголовка Access-Control-Allow-Origin
для браузеров Firefox 3.5+ и IE9+.ua
(необязательный) — список user-agents, которым мы отдаём шрифты. По умолчанию connect-fonts определяет user-agent по запросу, самостоятельно решая, какие форматы файлов ключить в декларацию. Это поведение может быть изменено, если передать ua: 'all'
— тогда будут включены все имеющиеся форматы.Внутри маршрута нужно передать локаль в шаблон:
// продолжение app.js
app.get('/time', function(req, res) {
var output = ejs.render(tpl, {
// передаём локаль в шаблон:
userLocale: detectLocale(req),
currentTime: new Date()
});
res.send(output);
});
Для определения локали Mozilla Persona использует i18n-abide [16]. Есть ещё очень неплохой модуль locale [17], оба они доступны через npm. Но, чтобы не сложнять пример, мы просто возьмем первые два символа из поля запроса Accept-language
:
// примитивное определение локали
function detectLocale(req) {
return req.headers['accept-language'].slice(0,2);
}
app.listen(8765, '127.0.0.1');
// конец app.js
Теперь нужно обновить шаблон. Connect-fonts предполагает, что маршруты прописаны в виде:
/:locale/:font-list/fonts.css
например:
/fr/opensans-regular,opensans-italics/fonts.css
В нашем случае надо добавить ссылку на файл стилей по тому пути, который ожидает connect-fonts:
// tpl.ejs - изменения для connect-fonts
<!doctype html>
<link href="/<%= userLocale %>/opensans-regular/fonts.css" rel="stylesheet">
и добавить в код страницы стиль для использования шрифта:
// продолжение tpl.ejs
<style>
body { font-family: "Open Sans", "sans-serif"; }
</style>
<p>the time is <%= currentTime %>
Вот и всё. CSS, созданный connect-fonts, зависит от локали пользователя и его браузера. Вот пример для английской локали:
* это пример вывода при свойстве ua установленном в 'all' */
@font-face {
font-family: 'Open Sans';
font-style: normal;
font-weight: 400;
src: url('/fonts/en/opensans-regular.eot');
src: local('Open Sans'),
local('OpenSans'),
url('/fonts/en/opensans-regular.eot#') format('embedded-opentype'),
url('/fonts/en/opensans-regular.woff') format('woff'),
url('/fonts/en/opensans-regular.ttf') format('truetype'),
url('/fonts/en/opensans-regular.svg#Open Sans') format('svg');
}
Если вы хотите сэкономить один HTTP запрос, вы можете использовать метод connect_fonts.generate_css()
, чтобы получать код CSS в виде строки, и включить её в общий файл CSS.
Теперь наше маленькое приложение красиво показывает время. Его полный исходный код доступен на Гитхабе. Мы использовали готовый font pack, но создать собственный совсем не трудно. Инструкция [18] есть в readme.
Подмножества могут дать очень большой выигрыш в производительности для сайтов, которые используют веб-шрифты. connect-fonts делает немало работы со шрифтами в многоязычном приложении. Даже если ваш сайт подерживает только один язык, вы всё равно можете использовать этот модуль чтобы урезать шрифты до единственной необходимой вам локали и автоматически генрировать CSS и заголовки CORS, плюс это облегчит последующую интернационализацию.
Дальнейшие оптимизации могут состоять в исключении хинтинга для платформ, которые его не поддерживают (всех кроме Windows), автоматическом сжатии шрифтов и установке заголовков для кеширования.
Автор: ilya42
Источник [19]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/node-js/45570
Ссылки в тексте:
[1] цикла о Node.js: https://hacks.mozilla.org/category/a-node-js-holiday-season/
[2] Persona: http://ru.wikipedia.org/wiki/Mozilla_Persona
[3] Охотимся за утечками памяти в Node.js: http://habrahabr.ru/company/nordavind/blog/195494/
[4] Нагружаем Node под завязку: http://habrahabr.ru/company/nordavind/blog/195686/
[5] Храним сессии на клиенте, чтобы упростить масштабирование приложения: http://habrahabr.ru/company/nordavind/blog/196018/
[6] Производительность фронтэнда. Часть 1 — конкатенация, компрессия, кэширование: http://habrahabr.ru/company/nordavind/blog/196358/
[7] Пишем сервер, который не падает под нагрузкой: http://habrahabr.ru/company/nordavind/blog/196518/
[8] Производительность фронтэнда. Часть 2 — кешируем динамический контент с помощью etagify: http://habrahabr.ru/company/nordavind/blog/196818/
[9] Приручаем конфигурации веб-приложений с помощью node-convict: http://habrahabr.ru/company/nordavind/blog/197166/
[10] Connect-fonts: https://github.com/shane-tomlinson/connect-fonts
[11] пакете npm: https://npmjs.org/browse/keyword/connect-fonts
[12] небольшую коллекцию: https://gist.github.com/6a68/5187976
[13] статья: http://habrahabr.ru/post/159907/
[14] FontSquirrel: http://www.fontsquirrel.com/tools/webfont-generator
[15] ☃: http://en.wikipedia.org/wiki/Snowman#Unicode
[16] i18n-abide: https://github.com/mozilla/i18n-abide
[17] locale: https://github.com/jed/locale
[18] Инструкция: https://github.com/shane-tomlinson/connect-fonts#creating_a_font_pack
[19] Источник: http://habrahabr.ru/post/197370/
Нажмите здесь для печати.