杜郎俊赏 - dujun.io

CleanCSS - 移除未使用的 CSS 代码

应用:CleanCSS
地址:https://dujun.eu.org/cleancss
功能:分析页面中引用的 CSS 文件,打包成单一的干净文件用于替换所有引用
适用:独立页面


一、缘起

我导航站用了开源项目WebStackPage,首次静态资源加载有 1.5M,一部分原因是它使用了第三方库,比如 Bootstrap。当然,第三方库只有少量代码实际被用到,所以我就想找个办法,把未使用的 CSS 代码移除,使得静态文件更小。

二、方案

很快就找到了这个网站https://unused-css.com/。它可以很好地实现我的需求,不过有一个小问题,它是收费的,最低 25 美元一个月。

Only paying users can download clean CSS files.

那怎么办呢?那就自己开发一个工具吧。

三、分析

清理 CSS 代码需要这么几步:

  • 抓取页面 HTML 内容
  • 找到页面引用的 CSS、JS 文件
  • 分析 HTML、JS 文件中用到的样式
  • 保留被用到的代码,打包成单一 CSS 文件

分别用到了下列工具:

(一) Puppeteer

使用 Puppeteer 抓取 HTML 原文和 CSS、JS 文件列表。示例代码如下:

const
    puppeteer = require('puppeteer');

(async () => {
    const browser = await puppeteer.launch({
        args: [
            '--disable-gpu',
            '--disable-dev-shm-usage',
            '--disable-setuid-sandbox',
            '--no-first-run',
            '--no-sandbox',
            '--no-zygote',
            '--single-process'
        ]
    });

    const page = await browser.newPage();

    await Promise.all([
        page.coverage.startJSCoverage(),
        page.coverage.startCSSCoverage(),
    ]);

    await page.goto(fetchUrl, {'timeout': 30000, 'waitUntil': 'domcontentloaded'});

    let html = await page.content();

    const [jsCoverage, cssCoverage] = await Promise.all([
        page.coverage.stopJSCoverage(),
        page.coverage.stopCSSCoverage(),
    ]);

    await browser.close();

    console.log(JSON.stringify({html: html, js: jsCoverage, css: cssCoverage}));
})();

(二)purifycss

使用 purifycss 移除未使用的 CSS 代码。示例如下:

purifycss src/css/main.css src/css/bootstrap.css src/js/main.js --info --out src/dist/index.css

(三)csso

最后使用 csso 压缩。示例代码如下:

gulp.task('css', () =>
    gulp.src(sourceFile)
        .pipe(stylelint({
            reporters: [
                {formatter: 'string', console: true}
            ],
            failAfterError: false
        }))
        .pipe(autoprefixer( //增加浏览器兼容前缀
            {
                overrideBrowserslist: ['> 5%', 'not dead']
            }))
        .pipe(cssMediaGroup())
        .pipe(csso()) //压缩优化
        .pipe(gulp.dest(targetDir)));

四、成果

以分析十年之约页面为例:

五、后记

(一)只支持明文调用

只能支持明文 CSS 代码调用的解析,例如:

$e.addClass('myClass');

不支持字面量表达式等调用,例如:

$e.addClass('my' + 'Class');

(二)执行开销较大

服务器配置低,执行较慢,需要耐心等待。

标签: 开发 前端 应用
日期:2022-10-31