详解Vue如何提取Critical Css

什么是Critical Css

首屏关键css
网页渲染时,浏览器解析只有在完成 部分 CSS 样式的加载、解析之后才会渲染页面。这种渲染方式意味着,如果 CSS 文件很大,那么用户就必须等待很长的时间才能看到渲染结果。针对这一问题,提出一种非常规的解决方案,提高页面的渲染速度,这一方案常被称为 critical rendering path(关键渲染路径)。我们要做的优化就是找出渲染首屏的最小 CSS 集合(Critical CSS),并把它们写到 部分,从而让浏览器接收到 HTML 文件后就尽快渲染出页面。对于剩余部分的 CSS,我们可以使用异步的方式进行加载。

总结:Critical Css就是渲染首屏的最小CSS集合。

通过criticalcss网站获取页面critical css【收费】

Vue-cli客户端提取Critical css

提取css

vue-cli4为例

css.extract

介绍

  • Type: boolean | Object
  • Default: 生产环境下是 true,开发环境下是 false

是否将组件中的 CSS 提取至一个独立的 CSS 文件中 (而不是动态注入到 JavaScript 中的 inline 代码)。

同样当构建 Web Components 组件时它总是会被禁用 (样式是 inline 的并注入到了 shadowRoot 中)。

当作为一个库构建时,你也可以将其设置为 false 免得用户自己导入 CSS。

提取 CSS 在开发环境模式下是默认不开启的,因为它和 CSS 热重载不兼容。然而,你仍然可以将这个值显性地设置为 true 在所有情况下都强制提取。

  • 开发环境
    extractfalse,样式内嵌到 head 中。
    开发环境.png
  • 生产环境
    extracttrue,样式分离,外链到 head 中。

形成两个css文件:

app.[contetHash].css:vue组件抽离出来的css

chunk-vendors.[contentHash].css:第三方库依赖的css

生产环境.png

内部插件

  • mini-css-extract-plugin:CSS 提取到单独的文件中,为每个包含 CSS 的 JS 文件创建一个 CSS 文件,并且支持 CSS 和 SourceMaps 的按需加载
  • @intervolga/optimize-cssnano-plugin:优化和压缩css

不足

要么样式全部内嵌在head中导致html文件过大,要么外链,如果出现网络问题,页面白屏时间过长。

针对这一不足,我们看一下在vue客户端项目中如何提取首屏渲染csscritical css

提取critical css

使用webpack插件critical-css-webpack-plugin

critical-css-webpack-plugin

项目配置

vue-cli4.x为例

Install
npm install critical-css-webpack-plugin -D
vue.config.js
const criticalCssWebpackPlugin = require('critical-css-webpack-plugin')

/ critical css Options
const criticalCssOptions = {
    // type: boolean/object,是否inline生成的critical-path css。
    // true:生成html,false:生成css,object:向`inline-critical`传递配置对象
    inline: true,
    // type: string,读取和写入源的目录
    base: resolve('dist'),
    // type: string,要操作的html源代码,此选项优先于src选项
    // html: '',
    // type: array,css路径的数组
    // css: [],
    // type: string,要操作的html源代码的位置
    src: 'index.html',
    // type: string,保存操作输出的位置,如果要同时存储`html`和`css`,使用`html`和`css`的对象
    target: 'index.html',
    // type: integer,1300,目标视口的宽度
    width: 1300,
    // type: integer,900,目标视口的高度
    height: 900,
    // type: array,包含宽度和高度的数组,如果设置,优先于width和height选项
    dimensions: [],
    // type: boolean,是否压缩生成的critical-path css
    minify: true,
    // type: boolean,小心使用,从html中删除inline样式,它会基于提取的内容生成新的引用,因此可以安全地在多个html文件引用同一样式文件。删除每页的关键css会为每个页面生成唯一一个异步加载css。意味着你不能跨多页面缓存
    extract: false,
    // type: boolean,inline图片
    inlineImages: true,
    // type: array,内联程序开始查询assets时的目录/url列表
    assetPaths: [],
    // 设置base64内联图片的最大大小(以字节为单位)
    maxImageFileSize: 10240000,
    // type: object/function,critical尝试相对文档的assets path
    rebase: undefined,
    // type: array
    ignore: [],
    // type: string,获取远程src时的用户代理
    // userAgent: '',
    // type: object,penthouse的配置选项
    penthouse: {
        // propertiesToRemove: ['background'],
        // 强制包含的selector
        forceInclude: ['.card', '.card__list', '.card__main', '.card__img', '.card__article'],
        forceExclude: []
    },
    // type: object,got的配置选项
    request: {},
    // type: string,RFC2617授权:user
    user: undefined,
    // type: string,RFC2617授权:pass
    pass: undefined,
    // type: boolean,如果找不到css,则抛出错误
    strict: false
};

module.exports = {
    chainWebpack: config => {
        config.plugin('critical')
                .use(criticalCssWebpackPlugin,
                    [
                        criticalCssOptions
                    ]
                ).tap(error => {
                    console.log(error, 'critical css generate error');
                    return error
                })
    }
}

配置完毕后,执行npm run build构建,查看dist/index.html,可以看到提取的critical css插入到head中,剩余css仍以外链形式引入。

这样index.html文件也不会很大,也可以保证在网络不稳定时,显示简单页面样式。

image.png

critical-css-webpack-plugin插件的核心是criticalcritical核心使用penthouse,接下来再详解一下criticalpenthouse

critical插件

critical插件介绍,使用到核心组件库penthouse。

html中提取critical css,并将critical-path内联到html中

Install
npm i -D critical
Usage

配置文件critical.js

const critical = require('critical');
critical.generate({
  // Inline the generated critical-path CSS
  // - true generates HTML
  // - false generates CSS
  inline: true,
  ...
});

