iT邦幫忙

2021 iThome 鐵人賽

DAY 15
2
Modern Web

排版神器 Tailwind CSS~和兔兔一起快速上手漂亮的元件開發!系列 第 16

Day 15:「你真的不減肥嗎...?」- Tailwind 的生產環境優化

Day15-Banner-not-yet

兔大媽:
「百貨公司在跳樓...大!拍!賣!!!(口水)」
「趕快來去搶!!!」

(兔大媽掏出了小卡進行一番熱血的戰鬥)

兔大媽:
「哇,害啊,買太多提不回家了...」
「打電話叫鵝籽來幫我提好了」

(十分鐘後...)

兔鵝籽:
「吼! 媽 啊你買那麼多東西,最後還不是放到過期!」
「買有需要的就好了啦~趁現在才剛買,還能退貨」
「我們,該來幫這購物袋大減肥了!」
 

carrotPoint 購物袋

今天一樣還是要用到我們之前在本地端安裝的 Tailwind 專案。

不過今天的生產環境優化的操作是無法在 Playground 中完成的。

因為 Playground 就是讓你操作新功能,以及示範、還有發問時用的,而不是用來完成你專案中實際使用的項目。

如果你的購物袋還是空的,在這裡把它裝滿:專案範本
(這專案的內容與 Day 14 完成後的內容相同)
 

可以齁,要開始退貨囉!
 

carrotPoint 生產環境優化

因為啊,Tailwind 編譯出來的 css 檔實在太大太大了! 這如果在正式環境上線的話,每次瀏覽一來一回造成的流量不小,而且正因為 css 檔太大,所以也會拖垮了整個頁面載入的速度

如果你去仔細觀察,不難發現編譯完的 style.css ...

對,就是這麼胖這麼肥,高達 4 MB
這個在正式環境上使用的瀏覽速度 ...

嗯 ... 真的慢的很可怕。
所以我們要來了解一下 Tailwind 原本的設計意圖

Tailwind 起初的設計概念就是在開發階段提供完整的所有可用的 class,讓你開發方便不需一直重新編譯。

然後到了要正式上線前,再透過 Tree-Shake 把未用到的樣式移除。

所謂 Tree-Shake 的概念就是去用力的搖晃一棵樹使其震動,而這時候會因為樹的搖晃而飄落下來的樹葉就是已經沒有生命力、原本就該掉的樹葉。

你可以把 Tailwind 想像成一大箱樂高,將其傾倒至地上後取出需要的部分來組合,完成後再將沒有用到的積木通通放回去箱子裡。

如此一來就可以完全理解一開始檔案這麼大的目的了。
接著我們來實際的操作一遍!
 

carrotPoint Purge 設定

一開始的配置檔 tailwind.config.js 中,我們可以看到 purge 的設定是空的:

module.exports = {
  purge: [],
  ...
}

這個 purge 的陣列之中,要加上我們想要檢查的檔案,那麼在 Tailwind 編譯時,就會去檢查檔案之中所用到的 class。

只有一個頁面

而目前我們也只有 index.html 一個頁面,所以我們可以這麼做就好:

module.exports = {
  purge: ["./index.html"],
  ...
}

多個頁面或資料夾

但為了以防我們之後會有其他的頁面或資料夾,也可以選擇這樣設定。

module.exports = {
  purge: [
    "./*.html",
    "./**/*.html",
  ],
  ...
}

把 JS 也算進去

如果你會在 js 中使用到 Tailwind 的 class,那也請把 js 加入 purge 的監聽列表。 我們可以一次設定多個副檔名:

module.exports = {
  purge: [
    "./*.{html,js}",
    "./**/*.{html,js}",
  ],
  ...
}

其實應該根據專案結構做細部的設定,但這邊不多加贅述;但不論是怎麼樣的結構,要給 purge 選項監聽的路徑格式都應該要符合規範

 

carrotPoint 重新編譯

既然有設定 purge 要清除的檔案範圍,我們就來重新編譯試試看效果吧! 一樣是這行執行過很多次的指令:

npm run build

編譯完後會發現,大小根本完全都沒有改變

「兔兔!哩喜咧裝肖維嗎!」

沒事,不要著急,一切都在我的掌控之中。 ?

我們剛剛也說過,
這是原本就是預計在正式環境上線才會使用的。
所以啊~現在沒有任何反應是正常的!

因為現在專案本身的環境還不是 production 呀,
所以若是把專案的 NODE_ENV 設定為 production,
在編譯 Tailwind 時,purge 選項就會自動生效囉!

不過我們這邊不設定 NODE_ENV,我們來改用別的方式達成。

手動啟動

purge 選項要生效,不僅可以透過專案的環境狀態來選擇是否要 Tree-Shake,也能夠設定手動開啟。

我們把 purge 選項改成這個樣子:

module.exports = {
  purge: {
    enabled: true, // true: 開啟 / false: 關閉
    content: [
      "./*.{html,js}",
      "./**/*.{html,js}",
    ]
  },
  ...
}

這麼一來,我們在編譯時,purge 若是設定為開啟,就會進行 Tree-Shake。

我們再來重新編譯一次試試看。

npm run build

編譯完之後 ... 檔案大小 降到 33KB 了,
而實際上速度也會比編譯完整檔案再更快一些。

「傑克!」
不對 ... 是 「兔兔!這真是太神奇了」

