让前端飞Web前端之路

webpack-优化阻塞的css

2019-12-04  本文已影响0人  小雨小雨丶
随着浏览器的日新月异,网页的性能和速度越来越好,并且对于用户体验来说也越来越重要。
现在有很多优化页面的办法,比如:静态资源的合并和压缩,code splitting,DNS预读取等等。
本文介绍的是另一种优化方法:首屏阻塞css优化

原理:

首先我们了解一下页面的基本渲染流程(参考):

webkit渲染过程:

image.png

Gecko渲染过程:

image.png

那么,为什么要做这种优化呢?上面的流程图就是原因:首先解析html生成dom树,同时解析css生成css树,之后结合两者生成渲染树,然后渲染到屏幕上。不但如此,如果css后面有其他javascript,并且css加载时间过长,也会阻塞后面的js执行,因为js可能会操作dom节点或者css样式,所以需要等待render树完成。那么,如果我们能优化css,那么就能大大减少页面渲染出来的时间,从而提升pv,增加黏性,走向编码巅峰。。。


怎么做呢:

目前我知道的比较实用的办法是webpack集成critical,critical是一个提取关键css,内联到html中,并且使用preload和noscript兼容加载非关键css的工具。
那么,我们开门见山,直接从webpack配置开始:

const HtmlWebpackPlugin = require('html-webpack-plugin'); // 创建html来服务你的资源
const MiniCssExtractPlugin = require('mini-css-extract-plugin'); // 提取css到分离的文件,需要webpack4
const HtmlCriticalWebpackPlugin = require('html-critical-webpack-plugin'); // 集成critical的html-webpack-plugin版本
const path = require('path');

// 用于设置Chromium,因为Chromium使用npm或者yarn经常有问题
process.env['PUPPETEER_EXECUTABLE_PATH'] =
    '你电脑中的Chromium地址';

module.exports = {
    mode: 'none',
    module: {
        rules: [
            {
                test: /\.css$/,
                // 使用MiniCssExtractPlugin.loader代替style-loader
                use: [MiniCssExtractPlugin.loader, 'css-loader']
            },
            {
                test: /\.js$/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: ['@babel/preset-env']
                    }
                }
            }
        ]
    },
    plugins: [
        new HtmlWebpackPlugin({ template: './index.html' }),
        new MiniCssExtractPlugin({}),
        new HtmlCriticalWebpackPlugin({
            base: path.resolve(__dirname, 'dist'),
            src: 'index.html',
            dest: 'index.html',
            inline: true,
            minify: true,
            extract: true,
            width: 375,
            height: 565,
            // 确保调用打包后的JS文件
            penthouse: {
                blockJSRequests: false
            }
        })
    ]
};

然后是html文件:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta http-equiv="X-UA-Compatible" content="ie=edge" />
        <title>Document</title>
    </head>
    <body>
        <div class="div"></div>
        <h2>hello world</h2>
        <div class="mask">这是一个弹窗</div>
    </body>
</html>

接着是css文件:

.div {
    width: 200px;
    height: 100vh;
    background-color: red;
}
h2 {
    color: blue;
}
.mask {
    width: 500px;
    height: 500px;
    display: none;
    position: absolute;
    top: 0;
    left: 0;
    bottom: 0;
    right: 0;
    margin: auto;
    background-color: yellowgreen;
}

运行webpack后,查看打包后的html文件:

// 省略...
<style>
    .div {
        width: 200px;
        height: 100vh;
        background-color: red;
    }
    .mask {
        width: 500px;
        height: 500px;
        display: none;
        position: absolute;
        top: 0;
        left: 0;
        bottom: 0;
        right: 0;
        margin: auto;
        background-color: #9acd32;
    }
</style>
<link
    href="main.80dc2a9c.css"
    rel="preload"
    as="style"
    onload="this.onload=null;this.rel='stylesheet'"
/>
<noscript><link href="main.80dc2a9c.css" rel="stylesheet"/></noscript>
// 省略...

代码仓库在此,点击fork进行实战练习

可以看到,h2标签的css样式没有出现在内联style里,而是出现在main.[hash].css中,因为它不再所设置首屏范围内,这就是所谓的首屏css优化。

相关内容

在上面打包后的html文件里,我们看到了有一个link内有rel="preload" as="style"字段,紧接着下面就有一个noscript标签,这两个是做什么的呢?

总结

利用critical可以大大提高页面渲染速度,但是由于其使用puppeteer,所以下载安装比较麻烦,上面的webpack中使用设置env中puppeteer位置的方法解决了这一问题。

文中如若有不对的地方,还望之处,共同交流。

上一篇下一篇

猜你喜欢

热点阅读