静态负载均衡和动态负载均衡

by Sarah Dayan

通过莎拉·达扬

(How I dropped 250KB of dead CSS weight with PurgeCSS)

I’m a big advocate for utility-first CSS. After trying several methods over the years, it’s what I’ve found to be the best, most maintainable and scalable way of writing CSS to this day.

我是实用程序优先CSS的大力倡导者 。 经过多年的尝试,我发现这是迄今为止编写CSS的最佳,最可维护和可扩展的方法 。

When my coworker Clément Denoix and I built api-search.io, I decided to use Tailwind CSS to style it. Tailwind CSS is a theme-agnostic, fully customizable, utility-first library.

当我的同事ClémentDenoix和我构建api-search.io时 ,我决定使用Tailwind CSS对其进行样式设置。 Tailwind CSS是一个与主题无关的,完全可自定义的,实用程序优先的库。

The whole point of a library is to give you access to a broad set of tools to use at will. The problem is, since you usually use only a subset of it, you end up with a lot of unused CSS rules in your final build.

库的全部目的是使您可以随意使用各种工具。 问题是,由于通常只使用其中的一部分,所以最终构建中最终会使用许多未使用CSS规则 。

In my case, not only did I load the entire Tailwind CSS library, but I also added several variants to some modules. That ended up making the final minified CSS file weight 259 KB (before GZip). That’s quite heavy when you consider that the website is a simple single-page app with a minimal design.

就我而言,不仅加载了整个Tailwind CSS库,而且还向某些模块添加了一些变体。 这样最终使最终的最小CSS文件重量为259 KB (在GZip之前)。 当您认为该网站是具有最小设计的简单单页应用程序时,这非常繁琐。

You don’t want to load each utility by hand when you need it. That would be a long and cumbersome task. A better scenario is to have everything at your disposal during development and automatically remove what you didn’t use during the build step.

您不想在需要时手动加载每个实用程序。 那将是一个漫长而繁琐的任务。 更好的方案是在开发过程中可以使用所有内容,并自动删除构建步骤中未使用的内容 。

In JavaScript, we call it tree-shaking. Now, thanks to PurgeCSS, you can do the same with your CSS codebase.

在JavaScript中,我们称其为tree-shaking 。 现在,感谢PurgeCSS , 您可以对CSS代码库执行相同的操作 。

PurgeCSS analyzes your content files and your CSS, then matches the selectors together. If it doesn’t find any occurrence of a selector in the content, it removes it from the CSS file.

PurgeCSS分析您的内容文件和CSS,然后将选择器匹配在一起。 如果在内容中未发现选择器,则会将其从CSS文件中删除。

For the most part, this can work out of the box. However, there are some areas in any website that may require some more thinking before letting PurgeCSS do its magic.

在大多数情况下, 这可以立即使用 。 但是,在任何网站上都有某些区域可能需要更多思考才能让PurgeCSS发挥作用。

(Splitting my CSS)

The project contains three main CSS files:

该项目包含三个主要CSS文件:

  • A CSS reset called normalize.css, included in Tailwind CSS. Tailwind CSS中包含一个CSS重置,称为normalize.css 。
  • Tailwind CSS, the most substantial part of my CSS codebase. Tailwind CSS ,这是我CSS代码库中最重要的部分。
  • Some custom CSS, mostly for styling the InstantSearch components to which I couldn’t add classes. 一些自定义CSS,主要用于设置无法添加类的InstantSearch组件的样式。

PurgeCSS can’t detect that I need to keep selectors such as .ais-Highlight, because the components that use it only show up in the DOM at runtime. Same goes with normalize.css: I’m relying on it to reset browser styles, but many of the related components will never be matched because they’re generated in JavaScript.

PurgeCSS无法检测到我需要保留选择器,例如.ais-Highlight , 因为使用它的组件仅在运行时显示在DOM中 。 normalize.css :我依靠它来重置浏览器样式,但是许多相关组件永远不会匹配,因为它们是用JavaScript生成的。

In the case of classes starting with .ais-, we can sort them out with whitelisting. Now when it comes to reset styles, selectors are a bit trickier to track down. Plus, the size of normalize.css is pretty insignificant and isn’t bound to change. So in this case, I decided to ignore the file altogether. Consequently, I had to split styles before running PurgeCSS.

对于以.ais-开头的类,我们可以将其列入白名单 。 现在,当涉及到重置样式时,选择器要追踪起来有些棘手。 另外, normalize.css的大小是微不足道的,并且不会更改。 因此,在这种情况下,我决定完全忽略该文件。 因此, 在运行PurgeCSS之前 , 我不得不拆分样式 。

My initial CSS configuration looked like this:

我最初CSS配置如下所示:

  • A tailwind.src.css file with three @tailwind directives: preflight, components and utilities. 一个tailwind.src.css文件有三个@tailwind指令: preflight , components和utilities 。
  • An App.css file with my custom styles. 具有我的自定义样式的App.css文件。
  • An npm script in package.json to build Tailwind CSS right before starting or building the project. Every time this script runs, it outputs a tailwind.css file in src, which is loaded in the project. package.json一个npm脚本,用于在开始或构建项目之前立即构建Tailwind CSS。 每次运行此脚本时,它将在src输出一个tailwind.css文件,该文件已加载到项目中。

The @tailwind preflight directive loads normalize.css. I didn’t want PurgeCSS to touch it, so I moved it to a separate file.

@tailwind preflight指令会加载normalize.css 。 我不希望PurgeCSS对其进行操作,因此将其移至单独的文件中。

// tailwind.src.css @tailwind components;
@tailwind utilities;/* normalize.src.css */ @tailwind preflight;

Then, I changed my existing tailwind script in package.json to build normalize.src.css separately.