不過,兔兔其實想跟你們說聲不好意思,因為啊上次專案結尾是新增了一個新的、套用 box 元件樣式的方塊,可是顏色都沒有調整,所以我們就來對那個方塊做細部設定吧!
 

carrotPoint 樣式調整

讓我們把場景快速切換到 index.html,來幫第三個方塊新增顏色。依照前兩個方塊以此類推,把第三個方塊設定為黃色的:

<div class="flex justify-evenly p-10 focus-within:bg-green-100 group">
  <box class="box bg-red-500 hover:bg-red-400 ring-red-300" tabindex="0">
    1
  </box>
  <box class="box bg-blue-500 hover:bg-blue-400 ring-blue-300" tabindex="1">
    2
  </box>

  <box class="box bg-yellow-500 hover:bg-yellow-400 ring-yellow-300" tabindex="2">
    3
  </box>
</div>

有規範過的 class 樣式改起來就是如此的輕鬆簡單,
我們來看看畫面吧:

「... 兔兔 ...!又是你的鍋嗎!?」

ㄟ,這你可就誤會大囉!
枉費我用心良苦鋪陳到這裡,哼哼~~

為什麼樣式沒有上去呢?
因為我們在編譯前沒有用到這個顏色,所以被移除了呀!

前面說過,Tailwind 一開始的設計理念就是樣式全部編譯,到了要上線時再減少樣式,那當然你現在多寫什麼,就沒有什麼,因為你必須重新編譯!

不過就可以趁機會提到這個有趣的設定。

如果你會需要在生產環境後臨時改變顏色間距等等的樣式,或是透過 js 動態改變主題顏色的話,接下來要講的這個設定很適合哦!
 

carrotPoint 安全名單 (Safe List)

看到名字就知道,顧名思義就是設定一個安全名單,讓 Tailwind 在移除樣式時略過他們,舉例:

module.exports = {
  purge: {
    enabled: true, // true: 開啟 / false: 關閉
    content: [
      "./*.{html,js}",
      "./**/*.{html,js}",
    ],
    safelist: [
      'bg-blue-500',
      'text-center',
      'hover:opacity-100',
      // ...
      'lg:text-right',
    ]
  },
  ...
}

但是這個方法需要把 class 一個一個定義清楚,如果想要一個範圍或大量定義的話,現在這個 safelist 的寫法是不適合的,我們必須要使用正規表達式來完成。

若把 safelist 直接寫在 purge 之中,那麼 safelist 裡面只接受字串格式,不接受你在裡面寫 regex。 如果想要用 regex 必須將 safelist 寫在 purge 的 options 參數中。

依照我們的設定,我們希望它之後即使不重新編譯仍然也可以臨時改變顏色,而我們有用到的顏色種類是背景顏色 bg-* 和外框顏色 ring-*,所以我們的正規表達式必須包含這兩種:

/(bg|ring)-(.*)-(\d{1}0{1,2})/

準備好 Regex,我們就可以把它加到設定中:

module.exports = {
  purge: {
    enabled: true, // true: 開啟 / false: 關閉
    content: [
      "./*.{html,js}",
      "./**/*.{html,js}",
    ],
    options: {
      safelist: [/(bg|ring)-(.*)-(\d{1}0{1,2})/]
    }
  },
  ...
}

接著再重新編譯 ... 編譯完馬上來看結果

npm run build

現在變成黃色了,那我們不要編譯,直接改成綠色呢?

<div class="flex justify-evenly p-10 focus-within:bg-green-100 group">
  <box class="box bg-red-500 hover:bg-red-400 ring-red-300" tabindex="0">
    1
  </box>
  <box class="box bg-blue-500 hover:bg-blue-400 ring-blue-300" tabindex="1">
    2
  </box>

  <box class="box bg-green-500 hover:bg-green-400 ring-green-300" tabindex="2">
    3
  </box>
</div>

直接儲存後馬上看結果:

OK 的,生效了! 所以未來你也可以透過類似的手法,讓特定類別的 class 就算未使用也不要被清除掉。

那這次就是真的完成囉~
這個作業 應該 不會再用到了吧?
 

兔鵝籽:
「媽~貨都退完了」

兔大媽:
「貨退完了齁,真的變很小袋餒。」
「啊我看一下還剩什麼...」(翻袋子)
「這個不是說也要退掉,怎麼沒退到?」

兔鵝籽:
「哦,爸說那種的都可以留著啦,因為那是消耗品」

兔大媽:
「齁 ... 是這樣子喔,好啦那我們可以回家了齁」

兔鵝籽:
「對,可以了。媽我車停那邊,我們過去那裏」

(漸行漸遠)

(兔大媽:「怎麼覺得還是很重餒 ...」)
 

carrotPoint 給你們的回家作業:


關於兔兔們:


 


( # 兔兔小聲說 )

兔兔有一天撿到一個神燈 ...
 
神燈:
「有智慧的兔子啊! 給你實現一個願望的機會!」
「許願吧!」

兔兔:
「神燈啊神燈!」
「希望我死前,能找到適合自己的紅蘿蔔!」
 
 
 
於是兔兔就獲得了永生。


上一篇
Day 14:「怎麼跟阿嬤的裹腳布一樣啦!」- 提取成元件
下一篇
Day 16:「寶藏,都藏在那裡了!」- Tailwind JIT 模式
系列文
排版神器 Tailwind CSS~和兔兔一起快速上手漂亮的元件開發!32

尚未有邦友留言

立即登入留言