node环境下执行配置文件critical.js即可

node critical.js
Critical Options

摘自https://www.npmjs.com/package/critical

Name Type Default Description
inline boolean/object false Inline critical-path CSS using filamentgroup's loadCSS. Pass an object to configure inline-critical
base string path.dirname(src) or process.cwd() Base directory in which the source and destination are to be written
html string HTML source to be operated against. This option takes precedence over the src option.
css array [] An array of paths to css files, file globs or Vinyl file objects.
src string Location of the HTML source to be operated against
target string or object Location of where to save the output of an operation. Use an object with 'html' and 'css' props if you want to store both
width integer 1300 Width of the target viewport
height integer 900 Height of the target viewport
dimensions array [] An array of objects containing height and width. Takes precedence over width and height if set
minify boolean true Enable minification of generated critical-path CSS
extract boolean false Remove the inlined styles from any stylesheets referenced in the HTML. It generates new references based on extracted content so it's safe to use for multiple HTML files referencing the same stylesheet. Use with caution. Removing the critical CSS per page results in a unique async loaded CSS file for every page. Meaning you can't rely on cache across multiple pages
inlineImages boolean false Inline images
assetPaths array [] List of directories/urls where the inliner should start looking for assets
maxImageFileSize integer 10240 Sets a max file size (in bytes) for base64 inlined images
rebase object or function undefined Critical tries it's best to rebase the asset paths relative to the document. If this doesn't work as expected you can always use this option to control the rebase paths. See postcss-url for details. (https://github.com/pocketjoso/penthouse#usage-1).
ignore array object undefined
userAgent string '' User agent to use when fetching a remote src
penthouse object {} Configuration options for penthouse.
request object {} Configuration options for got.
user string undefined RFC2617 basic authorization: user
pass string undefined RFC2617 basic authorization: pass
strict boolean false Throw an error if no css is found
Global Install And Cli
npm install -g critical
critical test/fixture/index.html --base test/fixture > critical.css

penthouse

penthouse介绍

关键路径css生成器

Install
npm i -D penthouse
Usage
penthouse({
  url: 'http://google.com',
  cssString: 'body { color: red }'
  ...
})
.then(criticalCss => {
  // use the critical css
  fs.writeFileSync('outfile.css', criticalCss);
})
Options

对应critical插件中的penthouseoptions

Name Type Default Description
url string Accessible url. Use file:/// protocol for local html files.
cssString string Original css to extract critical css from
css string Path to original css file on disk (if using instead of cssString)
width integer 1300 Width for critical viewport
height integer 900 Height for critical viewport
screenshots object Configuration for screenshots (not used by default). See Screenshot example
keepLargerMediaQueries boolean false Keep media queries even for width/height values larger than critical viewport.
forceInclude array [] Array of css selectors to keep in critical css, even if not appearing in critical viewport. Strings or regex (f.e. ['.keepMeEvenIfNotSeenInDom', /^.button/])
forceExclude array [] Array of css selectors to remove in critical css, even if appearing in critical viewport. Strings or regex (f.e. ['.doNotKeepMeEvenIfNotSeenInDom', /^.button/])
propertiesToRemove array ['(.)transition(.)', 'cursor', 'pointer-events', '(-webkit-)?tap-highlight-color', '(.*)user-select'] ] Css properties to filter out from critical css
timeout integer 30000 Ms; abort critical CSS generation after this time
puppeteer object Settings for puppeteer. See Custom puppeteer browser example
pageLoadSkipTimeout integer 0 Ms; stop waiting for page load after this time (for sites when page load event is unreliable)
renderWaitTime integer 100 ms; wait time after page load before critical css extraction starts (also before "before" screenshot is taken, if used)
blockJSRequests boolean true set to false to load JS (not recommended)
maxEmbeddedBase64Length integer 1000 characters; strip out inline base64 encoded resources larger than this
maxElementsToCheckPerSelector integer undefined Can be specified to limit nr of elements to inspect per css selector, reducing execution time.
userAgent string 'Penthouse Critical Path CSS Generator' specify which user agent string when loading the page
customPageHeaders object et extra http headers to be sent with the request for the url.
cookies array [] For formatting of each cookie, see Puppeteer setCookie docs
strict boolean false Make Penthouse throw on errors parsing the original CSS. Legacy option, not recommended.
allowedResponseCode number|regex|function Let Penthouse stop if the server response code is not matching this value. number and regex types are tested against the response.status(). A function is also allowed and gets Response as argument. The function should return a boolean.

SSR服务端提取Critical css

介绍

简介

SSR服务端渲染时,管理 CSS 的推荐方法是简单地使用 *.vue 单个文件组件内的

新建pages/test.vue页面,验证SSR是否会自动注入关键css(critical css



  1. index.vue中引入test.vue,服务启动后,test.vue样式也以style形式内嵌在页面中
  2. 不在index.vue中引入test.vue,服务启动后,test.vue样式则没有内嵌在首屏渲染页面中

总结:SSR服务端会自动注入首屏渲染关键css,无需引入其他插件。

提取CSS

nuxt框架配置为例nuxt.config.js

SSR可通过extractCSS将css提取到独立的文件中,方便缓存。

export default {
    build: {
        extractCSS: true,
    }
}
image.png

总结

  • 客户端和服务端均可通过extract提取css至单独文件中,以外链形式引入
  • 客户端只可内嵌csshead中,或提取成单独文件外链引入,不可提取critical css,需要增加额外webpack plugin来提取
  • 服务端自动注入critical css,不需额外引入其他插件

参考文档

  • ssr服务端介绍
  • ssr nuxt框架介绍
  • vue cli css配置
  • critical
  • penthouse
  • inline-critical

你可能感兴趣的:(详解Vue如何提取Critical Css)