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 3 | Dart 基本介绍 - Dart vs JS

>>:  Day1 後端及PHP介绍

CDB(集中式) 是什麽? DDB(分散式)是什麽?

分散资料库(Distributed Database, DDB) VS 集中式资料库(Central...

怎么恢复安卓系统被删除的短信呢?

您可能会因为错误的点击而意外删除重要的短信,或者在恢复出厂设置、系统崩溃、Android 更新、ro...

D25 - 走!去浏览器吃饼乾 yummy yummy!

前言 今天来学元素的 classList,一口一口吃饼乾 yummy yummy! Codepen ...

【把玩Azure DevOps】Day2 Azure DevOps介绍

DevOps是近几年很热门的关键字和技术,微软在这个部份自然也不会缺席,只是过往的产品名称并不是叫「...

Day 2. Pre-Start × WYSIWYG

那个 W 开头的 你是不是看我书读得少,想随便拿一串英文符号呼隆我? 这误会可不是普通的小啊!必须...