【翻译】10倍性能提升:优化静态站点——by JonLuca De Caro

10倍性能提升:优化静态站点——by JonLuca De Caro

原文地址:10x Performance Increases: Optimizing a Static Site by JonLuca De Caro https://link.medium.com/KtPI4fhWdR

几个月前,我在美国境外旅行,并且我希望向我的朋友展示我的个人静态网站,我尝试导航到我的网站,但我花费了比我预期更长的时间。网站中绝对没有任何的动态内容,只是有一些动画和响应式设计,但是内容是静态保持不变的。我对这个结果表示非常震惊,DOM节点内容加载花费了4s,整个网页加载花费了6.8s。网站中有20个静态站点请求,传输总数据为1Mb,我已经习惯了连接到我在旧金山的服务器的洛杉矶的1Gb/s 低延迟物联网速度,这让这个怪物像闪电般快速。在意大利,以8Mb/秒的网速,这完全是一个不同的画面。

这是我第一次研究网络优化,到目前为止之前我无论什么时候想要添加一个库或者资源,我都会将其抛入并指向到src=‘’。我没有注意任何形式的性能,从缓存到内联到延迟加载。

我开始寻找有相似经验的人,但是很不幸,很多关于静态文件优化的文献都已经过时了,都是一些2010年或者2011年的建议或者讨论。文库或者假设都不再是真实的,只是重复以前的理论。

但是我还是找到了两个很好的信息资源——高性能浏览器网络和Dan Luu 在优化静态站点方面的类似经验。虽然在代码格式和内容方面我达不到Dan的水平,但是我确实设法让自己的页面加载速度大约快了10倍,DOM节点内容加载大约为5分之一秒,整页面加载只有388ms。(实际是有点不准确,因为它解决了延迟加载)。

过程

这个过程的第一步是分析网站轮廓。我想要弄清楚什么是加载时间最长的,以及如何最好的并行优化一切。我运行了各种工具来分析我的网站,并且在世界各地进行测试,包括:
• https://tools.pingdom.com/
• www.webpagetest.org/
• https://tools.keycdn.com/speed
• https://developers.google.com/web/tools/lighthouse/
• https://developers.google.com/speed/pagespeed/insights/
• https://webspeedtest.cloudinary.com/

其中一些提供了有关改进的建议,但是当你的网站有50个请求时,你才可以做到这一点。这从90年代遗留下来的gif空图像,是未使用的资源。(我加载了6种字体却只使用了其中一种)。


我的网站的时间线 - 我在Web Archive网络存档上对此进行了测试,因为我没有截取原始网站,但它看起来与我几个月前看到的相似。


我想改进我控制的一切 ———从内容和和通过javascript连接到Web服务器(Nginx)的速度和DNS设置。


优化

缩小和合并资源

第一件我需要注意的事情是我为CSS和JS(没有任何形式的HTTP keepalive)制作了十几个请求,对于不同站点,其中一些是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文件位于我网站的head部分,会形成阻塞。它的最终大小为829kb,包括每一个非图片资源(css,字体,所有库和依赖项以及js)。这里面绝大多数是字体文件,占用了829kb中的724kb。

我浏览了Font Awesome 库,并删除了除了我使用的三个图标以外的所有,只留下了fa-github,fa-envelope和fa-code图标。
我使用了一个名为fontello的服务来拉取我需要的图标,这时候字体资源只需要94kb大小。

网站目前的构建方式,如果我们只要样式表,那看起来是不正确的,所以我接受了单个bundle.js的阻塞性质。加载时间为118毫秒,比上述要好一个等级。

这也有一些额外的好处,我不再需要指向第三方资源或者CDN,因此用户不需要
1.对资源执行CDNS查询;
2.执行https握手;
3.等待资源从第三方完全下载;

虽然CDN和分布式缓存可能对大规模的分布式站点有意义,但对我的小型静态网站没有意义。额外的100毫秒左右是值得的权衡。

 

压缩资源

我加载了8Mb大小的头部头像,然后以10% 的宽度高度显示它。这不仅仅是缺乏优化,这几乎是对用户带宽的浪费使用。

我在这个网站压缩了所有图像,https://webspeedtest.cloudinary.com/。它还建议我切换到webp格式,但我希望保持更多可能性的浏览器兼容,所以依然坚持使用jpg格式。其实可以建立一个程序,让webp仅被传递到支持它的浏览器。
但是我希望尽可能保持简单,而且对于增加抽象层代码的优势并不明显和值得。


改进Web服务器-Http2,TLS等

我做的第一件事情是转到https,以前我在端口80上运行Nginx,只是从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,我从Let's Encrypt获得了我的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指令,Nginx就可以充分利用最新HTTP功能的所有优势特性。 请注意,如果要利用HTTP2(以前的SPDY),则必须使用HTTPS。 在这里阅读(https://hpbn.co/http2/)更多相关信息。

您还可以利用带有http2_push 命令作用于images / Headshot.jpg;

注意:启用gzip和TLS可能会使您面临BREACH风险。 由于这是一个静态站点,面临BREACH的实际风险很低,所以保持压缩是是没有问题的。

利用缓存和压缩指令

通过Nginx还可以实现更多目标吗?跳出来的第一件事就是缓存和压缩指令。

我发送原始的未压缩的html,只需要一个_gzip和_line命令,就能够从160000字节变为8000字节,减少50%。

我们实际上可以能够进一步提高这个数字——如果设置Nginx的_gzip_static,它会预先查找所有请求文件的预压缩版本。这与我们上面的webpack config结合使用,我们可以用ZopicPlugin在构建时预压缩我们所有文件。这节省了计算资源,并允许我们最大限度的提高压缩率,而无需权衡速度。

此外,我的网站很少更改,所以我希望更可能长时间的缓存资源。这将使得在后期用户访问中,不需要重新下载资源(尤其是bundle.js)

我更新的服务器配置如下所示:请注意,我并没有讲解我所有的更改,例如TCP设置更改,gzip指令和文件缓存。如果您想要了解更多相关信息,请阅读有关调优Nginx的文章

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; # Tells nginx to look for compressed versions of all requested files first
        expires 15d; # 15 day expiration for all static assets
    }

}


延迟加载

最后,我对我的实际网站进行了一些小的改动,这也对速度有少许不可忽视的提高。有5个图像是在您按下相应的标签之前看不到,但是这些图片还是与其他所有标签同时加载。(因为他们位于<img src ="">标签中。

我写了一个简短的脚本,用lazyload类修改这些元素的属性。只有在单击相应的框时才会加载这些图像。

$(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中往返服务器。
这些都是值得的改变,但对于作为在线简历/关于我的页面的个人静态网站而言并不是特别重要。

结论

这使得我的页面加载速度从第一页加载时的8秒以上变为350ms,后续加载时间为200毫秒。我真的建议您阅读所有高性能浏览器网络High Performance Browser Networking ,它很容易阅读完,但是却提供了一个令人难以置信的现代互联网概述,并对优化现代互联网模型的每一层提出了很好的建议。

我错过遗漏了什么吗?是否有一些违反最佳实践或可以进一步改善性能的方法?随意联系JonLuca De Caro!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值