Skip to content

He110te4m/unplugin-css-checker

Repository files navigation

English | 简体中文

CSS Pollution Checker Plugin

Installation

npm i -D unplugin-css-checker

Vite

// vite.config.ts
import CSSChecker from 'unplugin-css-checker/vite'

export default defineConfig({
  plugins: [
    CSSChecker({ /* options */ }),
  ],
})

Rollup

// rollup.config.js
import CSSChecker from 'unplugin-css-checker/rollup'

export default {
  plugins: [
    CSSChecker({ /* options */ }),
  ],
}

Webpack

// webpack.config.js
module.exports = {
  /* ... */
  plugins: [
    require('unplugin-css-checker/webpack')({ /* options */ })
  ]
}

Vue-cli

// vue.config.js
module.exports = {
  configureWebpack: {
    plugins: [
      require('unplugin-css-checker/webpack')({ /* options */ }),
    ],
  },
}

esbuild

// esbuild.config.js
import { build } from 'esbuild'
import CSSChecker from 'unplugin-css-checker/esbuild'

build({
  plugins: [CSSChecker()],
})

Usage Examples

import { defineConfig, loadEnv } from 'vite'
import { createVuePlugin } from 'vite-plugin-vue2'

export default defineConfig(({ mode, command }) => {
  const env = loadEnv(mode, process.cwd())
  const isDev = command === 'serve'

  return {
    plugins: [
      createVuePlugin(),
      cssChecker({
        // Declare when to enable plugin checking. Since this plugin will terminate the build if the check fails,
        // it's not recommended to set it to true directly to avoid affecting the build output
        // To avoid affecting the build output, this configuration defaults to false
        enable: isDev || !!env.VITE_CHECK_CSS,

        // Declare the project root directory, required
        projectRoot: __dirname,

        // Declare which file extensions to check, defaults to checking `.css`, `.pcss`, `.postcss`, `.less`, `.scss`, `.sass`
        suffixes: ['.css', '.pcss', '.postcss', '.less', '.scss', '.sass'],

        // Configure public styles, required
        immutables: {
          // Configure which files or directories are public styles
          libs: [
            // Declare sfv component library as public styles
            'node_modules/your-components/dist/themes',
            // Declare the global styles directory, will automatically read all files
            'src/style',
          ],

          // Manually specify public style class names
          selectors: ['el-lang'],

          // Declare which class names in public style files are not public styles
          excludeSelectors: [
            '.iconfont',
            /\[ant\]/,
          ],
        },

        // Declare which files to exclude from checking, if public styles are not globally injected, this needs to be configured
        excludeRules: [
          /windi\.css$/,
          /src[\\\/]style/,
        ],
      }),
    ],
  }
})

How It Works

Definition of a "rule": .sfv-btn { color: red; } is one rule, .sfv-btn, .custom-btn { color: red; } is two rules

  1. When the build tool performs buildStart, collect all public style class names.
  2. When the build tool performs transform, start checking each file.
  3. If enable is not true or the file extension is not supported, and it's not a style code block in a vue file, then end.
  4. Check if it's a scoped style in a vue file, if yes then end.
  5. Parse the CSS code and extract rules.
  6. Check if all class selectors in each rule are public style class names, if yes then mark as style pollution.

Why These Types of Pollution Are Not Checked

Scoped Styles

  1. Scoped adds attribute selectors, even when using /deep/ for penetration, it will still have them. Even if it pollutes, it can only pollute things inside slots.
  2. If we want to check slots, the cost would be high and cannot be achieved through static analysis. It would require using a headless browser for e2e testing, which contradicts this plugin's positioning (a static analysis plugin).

Why Not Check for Same Class Names Used in Multiple Files

  1. Vite is bundless, unless building, it cannot know all file information and cannot know during dev that other files are using the same class names.
  2. If we pre-scan all files to get all class names, it would be difficult to handle in large project scenarios, whether for storage, matching, or other processes, it would be a huge overhead. Considering the cost-benefit ratio, we don't plan to support this for now.
  3. If there are scenarios where the same class names are used across projects, this can be handled through custom public style class names.

Why Not Check ID, Pseudo-classes, Pseudo-elements, and Tag Selectors

ID Selectors

Normally, we shouldn't set styles for ID selectors, and even if we do, it should be set where it's used.

In HTML, element IDs need to be unique, so theoretically there shouldn't be cases where unrelated files pollute ID selector styles.

We can consider adding corresponding checks when needed in the future.

Tag Selectors

Generally, tag selectors don't work alone, they only work alone in reset scenarios.

This means that in business scenarios, we normally don't directly override tag styles, but instead use classes or atomic CSS or other methods to override, so there's no corresponding check.

We can consider adding corresponding checks when needed in the future.

Pseudo-classes and Pseudo-elements

These two types of selectors basically need to work together with other selectors, like class selectors, so there's no corresponding check.

We can consider adding corresponding checks when needed in the future.

About

Check CSS pollution for bundlers

Resources

License

Stars

Watchers

Forks

Packages

No packages published