在前端的世界中,我们经常会站在巨人的肩膀上,如果任何事情都需要自己从零开始动手做,後续的维护也会耗费可观的成本。例如想要一个好用的 UI framework,有 Material UI、Ant Design、Chakra 、 Bootstrap 等以上几种常见的选择;想要方便的 utility CSS framework,最热门的选项不外乎是 Tailwind。
但是在设定这些 framework 时通常都需要引入整包的套件,像是我们只想要使用部分 Tailwind 的功能,但是明明很多功能都用不到,却在客户端载入异常庞大的 CSS 档案,对於使用者的体验也会不好。
在这篇文章中我们想要尝试在 Next.js 中导入 Ant Design 与 Tailwind 两个套件,然後在 Next.js 使用 postCSS 设定 purge CSS,达到在打包时移除没用到的 CSS,避免客户端必须载入无用的 CSS 。
在使用 Ant Design 时,我们可能会想修改它预设的 theme,而要修改 Ant Design 的 theme 要透过修改 less 的变数才能达成,但是在 Next.js 中目前还没有内建支援 less 的 CSS 档案格式,不过支援 less 的 PR#23185 已经在路上了,我们可以耐心等待有一天这支 PR 被 merge ?。
在还没支援 less 以前,我们需要手动修改一些 next.config.js
的设定,首先安装以下几个套件:
yarn add antd next-compose-plugins next-with-less less less-loader
然後,我们修改 next.config.js
的档案内容,把 Ant Design 的 primary-color
跟 border-radius-base
修改成客制化的样式:
// next.config.js
const withPlugins = require("next-compose-plugins");
const withLess = require("next-with-less");
const plugins = [
[
withLess,
{
lessLoaderOptions: {
lessOptions: {
modifyVars: {
"primary-color": "#00ccb4",
"border-radius-base": "4px",
},
},
},
},
],
];
module.exports = withPlugins(plugins, {
reactStrictMode: true,
});
然後,为了在专案中能够使用 Ant Design 的样式,我们需要在 pages/_app.tsx
中引入 antd.less
这个档案,这样才能让专案全域都可以拿到 Ant Design 的样式:
// _app.tsx
import type { AppProps } from "next/app";
import "antd/dist/antd.less";
function MyApp({ Component, pageProps }: AppProps) {
return <Component {...pageProps} />;
}
export default MyApp;
最後,测试看看 Ant design 的预设元件 theme 是不是已经被修改,在一个页面中使用「按钮元件」,因为 primary-color
跟 border-radius-base
都被新的设定覆盖,所以你在画面上就可以看到修改预设 theme 後的元件。
import { NextPage } from "next";
import { Button } from "antd";
const Home: NextPage = () => {
return <Button type="primary">my button</Button>;
};
export default Home;
接下来我们要在 Next.js 中设定 Tailwind,在 Next.js v10 以上的版本要使用以下指令安装 Tailwind:
yarn add -D tailwindcss@latest postcss@latest autoprefixer@latest
接着,再使用以下指令初始化 Tailwind 的环境,以下指令会在专案中产生 tailwind.config.js
与 postcss.config.js
两个档案:
npx tailwindcss init -p
从 Tailwind 官方网站中看到以上指令会在 postcss.config.js
中新增 tailwindcss
与 autoprefixer
两个 plugins
,而且两个值都为空物件 {}
,但是我们在这篇文章中不需要做额外的客制化设定,在这里可以直接在 plugins
的阵列中直接加入两个参数:
// postcss.config.js
module.exports = {
plugins: ["tailwindcss", "autoprefixer"],
};
然後我们在修改 pages/index.js
中的内容来测试 Tailwind 是否设定成功,简单地在 <Button />
这个元件上设定 m-8
,代表 margin: 2rem
的意思:
import { Button } from "antd";
const Home = () => {
return (
<Button className="sm:m-16 m-8" type="primary">
my button
</Button>
);
};
export default Home;
最後你应该可以在画面上看到 <Button />
的 margin
成功地被设置,原本紧贴在萤幕边缘的按钮,现在多了一些间距:
想要测试真实环境下每个页面会载入的 CSS 档案大小,必须事先 yarn build
及 yarn start
,如此一来才能准确地看到 CSS 档案被额外地载入,如果只是开启 dev server,CSS 只会被插入在 JavaScript 里面,无法准确地知道 CSS 档案的大小。
在 yarn start
之後,从 Chrome → Network → CSS 中可以看到有一包 CSS 档案被载入,从画面中可以看到其大小为 380 kB,是一个不小的数字,明明只有用到一个 Ant Design 的按钮元件, 也只有用到 Tailwind 的 m-8
这个 CSS selector 而已,理应是一个不大的档案大小才对。
而且如果每次使用者进入到一个页面都需要载入这麽大的档案,对於网路传输较慢的使用者将会是一场折磨。
所以为了解决这个问题,我们需要使用 purge CSS 将使用不到的 CSS 从最终的 CSS bundle 中移除。根据官方的说明,使用以下指令安装所需要的套件:
yarn add @fullhuman/postcss-purgecss postcss-flexbugs-fixes postcss-preset-env
然後在 postcss.config.js
中加上一些额外的设定,让 purge CSS 可以为我们工作:
module.exports = {
plugins: [
"tailwindcss",
"autoprefixer",
"postcss-flexbugs-fixes",
[
"postcss-preset-env",
{
autoprefixer: {
flexbox: "no-2009",
},
stage: 3,
features: {
"custom-properties": false,
},
},
],
[
"@fullhuman/postcss-purgecss",
{
content: [
"./pages/**/*.{js,jsx,ts,tsx}",
"./components/**/*.{js,jsx,ts,tsx}",
],
defaultExtractor: (content) => content.match(/[\w-/:]+(?<!:)/g) || [],
safelist: ["html", "body"],
},
],
],
};
可是如同上面一样操作,在 yarn build
及 yarn start
後看到在页面中载入的档案大小已经缩小为 2.7 kB,但是画面中的按钮样式全都不见了:
会发生这个问题的主要原因是 Ant Design 的 CSS selector 较难以判定,如果使用上面看到的 defaultExtractor
便无法顺利地萃取出正确的 selector,因此就会不小心删掉原本不该删掉的 selector,最後导致看到的按钮样式与预期中的不一样。
为了解决在 Ant Design 中能够正确地使用 purge CSS,在 issue#172 中有一个较为正确的解决方案,可以额外在 content
中使用 glob
寻找在 node_modules/antd/es
这个资料夹里面所有的 CSS 档案,让 purge CSS 在执行时不会把 Ant Design 的 CSS 都删掉:
const glob = require("glob");
...glob.sync("node_modules/antd/es/**/*.css", { noDir: true })
此外,还需要加上一个 extractor
能够正常萃取出 Ant Design 的 CSS selector:
extractors: [
{
extractor: (content) => content.match(/([a-zA-Z-]+)(?= {)/g) || [],
extensions: ["css"],
},
],
再设定完後,同样地,再次 yarn build
与 yarn start
让 Next.js 将 CSS 打包成独立的档案,方便我们观察最後的结果。在浏览器中应该可以看到按钮的样式没有被移除,但是 CSS 的档案大小增加为 40.6 kB,如果仔细看看这个档案中的内容会发现里面多了不少没有使用到的 CSS,也许这个 extractor
还有调整的空间。
在这篇文章中我们了解了如何在 Next.js 使用 Ant Design 与 Tailwind,而搭配 purge CSS 可以有效地降低 CSS 的档案大小,将档案大小从 380 kB 降低为 40.6 kB。然而,以上是的设定是根据 purge CSS 的官方文件所设定的,不知道还有没有更好的 extractor
,可以更准确地移除无用的 CSS。
<<: Day 26: Insertion sort & Selection sort
>>: Day 26 战斗民族-俄罗斯酸奶牛肉 Beef Stroganoff
传值(Call by value) 在 JavaScript 中,只有原始型别为传值(Call by...
昨天被讨薪水,今天还在躲 ... 唉, 所以今天就不收作业了。 (兔导今天回学校兼课,带即将毕业的...
206. Reverse Linked List https://leetcode.com/prob...
前面我们介绍了如何使用探索性分析(EDA)来观察资料的型态,也学会用图表来找出这些资料的潜在讯息,今...
但是老师教我用var宣告变数,但我也看到有同学用 let 与 const 宣告变数,这是怎麽一回事...