“消除渲染阻止的javascript和css”。 这是我始终坚持使用的google page speed insights建议。google建议您在页面加载准备就绪时将最初需要的css(内插)css内嵌并加载css的其余部分
当访问web页面时,谷歌希望它只加载对初始视图有用的内容,并使用空闲时间来加载其他内容。这样,用户可以尽早看到页面。
我们可以做很多事情来最小化javascript的委托阻塞,比如代码分割、树抖动、缓存等等。
那么css呢?为此,我们可以通过隔离用于上述内容的css(即关键的css)并首先加载它来最小化委托阻塞。然后我们可以加载非关键的css。
隔离关键的css是可以通过编程实现的,在本文中,我将向您展示如何将其委派给webpack管道。
渲染阻止是什么意思?
如果资源是“渲染阻止”,则意味着浏览器在下载或处理该资源之前无法显示该页面。
通常情况下,我们会通过链接到文档头部的样式表来以一种阻塞的方式加载css,如下所示:
<head> <link rel="stylesheet" href="/style.css"> ...</head><body> <p>i can't be seen until style.css has been loaded!</p></body>
当web浏览器加载这个页面时,它将从头到尾地读取它。当浏览器到达链接标记时,它将立即开始下载样式表,并且在完成之前不会呈现页面。
对于大型站点,特别是具有bootstrap这样的大框架的站点,样式表可能是几百kb,用户必须耐心等待,直到完全下载完毕。
那么,我们是否应该链接到主体中的样式表,在那里呈现不会被阻塞?你可以这么做,但问题是,阻止租客并不完全是坏事,我们实际上想利用它。如果页面渲染没有任何css加载,我们会得到丑陋的“flash无风格的内容”:
我们想要的最佳点是在哪里渲染,用关键的css阻塞页面,这是设计主视图样式所必需的,但是所有非关键的css都是在初始渲染之后加载的。
关键的css
看看我用bootstrap和webpack构建的这个简单页面。这是它第一次渲染后的样子:
该页面还有一个模式,可通过“立即注册”按钮打开。 打开后,它看起来像这样:
对于页面的第一次呈现,我们需要nav bar、jumbotron、button和其他一些布局和字体的一般规则的css规则。但我们不需要模态的规则,因为它不会立即显示。考虑到这一点,我们可以将关键css与非关键css分离:
critical.css
.nav { ...}.jumbtron { ...}.btn { ...}
non_critical.css
.modal { ...}
如果你认同这个概念,你可能会对以下两个问题感兴趣:
我们如何通过编程来区分关键的和非关键的css ?
如何让页面在第一次渲染前加载关键的css,在第一次渲染后加载非关键的css ?
示例项目
我将简要地向您介绍这个项目的基本设置,以便在我们找到解决方案时能够很快地消化。
首先,我加载引导sass到我的输入文件。
main.js
require("bootstrap-sass/assets/stylesheets/_bootstrap.scss");
我正在使用sass-loader处理此问题,并将其与extract text plugin结合使用,以便将已编译的css放入其自己的文件中。
我还使用html webpack插件在构建中创建html文件。 如您将很快看到的,该解决方案是必不可少的。
webpack.config.js
module.exports = { module: { rules: [ { test: /\.scss$/, use: extracttextplugin.extract({ fallback: 'style-loader', use: ['css-loader', 'sass-loader'] }) }, ... ] }, ... plugins: [ new extracttextplugin({ filename: 'style.css' }), new htmlwebpackplugin({ filename: 'index.html', template: 'index.html', inject: true }) ] };
运行构建后,html文件是这样的。注意css是在头部加载的,因此会阻塞渲染。
index.html
<!doctype html><html><head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1"> <title>vuestrap-code-split</title> <link href="/style.css" rel="stylesheet"></head><body> <!--app content goes here, omitted for brevity.--> <script type="text/javascript" src="/build_main.js"></script></body></html>
以编程方式识别关键css
手动识别关键css会很麻烦。 要以编程方式做到这一点,我们可以使用addy osmani恰当地命名为critical的工具。 这是一个node.js模块,它将读取html文档,并标识关键的css。 除此之外,它的作用还不止于此,我们很快就会看到。
critical识别关键css的方法是使用phantomjs加载页面,使用指定的屏幕维度,并提取呈现页面中使用的任何css规则。
以下是我们如何为这个项目设置:
const critical = require("critical");critical.generate({ /* the path of the webpack bundle */ base: path.join(path.resolve(__dirname), 'dist/'), src: 'index.html', dest: 'index.html', inline: true, extract: true, /* iphone 6 dimensions, use whatever you like*/ width: 375, height: 565, /* ensure that bundled js file is called */ penthouse: { blockjsrequests: false, }});
执行时,这将把webpack包输出中的html文件更新为:
index.html
<!doctype html><html><head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1"> <title>bootstrap critical</title> <style type="text/css"> /* critical css is inlined into the document head, abbreviated here. */ body { font-family: helvetica neue,helvetica,arial,sans-serif; font-size: 14px; line-height: 1.42857; color: #333; background-color: #fff; } ... </style> <link href="/style.96106fab.css" rel="preload" as="style" onload="this.rel='stylesheet'"> <noscript> <link href="/style.96106fab.css" rel="stylesheet"> </noscript> <script> /*a script for loading the non-critical css goes here, omitted for brevity.*/ </script></head><body> <!--app content goes here, omitted for brevity.--> <script type="text/javascript" src="/build_main.js"></script></body></html>
它还将输出一个新的css文件,例如style.96106fab.css(文件名会自动添加一个散列)。这个css文件与原始样式表相同,只是去掉了关键的css。
内联关键css
您将注意到关键的css已内联到文档的头部。这是最优的,因为页面不必从服务器加载它。
预加载非关键css
您还将注意到,非关键css加载了外观精美的链接。 preload值告诉浏览器开始获取非关键css供挂起使用。 但至关重要的是,预加载不是渲染阻止,因此无论预加载资源是否完成,浏览器都将继续绘制页面。
链接中的onload属性允许我们在非关键的css最终加载后运行脚本。关键模块自动将脚本内联到文档中,从而提供跨浏览器兼容的方式将非关键样式表加载到页面中。
<link href="/style.96106fab.css" rel="preload" as="style" onload="this.rel='stylesheet'">
将critical放入webpack管道
我制作了一个名为html关键webpack plugin的webpack插件,它仅仅是关键模块的包装器。它将在您的文件从html网页包插件发出后运行。
以下是如何将它包含在webpack项目中:
const htmlcriticalplugin = require("html-critical-webpack-plugin");module.export = { ... plugins: [ new htmlwebpackplugin({ ... }), new extracttextplugin({ ... }), new htmlcriticalplugin({ base: path.join(path.resolve(__dirname), 'dist/'), src: 'index.html', dest: 'index.html', inline: true, minify: true, extract: true, width: 375, height: 565, penthouse: { blockjsrequests: false, } }) ] };
注意:您可能只应该在生产构建中使用它,而不是在开发中,因为它会使您的构建非常慢!
性能结果
现在我已经隔离了关键的css,并在空闲时间加载了非关键的css,那么如何改进性能呢?
我使用chrome的灯塔扩展来寻找答案。请记住,我们试图优化的度量标准是第一次有意义的绘制的时间,它基本上告诉我们用户看到某些东西需要多长时间。
在实施关键的css:
关键的css实现后:
如您所见,我的应用程序在整整一秒钟前就获得了一幅有意义的画作,并且在半秒钟前就实现了交互。
实际上,你可能不会在你的应用程序中得到如此显著的改进,因为我的css已经完全膨胀了(我包括了整个引导库),在这样一个简单的应用程序中,我没有很多关键的css规则。
英文原文地址:https://vuejsdevelopers.com/2017/07/24/critical-css-webpack/
更多编程相关知识,请访问:编程课程!!
以上就是详解减少阻塞渲染的css的自动化的方法的详细内容。