- Оригинальный адрес:10x Performance Increases: Optimizing a Static Site
- Оригинальный автор:JonLuca De Caro
- Перевод с:Программа перевода самородков
- Постоянная ссылка на эту статью:GitHub.com/rare earth/gold-no…
- Переводчик:Starrier
- Корректор:dandyxu,Hopsken
10-кратное повышение производительности: оптимизация статических веб-сайтов
Несколько месяцев назад я путешествовал за границей и хотел показать другу ссылку с моего личного (статического) сайта. Я попытался просмотреть свой сайт, но это заняло больше времени, чем я ожидал. На сайте нет абсолютно никакого динамического контента — только анимация и некоторый адаптивный дизайн, и контент все время остается одним и тем же. Я был шокирован результатами, для загрузки DOMContentLoaded потребовалось 4 с, а для загрузки всей страницы — 6,8 с. Есть около 20статический веб-сайтзапросов (всего 1 МБ данных). Я привык к интернет-соединению со скоростью 1 ГБ/с с малой задержкой от Лос-Анджелеса до моего сервера в Сан-Франциско, поэтому этот монстр кажется молниеносно быстрым. В Италии разница составляет 8 МБ/с.
Это моя первая попытка оптимизации. До сих пор каждый раз, когда я хочу добавить библиотеку или ресурс, я просто импортирую ее и используюsrc=""указать на это. От кеширования до инлайнинга и ленивой загрузки я не обращаю внимания ни на какую производительность.
Я начал искать людей с похожим опытом. К сожалению, большая часть литературы по статической оптимизации быстро устаревает — в предложениях 2010 или 2011 года либо говорится о библиотеках, либо делаются предположения, которые вообще никогда не проверялись, либо просто повторяются одни и те же рекомендации.
Однако я нашел два хороших источника информации -- Высокопроизводительная браузерная сетьа такжеАналогичный опыт Дэна Луу по оптимизации статического веб-сайта. Хотя я не так хорошо, как Дэн, в удалении форматирования и контента, мне удалось заставить мои страницы загружаться примерно в 10 раз быстрее. DOMContentLoaded занимает примерно пятую долю секунды, а вся страница загружается всего за 388 мс (на самом деле немного неточно, позже я объясню, почему ленивая загрузка).
Обработать
Первым шагом в этом процессе был анализ сайта, я хотел выяснить, где это занимает больше всего времени и как лучше все распараллелить. Я запускаю различные инструменты для анализа своего сайта и тестирования его по всему миру, в том числе:
- tools.pingdom.com/
- www.webpagetest.org/
- tools.keycdn.com/speed
- Developers.Google.com/Web/tools/com…
- Developers.Google.com/speed/pages…
- webspeedtest.cloudinary.com/
Некоторые из них предлагают предложения по улучшению, но вы можете сделать так много только тогда, когда на статическом сайте есть 50 запросов — от разнесенных гифок, оставшихся с 90-х годов, до активов, которые больше не используются (я загрузил 6 шрифтов, но использовал только 1 шрифт).
Моя временная шкала веб-сайта — я проверил это в веб-архиве, не делая скриншот оригинала, но он все еще выглядит так же, как то, что я видел несколько месяцев назад.
Я хочу улучшить все, что могу контролировать — от контента и скорости JavaScript до фактического веб-сервера (Ngnix) и настроек DNS.
оптимизация
Упрощайте и комбинируйте ресурсы
Первое, что я заметил, это то, что я делал дюжину запросов (без какой-либо формы поддержки активности HTTP) к различным веб-сайтам, будь то для CSS или JS, и некоторые из них были https-запросами. Это добавляет несколько обращений к различным CDN или серверам, некоторые файлы JS запрашивают другие файлы, что вызывает каскадную блокировку, показанную выше.
я используюwebpackОбъедините все ресурсы в один файл js. Всякий раз, когда я что-то меняю, оно автоматически упрощает и преобразует все мои зависимости в один файл.
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const ZopfliPlugin = require("zopfli-webpack-plugin");
module.exports = {
entry: './js/app.js',
mode: 'production',
output: {
path: __dirname + '/dist',
filename: 'bundle.js'
},
module: {
rules: [{
test: /\.css$/,
loaders: ['style-loader', 'css-loader']
}, {
test: /(fonts|images)/,
loaders: ['url-loader']
}]
},
plugins: [new UglifyJsPlugin({
test: /\.js($|\?)/i
}), new ZopfliPlugin({
asset: "[path].gz[query]",
algorithm: "zopfli",
test: /\.(js|html)$/,
threshold: 10240,
minRatio: 0.8
})]
};
Я пробовал различные конфигурации. Теперь этот файл bundle.js на моем сайте<head>
, и находится в состоянии блокировки. Его окончательный размер составляет 829 КБ, включая все ресурсы, не связанные с изображениями (шрифты, css, все библиотеки, зависимости и js). Подавляющее большинство шрифтов использует font-awesome, на долю которого приходится 724 из 829 КБ.
Я просмотрел библиотеку Font Awesome, и все, кроме трех иконок, которые я хочу использовать: fa-github, fa-envelope и fa-code, были удалены. Я использую что-то под названиемfontelloсервис для извлечения нужных мне иконок. Новый размер всего 94 кб.
То, как сейчас построен сайт, выглядит неправильно, если у нас есть только таблицы стилей, поэтому я принял блокирующий характер одного bundle.js. Время загрузки составило 118 мс, что на порядок лучше, чем раньше.
Это также дает некоторые дополнительные преимущества — я больше не указываю на сторонний ресурс или CDN, поэтому пользователю не нужно: (1) выполнять DNS-запрос для ресурса, (2) выполнять рукопожатие https, ( 3) дождаться полной загрузки ресурса.
В то время как CDN и распределенный кеш могут иметь смысл для крупного распределенного веб-сайта, они не имеют смысла для моего небольшого статического сайта. Стоит ли оптимизировать эти дополнительные 100 мс или около того.
Сжатые ресурсы
Я загрузил аватар размером 8 МБ и отобразил его с соотношением сторон 10%. Это не просто отсутствие оптимизации, это почтиигнорирует использование пропускной способности пользователем.
я используюwebspeedtest.cloudinary.com/сжать все изображения -- мне также предложили переключиться наwebp, но мне нужна максимальная совместимость с другими браузерами, поэтому я придерживаюсь jpg. Хотя вполне возможно создать систему, которая доставляет webp только в браузеры, которые его поддерживают, я бы хотел, чтобы она была как можно проще, выгода от добавления уровня абстракции не кажется очевидной.
Улучшение веб-сервера — HTTP2, TLS и т. д.
Первое, что я сделал, это перешел на https — сначала я запускал Ngnix на порту 80, обслуживая только файлы из /var/www/html.
server{
listen 80;
server_name jonlu.ca www.jonlu.ca;
root /var/www/html;
index index.html index.htm;
location ~ /.git/ {
deny all;
}
location ~ / {
allow all;
}
}
Сначала установите https и перенаправьте все http-запросы на https. Я изДавайте зашифруем(Отличная организация только начинает подписывать групповые сертификаты!wildcard certificates), чтобы получить собственный сертификат TLS.
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name jonlu.ca www.jonlu.ca;
root /var/www/html;
index index.html index.htm;
location ~ /.git {
deny all;
}
location / {
allow all;
}
ssl_certificate /etc/letsencrypt/live/jonlu.ca/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/jonlu.ca/privkey.pem; # managed by Certbot
}
Просто добавив директиву http2, Ngnix может воспользоваться всеми преимуществами новейших функций HTTP. Обратите внимание, что если вы хотите воспользоваться преимуществами HTTP2 (ранее SPDY), выдолженИспользуя HTTPS, вздесьПодробнее.
Вы также можете воспользоваться командой HTTP2 push, используяhttp2протолкнуть изображения/Headshot.jpg;
ПРИМЕЧАНИЕ. Включение gzip и TLS может привести кBREACHриск. Поскольку это статический веб-сайт и фактический риск НАРУШЕНИЯ низок, я чувствую себя комфортно, сохраняя его сжатым.
Используйте инструкции по кэшированию и сжатию
Что еще можно сделать, просто используя Ngnix? Первый — это инструкции по кэшированию и сжатию.
Я всегда отправлял необработанный несжатый HTML. нужен только одинgzip; да, я могу перейти с 16 000 байт на 8 000 байт, сокращение на 50%.
На самом деле, мы смогли улучшить это число еще больше, если NgnixgzipКогда static включен, он заранее ищет предварительно сжатые версии всех запрошенных файлов. Это сочетается с нашей конфигурацией веб-пакета выше - мы можем использовать во время сборкиZopflicPluginВсе файлы предварительно сжаты! Это экономит вычислительные ресурсы и позволяет максимизировать сжатие без ущерба для скорости.
Кроме того, мой сайт очень мало меняется, поэтому я хочу кэшировать ресурсы как можно дольше. Таким образом, при будущих посещениях пользователю не нужно повторно загружать все ресурсы (особенно bundle.js).
Моя обновленная конфигурация сервера выглядит так. Обратите внимание, что я не буду вдаваться во все изменения, которые я сделал, такие как изменения настроек TCP, директивы gzip и кэширование файлов. Если вы хотите узнать больше, пожалуйстаПрочтите эту статью о настройке Ngnix.
worker_processes auto;
pid /run/nginx.pid;
worker_rlimit_nofile 30000;
events {
worker_connections 65535;
multi_accept on;
use epoll;
}
http {
##
# Basic Settings
##
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# Turn of server tokens specifying nginx version
server_tokens off;
open_file_cache max=200000 inactive=20s;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors on;
include /etc/nginx/mime.types;
default_type application/octet-stream;
add_header Referrer-Policy "no-referrer";
##
# SSL Settings
##
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_dhparam /location/to/dhparam.pem;
ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';
ssl_session_timeout 1d;
ssl_session_cache shared:SSL:50m;
ssl_stapling on;
ssl_stapling_verify on;
add_header Strict-Transport-Security 'max-age=31536000; includeSubDomains; preload';
ssl_certificate /location/to/fullchain.pem;
ssl_certificate_key /location/to/privkey.pem;
##
# Logging Settings
##
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
##
# Gzip Settings
##
gzip on;
gzip_disable "msie6";
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript application/vnd.ms-fontobject application/x-font-ttf font/opentype image/svg+xml image/x-icon;
gzip_min_length 256;
##
# Virtual Host Configs
##
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
и соответствующий серверный блок
server {
listen 443 ssl http2;
server_name jonlu.ca www.jonlu.ca;
root /var/www/html;
index index.html index.htm;
location ~ /.git/ {
deny all;
}
location ~* /(images|js|css|fonts|assets|dist) {
gzip_static on; # 告诉 Nginx 首先查找所有请求文件的压缩版本。
expires 15d; # 15 day expiration for all static assets
}
}
ленивая загрузка
Наконец, есть небольшое изменение в моем реальном веб-сайте, оптимизация, которую он приносит, не является незначительной. Есть 5 изображений, которые не видны, пока не нажмешь соответствующую вкладку, но они подгружаются одновременно со всем остальным (потому что они в<img src=”…”>
этикетка).
Я написал короткий скрипт, который используеткласс ленивой загрузкиИзмените свойства каждого элемента. Эти изображения загружаются только при нажатии соответствующего поля.
$(document).ready(function() {
$("#about").click(function() {
$('#about > .lazyload').each(function() {
// set the img src from data-src
$(this).attr('src', $(this).attr('data-src'));
});
});
$("#articles").click(function() {
$('#articles > .lazyload').each(function() {
// set the img src from data-src
$(this).attr('src', $(this).attr('data-src'));
});
});
});
поэтому, как только документ завершит загрузку, он изменит<img>
теги, чтобы они были удалены из<img data-src=”…”>
идти к<img src=”…”>
Затем загрузите его в фоновом режиме.
будущие улучшения
Есть несколько других изменений для повышения скорости загрузки страниц — в первую очередь использование Service Workers для кэширования и перехвата всех запросов, возможность работы сайта даже в автономном режиме, кэширование контента в CDN, чтобы пользователям не нужно было возиться с сервером в SF A. полная круговая операция. Это ценные изменения, но они не особенно важны для личного статического сайта, так как это страница онлайн-резюме (обо мне).
В заключение
Это улучшило время загрузки моей страницы с 8 секунд при первой загрузке до 350 мс и 200 мс на последующих страницах. очень рекомендую прочитатьВысокопроизводительная браузерная сеть -- Вы можете прочитать его быстро, он дает очень хороший обзор современного Интернета, оптимизированный на каждом уровне интернет-модели.
Я что-то пропустил? Имеются ли нарушения лучших практик? Или, может быть, еще что-то, чтобы улучшить мое повествование? Пожалуйста, не стесняйтесь поправлять меня - JonLuca De Caro!
Программа перевода самородковэто сообщество, которое переводит высококачественные технические статьи из Интернета сНаггетсДелитесь статьями на английском языке на . Охват контентаAndroid,iOS,внешний интерфейс,задняя часть,блокчейн,товар,дизайн,искусственный интеллектЕсли вы хотите видеть более качественные переводы, пожалуйста, продолжайте обращать вниманиеПрограмма перевода самородков,официальный Вейбо,Знай колонку.