詳解Vue如何提取Critical Css

什么是Critical Css

首屏關(guān)鍵css
網(wǎng)頁渲染時(shí),瀏覽器解析只有在完成 <head> 部分 CSS 樣式的加載、解析之后才會(huì)渲染頁面。這種渲染方式意味著,如果 CSS 文件很大,那么用戶就必須等待很長的時(shí)間才能看到渲染結(jié)果。針對(duì)這一問題,提出一種非常規(guī)的解決方案,提高頁面的渲染速度,這一方案常被稱為 critical rendering path(關(guān)鍵渲染路徑)。我們要做的優(yōu)化就是找出渲染首屏的最小 CSS 集合(Critical CSS),并把它們寫到 <head> 部分,從而讓瀏覽器接收到 HTML 文件后就盡快渲染出頁面。對(duì)于剩余部分的 CSS,我們可以使用異步的方式進(jìn)行加載。

總結(jié):Critical Css就是渲染首屏的最小CSS集合。

通過criticalcss網(wǎng)站獲取頁面critical css【收費(fèi)】

Vue-cli客戶端提取Critical css

提取css

vue-cli4為例

css.extract

介紹

  • Type: boolean | Object
  • Default: 生產(chǎn)環(huán)境下是 true,開發(fā)環(huán)境下是 false

是否將組件中的 CSS 提取至一個(gè)獨(dú)立的 CSS 文件中 (而不是動(dòng)態(tài)注入到 JavaScript 中的 inline 代碼)。

同樣當(dāng)構(gòu)建 Web Components 組件時(shí)它總是會(huì)被禁用 (樣式是 inline 的并注入到了 shadowRoot 中)。

當(dāng)作為一個(gè)庫構(gòu)建時(shí),你也可以將其設(shè)置為 false 免得用戶自己導(dǎo)入 CSS。

提取 CSS 在開發(fā)環(huán)境模式下是默認(rèn)不開啟的,因?yàn)樗?CSS 熱重載不兼容。然而,你仍然可以將這個(gè)值顯性地設(shè)置為 true 在所有情況下都強(qiáng)制提取。

  • 開發(fā)環(huán)境
    extractfalse,樣式內(nèi)嵌到 head 中。
    開發(fā)環(huán)境.png
  • 生產(chǎn)環(huán)境
    extracttrue,樣式分離,外鏈到 head 中。

形成兩個(gè)css文件:

app.[contetHash].css:vue組件抽離出來的css

chunk-vendors.[contentHash].css:第三方庫依賴的css

生產(chǎn)環(huán)境.png

內(nèi)部插件

不足

要么樣式全部內(nèi)嵌在head中導(dǎo)致html文件過大,要么外鏈,如果出現(xiàn)網(wǎng)絡(luò)問題,頁面白屏?xí)r間過長。

針對(duì)這一不足,我們看一下在vue客戶端項(xiàng)目中如何提取首屏渲染csscritical css。

提取critical css

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

critical-css-webpack-plugin

