English | 简体中文
npm i -D unplugin-css-checker
// vite.config.ts
import CSSChecker from 'unplugin-css-checker/vite'
export default defineConfig({
plugins: [
CSSChecker({ /* options */ }),
],
})
// rollup.config.js
import CSSChecker from 'unplugin-css-checker/rollup'
export default {
plugins: [
CSSChecker({ /* options */ }),
],
}
// webpack.config.js
module.exports = {
/* ... */
plugins: [
require('unplugin-css-checker/webpack')({ /* options */ })
]
}
// vue.config.js
module.exports = {
configureWebpack: {
plugins: [
require('unplugin-css-checker/webpack')({ /* options */ }),
],
},
}
// esbuild.config.js
import { build } from 'esbuild'
import CSSChecker from 'unplugin-css-checker/esbuild'
build({
plugins: [CSSChecker()],
})
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/,
],
}),
],
}
})
Definition of a "rule":
.sfv-btn { color: red; }
is one rule,.sfv-btn, .custom-btn { color: red; }
is two rules
- When the build tool performs
buildStart
, collect all public style class names. - When the build tool performs
transform
, start checking each file. - If
enable
is nottrue
or the file extension is not supported, and it's not astyle
code block in avue
file, then end. - Check if it's a
scoped
style in avue
file, if yes then end. - Parse the
CSS
code and extract rules. - Check if all
class
selectors in each rule are public style class names, if yes then mark as style pollution.
- 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. - 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).
- 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.
- 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.
- If there are scenarios where the same class names are used across projects, this can be handled through custom public style class names.
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.
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.
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.