從Highlight淺談Webpack按需加載

動態(tài)加載CSS.gif

前言

最近有在使用 highlight.js 做代碼的高亮展示,主要是展示對 SQL 語言的處理粗悯。看了看 highlight.js 的提供的相關代碼

![2.png](https://upload-images.jianshu.io/upload_images/3995692-dc52856084af134e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

因為只需要加載對應語言的種類,以及一種樣式萧豆,所以我們希望 webpack 能夠按需加載

按需加載的實踐

完全加載

為了對比出按需加載究竟能幫助我們節(jié)約多少資源,我們先貼出沒有按需加載的代碼

// 忽略一些無關的代碼
import * as hljs from 'highlight.js/lib/highlight'
import 'highlight.js/styles/atom-one-light.css'

export class Highlight extends React.Component {

  public componentDidMount() {
    hljs.highlightBlock((this.code as any))
  }

  public render() {
    return (
      <pre ref={ref => this.code = ref} style={{marginTop: 20}}>
        <code>{this.props.content}</code>
      </pre>
    )
  }
}

這是一份完整的加載捞附,我們看看最后的數(shù)據(jù)有多大(包含完整引用的 antd 文件祝拯,我在項目中使用了 antd )

highlight-1.png

按需加載

接著我們按照官方的 demo 實現(xiàn)按需加載

import * as hljs from 'highlight.js/lib/highlight'
import * as javascript from 'highlight.js/lib/languages/javascript'
hljs.registerLanguage('javascript', javascript)

其他的部分和上文相同,區(qū)別在于温算,沒有從整個 highlight 中加載怜校,而是引用了部分文件以及需要注冊的 javascript 語言部分,默認是加載包含所有語言版本的 hljs 注竿,看看這下的打包大小

highlight-2.png

我們可以看到茄茁,使用按需加載將近節(jié)省了600KB的空間,而使用按需加載的引入方式是
import * as XXX from 'module/lib/xxx'巩割。并且使用 import { xx } from 'moduls' 并不能觸發(fā) webpack 的 treeshake裙顽,webpack仍然會打包完整庫,哪怕引用的僅僅是從庫里導出的接口(在ECharts下是如此表現(xiàn)的)宣谈。我們看看按需引用 antd 里的組件會是什么情況

部分按需引用

上面1.78MB的打包體積是 import { Card } from 'antd'(如gif效果圖愈犹,我用Card包裹了高亮組件),接著我們看看

import Card from 'antd/lib/card'

這種方式最后的打包體積

highlight-4.png

媽耶,居然這么小闻丑。

小結(jié)

  1. 如果要實現(xiàn)按需加載得使用babel-plugin-import,這個在TS下的情況還沒有檢查過
  2. 使用TS時漩怎,因為某些庫的 d.ts 文件 指向的路徑是模塊勋颖,因此要導入該庫的接口只能完整的導入該模塊,比如ECharts勋锤,這個問題目前暫時還未解決

動態(tài)加載的實踐

上面只是按需加載部分的JS饭玲,并且通過字符串寫死的方式指定了路徑,還有一部分怪得,如同CSS的部分需要在組件生成時動態(tài)加載咱枉,或者通過變量的形式加載。如下所示

  constructor(props) {
    super(props)
    require('highlight.js/styles/' + this.props.css)
  }

  static async getDerivedStateFromProps(nextProps) {
    // const css = await import('highlight.js/styles/' + nextProps.css)
    const css = require('highlight.js/styles/' + nextProps.css)
    console.log(css)
    return null
  }

我們在構(gòu)造階段通過props傳過來的變量加載對應的CSS文件徒恋,之前是使用import 'highlight.js/styles/atom-one-light.css'的方式蚕断,我們看看兩者打包體積的區(qū)別

highlight-css-1.png
highlight-css-2.png

通過指定加載的CSS體積大小是427KB,而動態(tài)加載的體積大小是484KB入挣。動態(tài)加載的體積要比靜態(tài)加載的體積大很多亿乳。分析一下webpack打包的行為

webpack始終結(jié)合關鍵字并按照靜態(tài)地址信息進行打包。比如require('highlight.js/styles/' + nextProps.css)
require是關鍵字径筏,接下來 webpack 會對 require 這個函數(shù)中的入?yún)⑦M行分析葛假,它會發(fā)現(xiàn)入?yún)⒂袃蓚€部分構(gòu)成, 一部分是硬編碼的 'highlight.js/styles/' 另一部分是不可知的變量滋恬。webpack將會以硬編碼部分為打包入口聊训,將'highlight.js/styles/*'下所有文件打包,在運行時根據(jù)完整的路徑記載資源恢氯。

所以我們沒辦法使用完全的變量 require(variable)带斑,因為這樣webpack找不到打包的路徑。

缺陷