項(xiàng)目配置

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`傳遞配置對(duì)象
    inline: true,
    // type: string,讀取和寫入源的目錄
    base: resolve('dist'),
    // type: string,要操作的html源代碼,此選項(xiàng)優(yōu)先于src選項(xiàng)
    // html: '',
    // type: array,css路徑的數(shù)組
    // css: [],
    // type: string,要操作的html源代碼的位置
    src: 'index.html',
    // type: string,保存操作輸出的位置,如果要同時(shí)存儲(chǔ)`html`和`css`,使用`html`和`css`的對(duì)象
    target: 'index.html',
    // type: integer,1300,目標(biāo)視口的寬度
    width: 1300,
    // type: integer,900,目標(biāo)視口的高度
    height: 900,
    // type: array,包含寬度和高度的數(shù)組,如果設(shè)置,優(yōu)先于width和height選項(xiàng)
    dimensions: [],
    // type: boolean,是否壓縮生成的critical-path css
    minify: true,
    // type: boolean,小心使用,從html中刪除inline樣式,它會(huì)基于提取的內(nèi)容生成新的引用,因此可以安全地在多個(gè)html文件引用同一樣式文件。刪除每頁的關(guān)鍵css會(huì)為每個(gè)頁面生成唯一一個(gè)異步加載css。意味著你不能跨多頁面緩存
    extract: false,
    // type: boolean,inline圖片
    inlineImages: true,
    // type: array,內(nèi)聯(lián)程序開始查詢assets時(shí)的目錄/url列表
    assetPaths: [],
    // 設(shè)置base64內(nèi)聯(lián)圖片的最大大?。ㄒ宰止?jié)為單位)
    maxImageFileSize: 10240000,
    // type: object/function,critical嘗試相對(duì)文檔的assets path
    rebase: undefined,
    // type: array
    ignore: [],
    // type: string,獲取遠(yuǎn)程src時(shí)的用戶代理
    // userAgent: '',
    // type: object,penthouse的配置選項(xiàng)
    penthouse: {
        // propertiesToRemove: ['background'],
        // 強(qiáng)制包含的selector
        forceInclude: ['.card', '.card__list', '.card__main', '.card__img', '.card__article'],
        forceExclude: []
    },
    // type: object,got的配置選項(xiàng)
    request: {},
    // type: string,RFC2617授權(quán):user
    user: undefined,
    // type: string,RFC2617授權(quán):pass
    pass: undefined,
    // type: boolean,如果找不到css,則拋出錯(cuò)誤
    strict: false
};

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

配置完畢后,執(zhí)行npm run build構(gòu)建,查看dist/index.html,可以看到提取的critical css插入到head中,剩余css仍以外鏈形式引入。

這樣index.html文件也不會(huì)很大,也可以保證在網(wǎng)絡(luò)不穩(wěn)定時(shí),顯示簡單頁面樣式。

image.png

critical-css-webpack-plugin插件的核心是critical,critical核心使用penthouse,接下來再詳解一下criticalpenthouse。

critical插件

critical插件介紹,使用到核心組件庫penthouse。

html中提取critical css,并將critical-path內(nèi)聯(lián)到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環(huán)境下執(zhí)行配置文件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介紹

關(guān)鍵路徑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

對(duì)應(yīng)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服務(wù)端提取Critical css

介紹

簡介

SSR服務(wù)端渲染時(shí),管理 CSS 的推薦方法是簡單地使用 *.vue 單個(gè)文件組件內(nèi)的<style>,它提供:

  • 與 HTML 并列同級(jí),組件作用域 CSS
  • 能夠使用預(yù)處理器(pre-processor)或 PostCSS
  • 開發(fā)過程中熱重載(hot-reload)

更重要的是,vue-style-loadervue-loader 內(nèi)部使用的 loader),具備一些服務(wù)器端渲染的特殊功能:

  • 客戶端和服務(wù)器端的通用編程體驗(yàn)。

  • 在使用 bundleRenderer 時(shí),自動(dòng)注入關(guān)鍵 CSS(critical CSS)。

  • 如果在服務(wù)器端渲染期間使用,可以在 HTML 中收集和內(nèi)聯(lián)(使用 template 選項(xiàng)時(shí)自動(dòng)處理)組件的 CSS。在客戶端,當(dāng)?shù)谝淮问褂迷摻M件時(shí),vue-style-loader 會(huì)檢查這個(gè)組件是否已經(jīng)具有服務(wù)器內(nèi)聯(lián)(server-inlined)的 CSS - 如果沒有,CSS 將通過 <style> 標(biāo)簽動(dòng)態(tài)注入。

demo示例

pages/index.vue為首屏渲染頁面

<template>
    <div class="index">首頁</div>
</template>
<style>
.index {
    color: red;
}
</style>

新建pages/test.vue頁面,驗(yàn)證SSR是否會(huì)自動(dòng)注入關(guān)鍵css(critical css

<template>
    <div class="test">測試</div>
</template>
<style>
.test {
    color: red;
}
</style>
  1. index.vue中引入test.vue,服務(wù)啟動(dòng)后,test.vue樣式也以style形式內(nèi)嵌在頁面中
  2. 不在index.vue中引入test.vue,服務(wù)啟動(dòng)后,test.vue樣式則沒有內(nèi)嵌在首屏渲染頁面中

總結(jié):SSR服務(wù)端會(huì)自動(dòng)注入首屏渲染關(guān)鍵css,無需引入其他插件。

提取CSS

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

SSR可通過extractCSS將css提取到獨(dú)立的文件中,方便緩存。

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

總結(jié)

  • 客戶端和服務(wù)端均可通過extract提取css至單獨(dú)文件中,以外鏈形式引入
  • 客戶端只可內(nèi)嵌csshead中,或提取成單獨(dú)文件外鏈引入,不可提取critical css,需要增加額外webpack plugin來提取
  • 服務(wù)端自動(dòng)注入critical css,不需額外引入其他插件

參考文檔

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容