然后,我更改了package.json现有的tailwind脚本,以分别构建normalize.src.css 。

{  "scripts": {    "tailwind": "npm run tailwind:normalize && npm run tailwind:css",    "tailwind:normalize": "tailwind build src/normalize.src.css -c tailwind.js -o src/normalize.css",    "tailwind:css": "tailwind build src/tailwind.src.css -c tailwind.js -o src/tailwind.css"  }}

Finally, I loaded normalize.css in the project.

最后,我在项目中加载了normalize.css 。

// src/index.js
...import './normalize.css'import './tailwind.css'import App from './App'...

Now, I can run PurgeCSS on tailwind.css without fearing it might strip down needed rulesets.

现在,我可以在运行PurgeCSS tailwind.css而不必担心它可能会剥离下来所需的规则集。

(Configuring PurgeCSS)

PurgeCSS comes in many flavors: a command-line interface, a JavaScript API, wrappers for Webpack, Gulp, Rollup, and so on.

PurgeCSS有多种风格:命令行界面,JavaScript API,Webpack包装,Gulp,Rollup等。

We used Create React App to bootstrap the website, so Webpack came preconfigured and hidden behind react-scripts. This means I couldn’t access Webpack configuration files unless I ran npm run eject to get them back and manage them directly in the project.

我们使用Create React App引导网站,因此Webpack已预先配置并隐藏在react-scripts后面。 这意味着除非我运行npm run eject exit取回它们并直接在项目中管理它们,否则我将无法访问Webpack配置文件。

Not having to manage Webpack yourself has many advantages, so ejecting wasn’t an option. Instead, I decided to use a custom configuration file for PurgeCSS, and an npm script.

不必自己管理Webpack具有许多优点,因此退出不是一种选择。 相反,我决定为PurgeCSS使用一个自定义配置文件和一个npm脚本。

I first created a purgecss.config.js at the root of the project:

我首先在项目的根目录创建了purgecss.config.js :

module.exports = {  content: ['src/App.js'],  css: ['src/tailwind.css']}
  • The content property takes an array of files to analyze to match CSS selectors. content属性采用文件数组进行分析以匹配CSS选择器。
  • The css property takes an array of stylesheets to purge. css属性需要清除样式表数组。

Then, I edited my npm scripts to run PurgeCSS:

然后,我编辑了npm脚本以运行PurgeCSS:

{  "scripts": {    "start": "npm run css && react-scripts start",    "build": "npm run css && react-scripts build",    "css": "npm run tailwind && npm run purgecss",    "purgecss": "purgecss -c purgecss.config.js -o src"  }}
  • I added a purgecss script that takes my configuration file and outputs the purged stylesheet in src. 我添加了一个purgecss脚本,该脚本获取我的配置文件并在src输出清除的样式表。
  • I made this script run every time we start or build the project.

Tailwind CSS uses special characters, so if you use PurgeCSS out of the box, it may remove necessary selectors. Fortunately, PurgeCSS allows us to use a custom extractor, which is a function that lists out the selectors used in a file. For Tailwind, I needed to create a custom one:

Tailwind CSS使用特殊字符,因此,如果您直接使用PurgeCSS,则它可能会删除必要的选择器。 幸运的是,PurgeCSS允许我们使用自定义提取器 ,该函数可列出文件中使用的选择器。 对于Tailwind,我需要创建一个自定义的 :

module.exports = {  ...  extractors: [    {      extractor: class {        static extract(content) {          return content.match(/[A-z0-9-:\/]+/g) || []        },        extensions: ['js']      }    }  ]}

(Whitelisting runtime classes)

PurgeCSS can’t detect classes that are generated at runtime, but it lets you define a whitelist. The classes you whitelist remain in the final file no matter what.

PurgeCSS无法检测在运行时生成的类 ,但是它使您可以定义白名单。 无论您将白名单中的类保留在最终文件中。

The project uses React InstantSearch, which generates components with classes that all start with ais-. Conveniently, PurgeCSS supports patterns in the form of regular expressions.

该项目使用React InstantSearch ,它生成的组件都带有以ais-开头的类。 方便地,PurgeCSS支持以正则表达式形式的模式。

module.exports = {  ...  css: ['src/tailwind.css', 'src/App.css'],  whitelistPatterns: [/ais-.*/],  ...}

Now if I forget to remove a class that I no longer use from App.css, it will be taken out from the final build, but my InstantSearch selectors will remain safe.

现在,如果我忘记从App.css删除不再使用的App.css ,它将从最终版本中删除,但我的InstantSearch选择器将保持安全。

(New build, lighter CSS)

With this new configuration, my final CSS file has gone from 259 KB to…9 KB! It’s pretty significant in the context of a whole project, especially since many countries still have slow and unstable Internet, and more and more people browse on their phones while on the move.

有了这个新配置, 我的最终CSS文件已从259 KB变为…9 KB! 对于整个项目而言,这非常重要,尤其是因为许多国家/地区的互联网仍然缓慢且不稳定,并且越来越多的人在旅途中浏览手机。

Accessibility is also about catering for people with low bandwidth connections. It’s not acceptable not to try and help your users with slower Internet, especially if what you’re making them download is dead code.

可访问性还与满足低带宽连接的人们有关。 不尝试用较慢的Internet来帮助您的用户是不可接受的,特别是如果您要让他们下载的内容是无效代码。

That’s worth taking a moment to optimize your build. ?

值得花一点时间来优化您的构建。 ?

Originally published at frontstuff.io.

最初发布在frontstuff.io上 。

翻译自: https://www.freecodecamp.org/news/how-i-dropped-250kb-of-dead-css-weight-with-purgecss-28821049fb/

静态负载均衡和动态负载均衡