效果圖雖然能看到我們通過 Select 的選擇按需加載 CSS 樣式勋拟,但其實是有缺陷的勋磕,表現(xiàn)為右側(cè)可以看到,動態(tài)加載的CSS是通過一個個style標簽加載上去的敢靡,這樣后面的樣式效果會覆蓋前面的挂滓。表現(xiàn)為 當 Select 又選到已經(jīng)加載的樣式時, 瀏覽器并不會重新加載那段代碼啸胧,導致樣式無效赶站。這個問題在另一個組件中得到了解決
react-syntax-highlighter

還沒來得及看具體的實現(xiàn),不過我估計應該是使用了 CSS-MODULES吓揪,明天再看看

沒來得及驗證的部分

有注意到 我在使用 const css = await import('xxx'),const css = require('xxx'),這兩者的表現(xiàn)上是有區(qū)別的亲怠,前者是一個Promise對象,后者直接返回了值柠辞,這就涉及到了一個同步和異步的問題,雖然最后打印出來都是 {}主胧, 不過這是因為沒有使用CSS modules的原因叭首。以后再研究研究 import require 動態(tài)加載時的區(qū)別

總結(jié)

  1. import { Card } from 'antd'并不會觸發(fā)按需加載,仍然會加載全部antd文件,應該使用import Card from 'antd/lib/Card'
  2. 使用變量加載require('highlight.js/styles/' + this.props.style) webpack會打包 'highlight.js/styles/*'下所有文件
  3. 猜想 在TS下即使只從某個庫里引用接口, import { IXxx } from 'xxx',webpack仍然會打包所有的 'xxx' 文件(在ECharts的表現(xiàn)下如此)

以上都是我瞎編的

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末习勤,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子焙格,更是在濱河造成了極大的恐慌图毕,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件眷唉,死亡現(xiàn)場離奇詭異予颤,居然都是意外死亡,警方通過查閱死者的電腦和手機冬阳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進店門蛤虐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人肝陪,你說我怎么就攤上這事驳庭。” “怎么了氯窍?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵饲常,是天一觀的道長。 經(jīng)常有香客問我狼讨,道長贝淤,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任政供,我火速辦了婚禮播聪,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘鲫骗。我一直安慰自己犬耻,他們只是感情好,可當我...
    茶點故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布执泰。 她就那樣靜靜地躺著枕磁,像睡著了一般。 火紅的嫁衣襯著肌膚如雪术吝。 梳的紋絲不亂的頭發(fā)上计济,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天,我揣著相機與錄音排苍,去河邊找鬼沦寂。 笑死,一個胖子當著我的面吹牛淘衙,可吹牛的內(nèi)容都是我干的传藏。 我是一名探鬼主播,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼毯侦!你這毒婦竟也來了哭靖?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤侈离,失蹤者是張志新(化名)和其女友劉穎试幽,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體卦碾,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡铺坞,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了洲胖。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片济榨。...
    茶點故事閱讀 39,696評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖宾濒,靈堂內(nèi)的尸體忽然破棺而出腿短,到底是詐尸還是另有隱情,我是刑警寧澤绘梦,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布橘忱,位于F島的核電站,受9級特大地震影響卸奉,放射性物質(zhì)發(fā)生泄漏钝诚。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一榄棵、第九天 我趴在偏房一處隱蔽的房頂上張望凝颇。 院中可真熱鬧,春花似錦疹鳄、人聲如沸拧略。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽垫蛆。三九已至,卻和暖如春腺怯,著一層夾襖步出監(jiān)牢的瞬間袱饭,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工呛占, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留虑乖,地道東北人。 一個月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓晾虑,卻偏偏與公主長得像疹味,于是被迫代替她去往敵國和親仅叫。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,592評論 2 353

推薦閱讀更多精彩內(nèi)容

  • 1 Webpack 1.1 概念簡介 1.1.1 WebPack是什么 1佛猛、一個打包工具 2惑芭、一個模塊加載工具 3...
    Kevin_Junbaozi閱讀 6,659評論 0 16
  • GitChat技術雜談 前言 本文較長坠狡,為了節(jié)省你的閱讀時間继找,在文前列寫作思路如下: 什么是 webpack,它要...
    蕭玄辭閱讀 12,689評論 7 110
  • 在現(xiàn)在的前端開發(fā)中逃沿,前后端分離婴渡、模塊化開發(fā)、版本控制凯亮、文件合并與壓縮边臼、mock數(shù)據(jù)等等一些原本后端的思想開始...
    Charlot閱讀 5,439評論 1 32
  • 學習流程 參考文檔:入門Webpack,看這篇就夠了Webpack for React 一. 簡單使用webpac...
    Jason_Zeng閱讀 3,134評論 2 16
  • 五一是游玩的時間假消,所以我和朋友便去玩柠并,開啟我們的旅程。 首先富拗,我們來到了天逸公園臼予,在一座橋上我們拍了一張照片。...
    自擇閱讀 25評論 0 0