├── .editorconfig ├── .github ├── FUNDING.yml └── workflows │ ├── autofix.yml │ ├── ci.yml │ ├── pkg.pr.new.yml │ └── release.yml ├── .gitignore ├── .node-version ├── .npmrc ├── .vscode ├── extensions.json └── settings.json ├── CHANGELOG.md ├── LICENSE ├── README.md ├── README.zh-CN.md ├── biome.json ├── commitlint.config.mjs ├── docs ├── .vitepress │ ├── config.ts │ └── theme │ │ ├── VAd.vue │ │ ├── custom.css │ │ └── index.ts ├── guide │ ├── faq.md │ ├── getting-started.md │ ├── options.md │ └── why.md ├── index.md ├── package.json └── zh-Hans │ ├── guide │ ├── faq.md │ ├── getting-started.md │ ├── options.md │ └── why.md │ └── index.md ├── examples └── react-ts │ ├── .gitignore │ ├── README.md │ ├── index.html │ ├── package.json │ ├── public │ └── vite.svg │ ├── src │ ├── App.css │ ├── App.tsx │ ├── assets │ │ └── react.svg │ ├── index.css │ ├── main.tsx │ └── vite-env.d.ts │ ├── stylelint.config.mjs │ ├── tsconfig.app.json │ ├── tsconfig.json │ ├── tsconfig.node.json │ └── vite.config.ts ├── lerna.json ├── lint-staged.config.mjs ├── package.json ├── packages └── core │ ├── CHANGELOG.md │ ├── README.md │ ├── README.zh-CN.md │ ├── build.config.ts │ ├── package.json │ └── src │ ├── constants.ts │ ├── index.ts │ ├── types.ts │ ├── utils.ts │ └── worker.ts ├── pnpm-lock.yaml ├── pnpm-workspace.yaml ├── simple-git-hooks.cjs └── tsconfig.json /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [ModyQyW] 2 | custom: ["https://github.com/ModyQyW/sponsors"] 3 | -------------------------------------------------------------------------------- /.github/workflows/autofix.yml: -------------------------------------------------------------------------------- 1 | # https://github.com/unocss/unocss/blob/fe83a90b59cf4599be57ea825166bb74d92b104c/.github/workflows/autofix.yml 2 | name: autofix.ci 3 | 4 | on: 5 | push: 6 | branches: 7 | - main 8 | 9 | pull_request: 10 | branches: 11 | - main 12 | 13 | jobs: 14 | autofix: 15 | runs-on: ubuntu-latest 16 | timeout-minutes: 10 17 | 18 | steps: 19 | - name: Checkout 20 | uses: actions/checkout@v4 21 | 22 | - name: Install pnpm 23 | uses: pnpm/action-setup@v4 24 | 25 | - name: Setup Node.js 26 | uses: actions/setup-node@v4 27 | with: 28 | node-version-file: .node-version 29 | cache: pnpm 30 | registry-url: https://registry.npmjs.org 31 | 32 | - name: Setup corepack 33 | run: corepack enable 34 | 35 | - name: Install Dependencies 36 | run: pnpm install --frozen-lockfile 37 | 38 | - name: Check 39 | run: pnpm check 40 | 41 | - name: Autofix 42 | uses: autofix-ci/action@v1 43 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | # https://github.com/unocss/unocss/blob/fe83a90b59cf4599be57ea825166bb74d92b104c/.github/workflows/ci.yml 2 | name: CI 3 | 4 | on: 5 | push: 6 | branches: 7 | - main 8 | 9 | pull_request: 10 | branches: 11 | - main 12 | 13 | merge_group: {} 14 | 15 | jobs: 16 | test: 17 | runs-on: ${{ matrix.os }} 18 | 19 | strategy: 20 | matrix: 21 | os: [ubuntu-latest, macos-latest, windows-latest] 22 | node_version: [18, 20, 22] 23 | fail-fast: false 24 | 25 | steps: 26 | - name: Set git to use LF 27 | run: | 28 | git config --global core.autocrlf false 29 | git config --global core.eol lf 30 | 31 | - name: Checkout 32 | uses: actions/checkout@v4 33 | 34 | - name: Install pnpm 35 | uses: pnpm/action-setup@v4 36 | 37 | - name: Setup Node.js ${{ matrix.node_version }} 38 | uses: actions/setup-node@v4 39 | with: 40 | node-version: ${{ matrix.node_version }} 41 | cache: pnpm 42 | registry-url: https://registry.npmjs.org 43 | 44 | - name: Setup corepack 45 | run: corepack enable 46 | 47 | - name: Install Dependencies 48 | run: pnpm install --frozen-lockfile 49 | 50 | - name: Build 51 | run: pnpm build 52 | 53 | - name: Test 54 | run: pnpm test 55 | 56 | - name: Type Check 57 | run: pnpm type-check 58 | -------------------------------------------------------------------------------- /.github/workflows/pkg.pr.new.yml: -------------------------------------------------------------------------------- 1 | # https://github.com/unocss/unocss/blob/fe83a90b59cf4599be57ea825166bb74d92b104c/.github/workflows/pkg.pr.new.yml 2 | name: Publish Any Commit 3 | 4 | on: 5 | pull_request: 6 | push: 7 | branches: 8 | - "**" 9 | tags: 10 | - "!**" 11 | 12 | jobs: 13 | build: 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - name: Checkout 18 | uses: actions/checkout@v4 19 | with: 20 | fetch-depth: 0 21 | 22 | - name: Install pnpm 23 | uses: pnpm/action-setup@v4 24 | 25 | - name: Setup Node.js 26 | uses: actions/setup-node@v4 27 | with: 28 | node-version-file: .node-version 29 | cache: pnpm 30 | registry-url: https://registry.npmjs.org 31 | 32 | - name: Setup corepack 33 | run: corepack enable 34 | 35 | - name: Install Dependencies 36 | run: pnpm install 37 | 38 | - name: Build 39 | run: pnpm build 40 | 41 | - name: Release 42 | run: pnpx pkg-pr-new publish --compact --pnpm './packages/*' 43 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | # https://github.com/unocss/unocss/blob/fe83a90b59cf4599be57ea825166bb74d92b104c/.github/workflows/release.yml 2 | name: Release 3 | 4 | on: 5 | push: 6 | tags: 7 | - "v*" 8 | 9 | jobs: 10 | release: 11 | permissions: 12 | id-token: write 13 | contents: write 14 | runs-on: ubuntu-latest 15 | steps: 16 | - name: Checkout 17 | uses: actions/checkout@v4 18 | with: 19 | fetch-depth: 0 20 | 21 | - name: Install pnpm 22 | uses: pnpm/action-setup@v4 23 | 24 | - name: Setup Node.js 25 | uses: actions/setup-node@v4 26 | with: 27 | node-version-file: .node-version 28 | cache: pnpm 29 | registry-url: https://registry.npmjs.org 30 | 31 | - name: Setup corepack 32 | run: corepack enable 33 | 34 | - name: GitHub Release 35 | run: pnpx changelogithub 36 | env: 37 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 38 | 39 | - name: Install Dependencies 40 | run: pnpm install 41 | 42 | - name: Build 43 | run: pnpm build 44 | 45 | - name: Publish to NPM 46 | run: pnpm -r publish --access public --no-git-checks 47 | env: 48 | NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} 49 | NPM_CONFIG_PROVENANCE: true 50 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | pnpm-debug.log* 9 | run 10 | 11 | # Diagnostic reports (https://nodejs.org/api/report.html) 12 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 13 | 14 | # Runtime data 15 | pids 16 | *.pid 17 | *.seed 18 | *.pid.lock 19 | 20 | # Directory for instrumented libs generated by jscoverage/JSCover 21 | lib-cov 22 | 23 | # Coverage directory used by tools like istanbul 24 | coverage 25 | *.lcov 26 | 27 | # nyc test coverage 28 | .nyc_output 29 | 30 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 31 | .grunt 32 | 33 | # Bower dependency directory (https://bower.io/) 34 | bower_components 35 | 36 | # node-waf configuration 37 | .lock-wscript 38 | 39 | # Compiled binary addons (https://nodejs.org/api/addons.html) 40 | build/Release 41 | 42 | # Dependency directories 43 | node_modules 44 | jspm_packages 45 | 46 | # Snowpack dependency directory (https://snowpack.dev/) 47 | web_modules 48 | 49 | # Temp directory 50 | .temp 51 | .tmp 52 | 53 | # TypeScript cache 54 | *.tsbuildinfo 55 | 56 | # Optional npm cache directory 57 | .npm 58 | 59 | # Optional eslint cache 60 | .eslintcache 61 | 62 | # Optional stylelint cache 63 | .stylelintcache 64 | 65 | # Microbundle cache 66 | .rpt2_cache 67 | .rts2_cache_cjs 68 | .rts2_cache_es 69 | .rts2_cache_umd 70 | 71 | # Optional REPL history 72 | .node_repl_history 73 | 74 | # Output of 'npm pack' 75 | *.tgz 76 | 77 | # Yarn Integrity file 78 | .yarn-integrity 79 | 80 | # dotenv environment variables file 81 | .env 82 | .env.test 83 | .env.*.test 84 | .env.local 85 | .env.*.local 86 | *.local 87 | 88 | # parcel-bundler cache (https://parceljs.org/) 89 | .cache 90 | .parcel-cache 91 | 92 | # Electron 93 | dist-electron 94 | dist_electron 95 | 96 | # Tauri 97 | dist-tauri 98 | dist_tauri 99 | 100 | # Cordova 101 | dist-cordova 102 | dist_cordova 103 | 104 | # Capacitor 105 | dist-capacitor 106 | dist_capacitor 107 | 108 | # Next.js build output 109 | .next 110 | out 111 | 112 | # Umi.js build output 113 | .umi 114 | .umi-production 115 | .umi-test 116 | 117 | # Nuxt.js build / generate output 118 | .nuxt 119 | dist 120 | 121 | # Rax.js build 122 | .rax 123 | 124 | # Vuepress build output 125 | .vuepress/dist 126 | 127 | # Vitepress build output 128 | **/.vitepress/cache 129 | **/.vitepress/dist 130 | 131 | # SSR 132 | dist-ssr 133 | dist_ssr 134 | 135 | # SSG 136 | dist-ssg 137 | dist_ssg 138 | 139 | # Serverless 140 | .serverless 141 | .dynamodb 142 | .s3 143 | .buckets 144 | .seeds 145 | 146 | # FuseBox cache 147 | .fusebox 148 | 149 | # TernJS port file 150 | .tern-port 151 | 152 | # Cypress 153 | /cypress/videos/ 154 | /cypress/screenshots/ 155 | 156 | # Editor 157 | .vscode-test 158 | .vscode/** 159 | !.vscode/extensions.json 160 | !.vscode/settings.json 161 | .idea 162 | .hbuilder 163 | .hbuilderx 164 | *.suo 165 | *.ntvs* 166 | *.njsproj 167 | *.sln 168 | *.sw? 169 | 170 | # yarn v2 171 | .yarn/cache 172 | .yarn/unplugged 173 | .yarn/build-state.yml 174 | .yarn/install-state.gz 175 | .pnp.* 176 | 177 | # Apple 178 | .DS_Store 179 | *.p12 180 | *.mobileprovision 181 | 182 | # Android 183 | *.keystore 184 | -------------------------------------------------------------------------------- /.node-version: -------------------------------------------------------------------------------- 1 | 22 2 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | shamefully-hoist=true 2 | registry=https://registry.npmjs.org/ 3 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["biomejs.biome"] 3 | } 4 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.defaultFormatter": "biomejs.biome", 3 | "editor.formatOnSave": true, 4 | "editor.codeActionsOnSave": { 5 | "quickfix.biome": "explicit", 6 | "source.organizeImports.biome": "explicit" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [6.0.0](https://github.com/ModyQyW/vite-plugin-stylelint/compare/v6.0.0-beta.2...v6.0.0) (2024-11-26) 7 | 8 | **Note:** Version bump only for package monorepo 9 | 10 | ## [6.0.0-beta.2](https://github.com/ModyQyW/vite-plugin-stylelint/compare/v6.0.0-beta.1...v6.0.0-beta.2) (2024-11-08) 11 | 12 | ### Bug Fixes 13 | 14 | * correct id & filePath params ([9c78976](https://github.com/ModyQyW/vite-plugin-stylelint/commit/9c7897659e63b4443569c72ca13b5ffe0b782a57)) - by @ 15 | 16 | ## [6.0.0-beta.1](https://github.com/ModyQyW/vite-plugin-stylelint/compare/v6.0.0-beta.0...v6.0.0-beta.1) (2024-10-19) 17 | 18 | **Note:** Version bump only for package monorepo 19 | 20 | ## [6.0.0-beta.0](https://github.com/ModyQyW/vite-plugin-stylelint/compare/v5.3.1...v6.0.0-beta.0) (2024-10-14) 21 | 22 | ### ⚠ BREAKING CHANGES 23 | 24 | * remove chokidar, introduce another way to handle imported style files 25 | 26 | ### Features 27 | 28 | * remove chokidar, introduce another way to handle imported style files ([17f3d5d](https://github.com/ModyQyW/vite-plugin-stylelint/commit/17f3d5d9955fd98e28ac36ac70b413b5225903af)) - by @ModyQyW 29 | 30 | ### Bug Fixes 31 | 32 | * fix wrong colorize ([55eb4c3](https://github.com/ModyQyW/vite-plugin-stylelint/commit/55eb4c36e8e439810e4cad9bc5186552cb41fbf1)) - by @ModyQyW 33 | * remove extra parsing ([68906c1](https://github.com/ModyQyW/vite-plugin-stylelint/commit/68906c1be6d4c679f69c16d43af99546f8cc8a8f)) - by @ModyQyW 34 | * stylelintInstance may not be initialized when calling lintFiles in the worker ([2caf01c](https://github.com/ModyQyW/vite-plugin-stylelint/commit/2caf01c21c16e365f5929f0fbf5523af7bf703ac)) - by @ModyQyW 35 | * terminate worker if possible ([acd43ca](https://github.com/ModyQyW/vite-plugin-stylelint/commit/acd43caa49e628468d318679633ca4f73158ac2e)) - by @ModyQyW 36 | 37 | ## 5.3.1 (2023-12-19) 38 | 39 | * fix: remove linterResult spread to avoid annoying warnings 40 | 41 | ## 5.3.0 (2023-12-09) 42 | 43 | * feat: support stylelint@16 44 | 45 | ## 5.2.1 (2023-11-17) 46 | 47 | * chore: update `peerDependencies` 48 | 49 | ## 5.2.0 (2023-10-23) 50 | 51 | * feat: support `rollup@4` and `vite@5`, **ATTENTION**: `rollup@4` is supported since `vite@5.0.0-beta.10` 52 | 53 | ## 5.1.1 (2023-08-23) 54 | 55 | * fix: fix wrong ignored when enable `chokidar` 56 | 57 | ## 5.1.0 (2023-08-21) 58 | 59 | ## 5.0.1 (2023-08-21) 60 | 61 | I want to publish `5.1.0` but sorry 😅 62 | 63 | * feat: add `test` option 64 | 65 | ## 5.0.0 (2023-08-16) 66 | 67 | I completely rewrote the plugin. It's still backward compatible, but there is still a possibility that the changes may affect some projects. So I bumped a major version. 68 | 69 | * feat: add `lintDirtyOnly` option 70 | * feat: add `debug` 71 | * types: add descriptions 72 | * docs: update README 73 | * feat!: update **internal functions** 74 | 75 | ## 4.3.0 (2023-03-09) 76 | 77 | * feat: export more types 78 | 79 | ## 4.2.0 (2023-02-10) 80 | 81 | * build: switch to `unbuild` 82 | * feat: support `stylelint@15` 83 | * feat: improve types 84 | 85 | ## 4.1.8 (2023-01-31) 86 | 87 | * fix: fix worker initial and close 88 | 89 | ## 4.1.7 (2023-01-30) 90 | 91 | * fix: use `__dirname` directly by accident 92 | * build: update minify and generate sourcemap 93 | 94 | ## 4.1.6 (2023-01-10) 95 | 96 | * perf: better emit handling 97 | 98 | ## 4.1.5 (2023-01-04) 99 | 100 | * build: switch to rollup 101 | * fix: lint some files twice or more 102 | 103 | ## 4.1.4 (2022-12-27) 104 | 105 | * fix: fix judge order 106 | 107 | ## 4.1.3 (2022-12-16) 108 | 109 | * perf: remove extra console 110 | * perf: worker message params 111 | 112 | ## 4.1.2 (2022-12-16) 113 | 114 | * fix: fix wrong customPrint color 115 | 116 | ## 4.1.1 (2022-12-16) 117 | 118 | * perf: internal function params 119 | 120 | ## 4.1.0 (2022-12-16) 121 | 122 | * feat: add `lintInWorker` option 123 | * perf: output syntax 124 | * perf: internal function params 125 | * perf: chokidar initial judgement 126 | 127 | ## 4.0.4 (2022-12-14) 128 | 129 | * perf: improve code 130 | 131 | ## 4.0.3 (2022-12-14) 132 | 133 | * fix: fix build 134 | 135 | ## 4.0.2 (2022-12-13) 136 | 137 | * fix: fix build 138 | 139 | ## 4.0.1 (2022-12-11) 140 | 141 | * fix: correct reading stylelint instance 142 | 143 | ## 4.0.0 (2022-12-09) 144 | 145 | * feat: support `vite@4` 146 | * feat!: require `node>=14.18` 147 | * feat!: `build` option defaults to `false` 148 | * feat!: `cacheLocation` option defaults to `.stylelintcache` 149 | * feat: esm by default 150 | * don't be afraid as commonjs is also supported 151 | 152 | ## 3.3.3 (2022-12-05) 153 | 154 | * perf: improve output syntax 155 | 156 | ## 3.3.2 (2022-12-04) 157 | 158 | * fix: fix Stylelint options lost 159 | 160 | ## 3.3.1 (2022-12-02) 161 | 162 | * fix: fix wrong behavior when enable `lintOnStart` and `chokidar` 163 | * perf: split `print`, `contextPrint` and `customPrint` functions 164 | * perf: split `pluginName` variable 165 | * perf: improve naming 166 | 167 | ## 3.3.0 (2022-11-29) 168 | 169 | * feat: add `chokidar` option 170 | 171 | ## 3.2.0 (2022-11-28) 172 | 173 | * feat: add `dev` and `build` options 174 | 175 | ## 3.1.1 (2022-11-26) 176 | 177 | * fix: fix build 178 | 179 | ## 3.1.0 (2022-11-25) 180 | 181 | * refactor 182 | * feat: add `formatter` option 183 | 184 | ## 3.0.10 (2022-11-25) 185 | 186 | * revert: revert `perf: reduce dependencies`, which breaks vite@2 187 | 188 | ## 3.0.9 (2022-11-24) 189 | 190 | * perf: reduce dependencies 191 | 192 | ## 3.0.8 193 | 194 | * fix: fix build 195 | 196 | ## 3.0.7 197 | 198 | * perf: use `config.cacheDir` to get default `cacheLocation` 199 | 200 | ## 3.0.6 201 | 202 | * fix: pass `ctx` to lintFiles method 203 | 204 | ## 3.0.5 205 | 206 | * fix: warning styles 207 | 208 | ## 3.0.4 209 | 210 | * perf: warn when `lintOnStart` is true 211 | 212 | ## 3.0.3 213 | 214 | * perf: import path from `node:path` instead of `path` 215 | * fix: fix `type: "module"` support 216 | 217 | ## 3.0.2 218 | 219 | Just update `peerDependencies` in `package.json`. 220 | 221 | ## 3.0.1 222 | 223 | * fix: fix type 224 | 225 | ## 3.0.0 226 | 227 | This version supports vite@2 and vite@3. The breaking changes are caused by aligning behaviors with `Stylelint` Node.js API. 228 | 229 | * feat!: remove `throwOnError` and `throwOnWarning` options (marked as `deprecated` before) 230 | * feat!: `include` and `exclude` options now accept `string | string[]` only to align with `stylelint.lint` 231 | * feat: add `lintOnStart` option 232 | * feat: exclude `virtual:` by default 233 | 234 | ## 2.3.1 235 | 236 | * fix: show error message when importing `stylelint` if possible 237 | * fix: include `shims` into `dist` 238 | 239 | ## 2.3.0 240 | 241 | * feat: support `vite@3` 242 | * feat: ignore virtual modules 243 | * perf: not to add `build.outDir` into `exclude` 244 | * fix: fix `then` handling 245 | 246 | ## 2.2.3 247 | 248 | * fix: revert [bee0a28](https://github.com/ModyQyW/vite-plugin-stylelint/commit/bee0a28b7691090e02d73e979bf62c27510a960d), closes [#8](https://github.com/ModyQyW/vite-plugin-stylelint/issues/8) 249 | 250 | ## 2.2.2 251 | 252 | * fix: remove `allowSyntheticDefaultImports` and `esModuleInterop` in `tsconfig.json`, closes [#5](https://github.com/ModyQyW/vite-plugin-stylelint/issues/5) 253 | 254 | ## 2.2.1 255 | 256 | * fix: try to fix `warning` output 257 | * fix: fix regressions 258 | 259 | ## 2.2.0 260 | 261 | * feat: include `.svelte` files by default 262 | 263 | ## 2.1.0 264 | 265 | * perf: better output format 266 | * feat: add `emitErrorAsWarning` and `emitWarningAsError` options 267 | 268 | ## 2.0.2 269 | 270 | * fix: fix `index.html` dealing 271 | 272 | ## 2.0.1 273 | 274 | * fix: fix `FilterPattern` type may be lost 275 | 276 | ## 2.0.0 277 | 278 | * feat: bring back `throwOnError` and `throwOnWarning` 279 | 280 | The plugin recommends `emitError` / `emitWarning` instead of `throwOnError` / `throwOnWarning` now. However, you can stay with `throwOnError` / `throwOnWarning` safely. This is actually a backward-compatible version update. 281 | 282 | ## 2.0.0-beta.0 283 | 284 | * feat: support Stylelint options 285 | 286 | ### Breaking Changes 287 | 288 | * `throwOnError` -> `emitError` 289 | * `throwOnWarning` -> `emitWarning` 290 | 291 | ## 1.3.0-beta.1 292 | 293 | * fix: `cacheLocation` use relative path 294 | 295 | ## 1.3.0-beta.0 296 | 297 | * feat: add `stylelintPath` option 298 | 299 | ## 1.2.0 300 | 301 | * feat: add `cacheLocation` option 302 | * fix: fix script 303 | 304 | ## 1.1.3 305 | 306 | * perf: minify dist by default 307 | * fix: stricter `include` 308 | * fix: ignore `index.html` ` 38 | -------------------------------------------------------------------------------- /docs/.vitepress/theme/custom.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ModyQyW/vite-plugin-stylelint/a10c6fff97c44f7fe17b72a69097f360a9c18195/docs/.vitepress/theme/custom.css -------------------------------------------------------------------------------- /docs/.vitepress/theme/index.ts: -------------------------------------------------------------------------------- 1 | // https://vitepress.dev/guide/custom-theme 2 | import type { EnhanceAppContext, Theme } from "vitepress"; 3 | import DefaultTheme from "vitepress/theme"; 4 | import { h } from "vue"; 5 | import VAd from "./VAd.vue"; 6 | import "./custom.css"; 7 | 8 | export default { 9 | extends: DefaultTheme, 10 | 11 | enhanceApp(ctx: EnhanceAppContext) { 12 | ctx.app.component("VAd", VAd); 13 | DefaultTheme.enhanceApp(ctx); 14 | }, 15 | 16 | Layout() { 17 | return h(DefaultTheme.Layout, null, { 18 | // 添加广告 19 | "aside-bottom": () => [h(VAd)], 20 | }); 21 | }, 22 | } satisfies Theme; 23 | -------------------------------------------------------------------------------- /docs/guide/faq.md: -------------------------------------------------------------------------------- 1 | # FAQ 2 | 3 | ## Should I use this plugin? 4 | 5 | Most of the time, you don't need this plugin. 6 | 7 | It is common to use [stylelint-webpack-plugin](https://github.com/webpack-contrib/stylelint-webpack-plugin) in Webpack. And this plugin does almost the same in Vite. 8 | 9 | However, our IDE is already probably giving all the info we need. We only need to add [Stylelint plugin](https://marketplace.visualstudio.com/items?itemName=stylelint.vscode-stylelint) in VSCode. WebStorm already includes the functionality. We can also run Stylelint in CI or CLI. 10 | 11 | Since we have these ways to run Stylelint, it is unnecessary to run Stylelint in Vite, which means we don't need this plugin in most cases. 12 | 13 | If you really want to check errors and warnings, try enable `lintInWorker` option, which keeps Vite speed and prints in console. Or [vite-plugin-checker](https://github.com/fi3ework/vite-plugin-checker). 14 | 15 | ## Cache is broken? 16 | 17 | Delete the cache file, fix the error manually and restart Vite. 18 | 19 | ## Plugin is running very slow? 20 | 21 | By default, the plugin is synchronous, which may cause blocking. Please try to enable `lintInWorker` option, which keeps Vite speed and prints in console. You can also try [vite-plugin-checker](https://github.com/fi3ework/vite-plugin-checker), or run Stylelint directly besides Vite. 22 | 23 | ## Recommended configuration? 24 | 25 | ```ts 26 | import { defineConfig } from "vite"; 27 | import stylelint from "vite-plugin-stylelint"; 28 | 29 | export default defineConfig({ 30 | plugins: [stylelint({ 31 | lintInWorker: true, 32 | lintOnStart: true, 33 | })], 34 | }); 35 | 36 | ``` 37 | 38 | ## Error messages in full red? 39 | 40 | Vite's error mask layer does not support displaying `PluginContext.warn` information and full-color messages, and there are some limitations (see [#2076](https://github.com/vitejs/vite/issues/2076), [#6274](https://github.com/vitejs/vite/pull/6274) and [#8327](https://github.com/vitejs/vite/discussions/8327). 41 | -------------------------------------------------------------------------------- /docs/guide/getting-started.md: -------------------------------------------------------------------------------- 1 | # Getting Started 2 | 3 | ## Overview 4 | 5 | `vite-plugin-stylelint` is a project providing Stylelint plugin for Vite. Supports Vite v2 ~ v6 and Stylelint v13 ~ v16. Requires `node>=18`. 6 | 7 | > For Nuxt projects, please use [@nuxtjs/stylelint-module](https://github.com/nuxt-modules/stylelint). 8 | 9 | > You may also want [Vite ESLint plugin](https://github.com/ModyQyW/vite-plugin-eslint2). 10 | 11 | ## Install 12 | 13 | ```sh 14 | npm install vite-plugin-stylelint -D 15 | ``` 16 | 17 | `vite-plugin-stylelint` does not install and config Stylelint for you. You should handle these yourself. 18 | 19 | ::: details Stylelint v16 20 | 21 | ```sh 22 | npm install stylelint@^16 -D 23 | ``` 24 | 25 | ::: 26 | 27 | ::: details Stylelint v15 28 | 29 | ```sh 30 | npm install stylelint@^15 -D 31 | ``` 32 | 33 | ::: 34 | 35 | ::: details Stylelint v14 36 | 37 | ```sh 38 | npm install stylelint@^14 -D 39 | ``` 40 | 41 | ::: 42 | 43 | ::: details Stylelint v13 44 | 45 | ```sh 46 | npm install stylelint@^13 @types/stylelint@^13 -D 47 | ``` 48 | 49 | ::: 50 | 51 | ## Usage 52 | 53 | ```typescript 54 | // vite.config.ts 55 | import { defineConfig } from "vite"; 56 | import stylelint from "vite-plugin-stylelint"; 57 | 58 | export default defineConfig({ 59 | plugins: [stylelint()], 60 | }); 61 | 62 | ``` 63 | 64 | ## Acknowledge 65 | 66 | Initially forked from [gxmari007/vite-plugin-eslint](https://github.com/gxmari007/vite-plugin-eslint). 67 | 68 | ## Contributors 69 | 70 | This project was created by [ModyQyW](https://github.com/ModyQyW). 71 | 72 | Thanks to [all contributors](https://github.com/ModyQyW/vite-plugin-stylelint/graphs/contributors) for their contributions! 73 | 74 | ## Sponsors 75 | 76 | If this package is helpful to you, please consider [sponsoring](https://github.com/ModyQyW/sponsors), which will benefit the ongoing development and maintenance of the project. 77 | 78 |

79 | 80 | 81 | 82 |

83 | -------------------------------------------------------------------------------- /docs/guide/options.md: -------------------------------------------------------------------------------- 1 | # Options 2 | 3 | You can pass Stylelint [shared options](https://stylelint.io/user-guide/options) to the plugin, or you can pass the extra options. The `files` option will always be overridden. 4 | 5 | ## Shared Options 6 | 7 | Common options and descriptions are listed below, complete links are provided above. 8 | 9 | ### `fix` 10 | 11 | - Type: `boolean` 12 | - Default: `false` 13 | 14 | Whether to automatically fix. 15 | 16 | ### `cache` 17 | 18 | - Type: `boolean` 19 | - Stylelint default: `false` 20 | - Plugin default: `true` 21 | 22 | Whether to enable the cache. This is disabled in Stylelint by default and enabled in plugin by default to improve speed. 23 | 24 | ### `cacheLocation` 25 | 26 | - Type: `string` 27 | - Default: `.stylelintcache` 28 | 29 | The path to the cache. 30 | 31 | ## Extra Options 32 | 33 | Extra options and explanations are listed below. 34 | 35 | ### `test` 36 | 37 | - Type: `boolean` 38 | - Default: `false` 39 | 40 | Whether to run Stylelint under `test` mode. See [Command Line Interface](https://vitejs.dev/guide/#command-line-interface) and [Configuring Vitest](https://vitest.dev/guide/#configuring-vitest) for more. 41 | 42 | ### `dev` 43 | 44 | - Type: `boolean` 45 | - Default: `true` 46 | 47 | Whether to run Stylelint under `serve` command. See [Command Line Interface](https://vitejs.dev/guide/#command-line-interface) for more. 48 | 49 | ### `build` 50 | 51 | - Type: `boolean` 52 | - Default: `false` 53 | 54 | Whether to run Stylelint under `build` command. See [Command Line Interface](https://vitejs.dev/guide/#command-line-interface) for more. 55 | 56 | ### `include` 57 | 58 | - Type: `string | string[]` 59 | - Default: `["src/**/*.{css,scss,sass,less,styl,vue,svelte}"]` 60 | 61 | This option specifies the files you want to lint. You don't need to change it in most cases, unless the `include` and `exclude` ranges overlap. 62 | 63 | If you're using the plugin defaults, the plugin will only call [stylelint.lint](https://stylelint.io/user-guide/node-api/) in the `transform` hook. The option value will be used to [create a filter](https://github.com/rollup/plugins/blob/master/packages/pluginutils/README.md#createfilter) to determine if the call should be made and the parameter of the call, which means that the option value needs to fulfill the requirements of [picomatch@2.3.1](https://github.com/micromatch/picomatch/tree/2.3.1). 64 | 65 | If you enable the `lintOnStart` option, the plugin will also call [stylelint.lint](https://stylelint.io/user-guide/node-api/) in the `buildStart` hook. The option value will not be used to create a filter, but will be used directly as the call parameter, which means that the option value also needs to fulfill the [globby@11.1.0](https://github.com/sindresorhus/globby/tree/v11.1.0) requirement. 66 | 67 | If you disable the `lintDirtyOnly` option, the plugin will use the option value as the call parameter every time it calls [stylelint.lint](https://stylelint.io/user-guide/node-api/), which means that the option value also needs to fulfill the requirements of [globby@11.1.0](https://github.com/sindresorhus/globby/tree/v11.1.0). 68 | 69 | ### `exclude` 70 | 71 | - Type: `string | string[]` 72 | - Default: `['node_modules', 'virtual:']` 73 | 74 | This option specifies the files you don't want to lint. You don't need to change it in most cases, unless the `include` and `exclude` ranges overlap. 75 | 76 | The plugin forces the virtual module to be ignored and you don't need to do any configuration related to it here. 77 | 78 | If you're using the plugin defaults, the plugin will only call [stylelint.lint](https://stylelint.io/user-guide/node-api/) in the `transform` hook. The option value will be used to [create a filter](https://github.com/rollup/plugins/blob/master/packages/pluginutils/README.md#createfilter) to determine if the call should be made and the parameter of the call, which means that the option value needs to fulfill the requirements of [picomatch@2.3.1](https://github.com/micromatch/picomatch/tree/2.3.1). 79 | 80 | If you enable the `lintOnStart` option or disable the `lintDirtyOnly` option, the option value will not take effect. You need to change `include` value to include this option value. 81 | 82 | ### `stylelintPath` 83 | 84 | - Type: `string` 85 | - Default: `"stylelint"` 86 | 87 | Path to Stylelint that will be used for linting. Use [dynamic import](https://javascript.info/modules-dynamic-imports) under the hood. Read [Vite server.fs options](https://vitejs.dev/config/server-options.html#server-fs-strict) first. 88 | 89 | ### `formatter` 90 | 91 | - Type: `string` 92 | - Default: `"string"` 93 | 94 | The name, the path or the function implementation of a formatter. This is used to [set a formatter](https://stylelint.io/user-guide/usage/options#formatter) in order to convert lint results to a human- or machine-readable string. 95 | 96 | ### `lintInWorker` 97 | 98 | - Type: `boolean` 99 | - Default: `false` 100 | 101 | Lint in [worker](https://nodejs.org/api/worker_threads.html#portpostmessagevalue-tran). This is disabled by default. 102 | 103 | When lint in worker, Vite build process will be faster. You will not see Vite error overlay, Vite build process will not be stopped, even with errors shown in terminal. 104 | 105 | It is similar with [vite-plugin-checker](https://github.com/fi3ework/vite-plugin-checker), but vite-plugin-checker can show you errors and warnings in browsers. 106 | 107 | ### `lintOnStart` 108 | 109 | - Type: `boolean` 110 | - Default: `false` 111 | 112 | Lint `include` option specified files once in `buildStart` hook to find potential errors. This is disabled by default. 113 | 114 | This will significantly slow down Vite first starting if you have no caches and don't enable `lintInWorker`. 115 | 116 | ### `lintDirtyOnly` 117 | 118 | - Type: `boolean` 119 | - Default: `true` 120 | 121 | Whether or not to checkout only modified files that are not included in the `exclude` option value when running Stylelint outside of the `buildStart` lifecycle. Enabled by default. 122 | 123 | When disabled, files are checked against the `include` and `exclude` option values. 124 | 125 | ### `emitError` 126 | 127 | - Type: `boolean` 128 | - Default: `true` 129 | 130 | Emit found errors. This is enabled by default. 131 | 132 | ### `emitErrorAsWarning` 133 | 134 | - Type: `boolean` 135 | - Default: `false` 136 | 137 | Emit found errors as warnings. This is disabled by default but you may want it enabled when prototyping. 138 | 139 | ### `emitWarning` 140 | 141 | - Type: `boolean` 142 | - Default: `true` 143 | 144 | Emit found warnings. This is enabled by default. 145 | 146 | ### `emitWarningAsError` 147 | 148 | - Type: `boolean` 149 | - Default: `false` 150 | 151 | Emit found warnings as errors when enabled. This is disabled by default. 152 | -------------------------------------------------------------------------------- /docs/guide/why.md: -------------------------------------------------------------------------------- 1 | # Why? 2 | 3 | ## Reason 4 | 5 | This project is forked from [gxmari007/vite-plugin-eslint](https://github.com/gxmari007/vite-plugin-eslint) to run Stylelint in Vite. 6 | 7 | There are also [vite-plugin-checker](https://github.com/fi3ework/vite-plugin-checker) that provide similar functionality, please choose one to use according to your needs. 8 | 9 | ## Acknowledge 10 | 11 | Initially forked from [gxmari007/vite-plugin-eslint](https://github.com/gxmari007/vite-plugin-eslint). 12 | 13 | ## Contributors 14 | 15 | This project was created by [ModyQyW](https://github.com/ModyQyW). 16 | 17 | Thanks to [all contributors](https://github.com/ModyQyW/vite-plugin-stylelint/graphs/contributors) for their contributions! 18 | 19 | ## Sponsors 20 | 21 | If this package is helpful to you, please consider [sponsoring](https://github.com/ModyQyW/sponsors), which will benefit the ongoing development and maintenance of the project. 22 | 23 |

24 | 25 | 26 | 27 |

28 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | # https://vitepress.dev/reference/default-theme-home-page 3 | layout: home 4 | 5 | hero: 6 | name: "vite-plugin-stylelint" 7 | tagline: "Stylelint plugin for Vite" 8 | actions: 9 | - theme: brand 10 | text: Get Started → 11 | link: /guide/getting-started 12 | - theme: alt 13 | text: Why? 14 | link: /guide/why 15 | - theme: alt 16 | text: View on GitHub 17 | link: https://github.com/ModyQyW/vite-plugin-stylelint 18 | # image: 19 | # src: /logo.png 20 | # alt: _repo_ 21 | # features: 22 | # - title: "_feature_" 23 | # details: _feature-details_ 24 | # link: /guide/_feature_ 25 | --- 26 | -------------------------------------------------------------------------------- /docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "docs", 3 | "version": "4.4.1", 4 | "private": true, 5 | "type": "module", 6 | "scripts": { 7 | "build": "vitepress build .", 8 | "dev": "vitepress dev .", 9 | "preview": "vitepress preview ." 10 | }, 11 | "devDependencies": { 12 | "vitepress": "^1.5.0", 13 | "vue": "^3.5.13" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /docs/zh-Hans/guide/faq.md: -------------------------------------------------------------------------------- 1 | # 常见问题 2 | 3 | ## 我应该使用这个插件吗? 4 | 5 | 大多数情况下不需要。 6 | 7 | 在 Webpack 使用 [stylelint-webpack-plugin](https://github.com/webpack-contrib/stylelint-webpack-plugin) 是很常见的,而这个插件在 Vite 中做着几乎一样的事情。 8 | 9 | 但是,我们的 IDE 可以直接显示相对应的校验信息。对于 VS Code,我们只需要添加 [Stylelint 插件](https://marketplace.visualstudio.com/items?itemName=stylelint.vscode-stylelint)。WebStorm 已经内置了这个功能。此外,我们也可以在命令行或者 CI 中运行 Stylelint 来获取反馈。 10 | 11 | 我们有这么多方法运行 Stylelint,没有太大必要再在 Vite 中运行 Stylelint,这也就意味着我们在大多数情况下不需要这个插件。 12 | 13 | 如果你真的很需要查看错误和警告,请尝试启用 `lintInWorker` 选项,它保持了 Vite 的速度,并在控制台中打印信息。你也可以尝试一下社区内的 [vite-plugin-checker](https://github.com/fi3ework/vite-plugin-checker)。 14 | 15 | ## 缓存失效了? 16 | 17 | 删除缓存文件,手动修复错误后重启 Vite 即可。 18 | 19 | ## 插件运行非常慢? 20 | 21 | 默认地,插件是同步运行的,这可能会造成阻塞。请尝试启用 `lintInWorker` 选项,它保持了 Vite 的速度,并在控制台中打印信息。你也可以尝试一下社区内的 [vite-plugin-checker](https://github.com/fi3ework/vite-plugin-checker),或者在 Vite 之外直接运行 Stylelint。 22 | 23 | ## 推荐配置? 24 | 25 | ```ts 26 | import { defineConfig } from "vite"; 27 | import stylelint from "vite-plugin-stylelint"; 28 | 29 | export default defineConfig({ 30 | plugins: [stylelint({ 31 | lintInWorker: true, 32 | lintOnStart: true, 33 | })], 34 | }); 35 | 36 | ``` 37 | 38 | ## 错误信息全红? 39 | 40 | Vite 的错误遮罩层不支持显示 `PluginContext.warn` 信息和全色消息,还有一些限制(参见 [#2076](https://github.com/vitejs/vite/issues/2076)、[#6274](https://github.com/vitejs/vite/pull/6274) 和 [#8327](https://github.com/vitejs/vite/discussions/8327))。 41 | -------------------------------------------------------------------------------- /docs/zh-Hans/guide/getting-started.md: -------------------------------------------------------------------------------- 1 | # 起步 2 | 3 | ## 总览 4 | 5 | `vite-plugin-stylelint` 是 Vite Stylelint 插件。支持 Vite v2 ~ v6 和 Stylelint v13 ~ v16。要求 `node>=18`。 6 | 7 | > 对于 Nuxt 项目,请使用[@nuxtjs/stylelint-module](https://github.com/nuxt-modules/stylelint)。 8 | 9 | > 你也可能想要 [Vite ESlint 插件](https://github.com/ModyQyW/vite-plugin-eslint2)。 10 | 11 | ## 安装 12 | 13 | ```sh 14 | npm install vite-plugin-stylelint -D 15 | ``` 16 | 17 | `vite-plugin-stylelint` 不会为你安装和配置 Stylelint。你应该自己处理这些。 18 | 19 | ::: details Stylelint v16 20 | 21 | ```sh 22 | npm install stylelint@^16 -D 23 | ``` 24 | 25 | ::: 26 | 27 | ::: details Stylelint v15 28 | 29 | ```sh 30 | npm install stylelint@^15 -D 31 | ``` 32 | 33 | ::: 34 | 35 | ::: details Stylelint v14 36 | 37 | ```sh 38 | npm install stylelint@^14 -D 39 | ``` 40 | 41 | ::: 42 | 43 | ::: details Stylelint v13 44 | 45 | ```sh 46 | npm install stylelint@^13 @types/stylelint@^13 -D 47 | ``` 48 | 49 | ::: 50 | 51 | ## 使用 52 | 53 | ```typescript 54 | // vite.config.ts 55 | import { defineConfig } from "vite"; 56 | import stylelint from "vite-plugin-stylelint"; 57 | 58 | export default defineConfig({ 59 | plugins: [stylelint()], 60 | }); 61 | 62 | ``` 63 | 64 | ## 致谢 65 | 66 | 最初从 [gxmari007/vite-plugin-eslint](https://github.com/gxmari007/vite-plugin-eslint) 分叉出来。 67 | 68 | ## 贡献者们 69 | 70 | 该项目由 [ModyQyW](https://github.com/ModyQyW) 创建。 71 | 72 | 感谢 [所有贡献者](https://github.com/ModyQyW/vite-plugin-stylelint/graphs/contributors) 的付出! 73 | 74 | ## 赞助 75 | 76 | 如果这个包对你有所帮助,请考虑 [赞助](https://github.com/ModyQyW/sponsors) 支持,这将有利于项目持续开发和维护。 77 | 78 |

79 | 80 | 81 | 82 |

83 | -------------------------------------------------------------------------------- /docs/zh-Hans/guide/options.md: -------------------------------------------------------------------------------- 1 | # 选项配置 2 | 3 | 你可以给这个插件传递 Stylelint [shared options](https://stylelint.io/user-guide/options),也可以传递这个插件特有的额外选项。`files` 选项总是会被覆盖。 4 | 5 | ## 构造器选项 6 | 7 | 常见的自带选项和说明如下,完整内容请查看上方链接。 8 | 9 | ### `fix` 10 | 11 | - 类型:`boolean` 12 | - 默认值:`false` 13 | 14 | 是否自动修复。 15 | 16 | ### `cache` 17 | 18 | - 类型:`boolean` 19 | - Stylelint 默认值:`false` 20 | - 插件默认值:`true` 21 | 22 | 是否启用缓存。Stylelint 默认禁用,插件默认启用以提高速度。 23 | 24 | ### `cacheLocation` 25 | 26 | - 类型:`string` 27 | - 默认值:`.stylelintcache` 28 | 29 | 缓存位置。 30 | 31 | ## 额外选项 32 | 33 | 额外的选项和说明如下。 34 | 35 | ### `test` 36 | 37 | - 类型:`boolean` 38 | - 默认值:`false` 39 | 40 | 是否在 `test` 模式下运行 Stylelint。查看 [命令行界面](https://cn.vitejs.dev/guide/#command-line-interface) 和 [配置 Vitest](https://cn.vitest.dev/guide/) 了解更多。 41 | 42 | ### `dev` 43 | 44 | - 类型:`boolean` 45 | - 默认值:`true` 46 | 47 | 是否在 `serve` 命令下运行 Stylelint。查看 [命令行界面](https://cn.vitejs.dev/guide/#command-line-interface) 了解更多。 48 | 49 | ### `build` 50 | 51 | - 类型:`boolean` 52 | - 默认值:`false` 53 | 54 | 是否在 `build` 命令下运行 Stylelint。查看 [命令行界面](https://cn.vitejs.dev/guide/#command-line-interface) 了解更多。 55 | 56 | ### `include` 57 | 58 | - 类型:`string | string[]` 59 | - 默认值:`["src/**/*.{css,scss,sass,less,styl,vue,svelte}"]` 60 | 61 | 这个选项指定你想要校验的文件模式。在绝大部分情况下,你并不需要调整它,除非 `include` 和 `exclude` 范围有重合。 62 | 63 | 如果你正在使用插件默认设置,插件只会在 `transform` 生命周期中调用 [stylelint.lint](https://stylelint.io/user-guide/node-api/)。这个选项值会被用于 [创建一个过滤器](https://github.com/rollup/plugins/blob/master/packages/pluginutils/README.md#createfilter) 来确定是否该调用以及调用参数。这意味着选项值需要满足 [picomatch@2.3.1](https://github.com/micromatch/picomatch/tree/2.3.1) 的要求。 64 | 65 | 如果你启用了 `lintOnStart` 选项,插件还会在 `buildStart` 生命周期中调用 [stylelint.lint](https://stylelint.io/user-guide/node-api/)。这个选项值不会用于创建过滤器,而是直接用作调用参数。这意味着这个选项值还需要满足 [globby@11.1.0](https://github.com/sindresorhus/globby/tree/v11.1.0) 的要求。 66 | 67 | 如果你禁用了 `lintDirtyOnly` 选项,插件每次调用 [stylelint.lint](https://stylelint.io/user-guide/node-api/) 时都会将该选项值作为调用参数。这意味着这个选项值也需要满足 [globby@11.1.0](https://github.com/sindresorhus/globby/tree/v11.1.0) 的要求。 68 | 69 | ### `exclude` 70 | 71 | - 类型:`string | string[]` 72 | - 默认值:`['node_modules', 'virtual:']` 73 | 74 | 这个选项指定你不想要校验的文件模式。在绝大部分情况下,你并不需要调整它,除非 `include` 和 `exclude` 范围有重合。 75 | 76 | 插件强制忽略虚拟模块,你不需要在这里进行任何相关配置。 77 | 78 | 如果你正在使用插件默认设置,插件只会在 `transform` 生命周期中调用 [stylelint.lint](https://stylelint.io/user-guide/node-api/)。这个选项值会被用于 [创建一个过滤器](https://github.com/rollup/plugins/blob/master/packages/pluginutils/README.md#createfilter) 来确定是否该调用以及调用参数。这意味着选项值需要满足 [picomatch@2.3.1](https://github.com/micromatch/picomatch/tree/2.3.1) 的要求。 79 | 80 | 如果你启用了 `lintOnStart` 选项或者禁用了 `lintDirtyOnly` 选项,这个选项值不会生效。你需要调整 `include` 值以包含该选项值。 81 | 82 | ### `stylelintPath` 83 | 84 | - 类型:`string` 85 | - 默认值:`"stylelint"` 86 | 87 | Stylelint 路径,用于校验文件。底层使用使用 [dynamic import](https://javascript.info/modules-dynamic-imports)。请先阅读 [Vite server.fs 选项](https://cn.vitejs.dev/config/server-options.html#server-fs-strict)。 88 | 89 | ### `formatter` 90 | 91 | - 类型:`string` 92 | - 默认值:`"string"` 93 | 94 | 格式化器的名称、路径或函数实现。用于 [设置格式化器](https://stylelint.io/user-guide/usage/options#formatter),以便将校验结果转换为人类或机器可读的字符串。 95 | 96 | ### `lintInWorker` 97 | 98 | - 类型:`boolean` 99 | - 默认值:`false` 100 | 101 | 在 [worker](https://nodejs.org/api/worker_threads.html#portpostmessagevalue-tran) 校验。默认禁用。 102 | 103 | 在 worker 中校验时,Vite 的构建过程会更快。即使终端显示了 Stylelint 校验错误,你也不会看到 Vite 错误遮罩层,Vite 构建也不会停止。 104 | 105 | 这与 [vite-plugin-checker](https://github.com/fi3ework/vite-plugin-checker) 类似,但 [vite-plugin-checker](https://github.com/fi3ework/vite-plugin-checker) 可以在浏览器中显示错误。 106 | 107 | ### `lintOnStart` 108 | 109 | - 类型:`boolean` 110 | - 默认值:`false` 111 | 112 | 在 `buildStart` 生命周期中校验 `include` 选项指定的文件一次以发现潜在的错误。默认禁用。 113 | 114 | 如果你没有缓存而且没有启用 `lintInWorker`,这将大大降低 Vite 的初次启动速度。 115 | 116 | ### `lintDirtyOnly` 117 | 118 | - 类型:`boolean` 119 | - 默认值:`true` 120 | 121 | 在 `buildStart` 生命周期之外运行 Stylelint 时,是否只校验修改过且没有包含在 `exclude` 选项值内的文件。默认启用。 122 | 123 | 禁用时,会根据 `include` 和 `exclude` 选项值确定需要校验文件。 124 | 125 | ### `emitError` 126 | 127 | - 类型:`boolean` 128 | - 默认值:`true` 129 | 130 | 输出发现的错误。默认启用。 131 | 132 | ### `emitErrorAsWarning` 133 | 134 | - 类型:`boolean` 135 | - 默认值:`false` 136 | 137 | 将发现的错误作为警告输出。默认禁用,但你可能会在开发原型时启用这个。 138 | 139 | ### `emitWarning` 140 | 141 | - 类型:`boolean` 142 | - 默认值:`true` 143 | 144 | 输出发现的警告。默认启用。 145 | 146 | ### `emitWarningAsError` 147 | 148 | - 类型:`boolean` 149 | - 默认值:`false` 150 | 151 | 将发现的警告作为错误输出。默认禁用。 152 | -------------------------------------------------------------------------------- /docs/zh-Hans/guide/why.md: -------------------------------------------------------------------------------- 1 | # 为什么? 2 | 3 | ## 起因 4 | 5 | 这个项目最初从 [gxmari007/vite-plugin-eslint](https://github.com/gxmari007/vite-plugin-eslint) 分叉出来以在 Vite 中运行 Stylelint。 6 | 7 | 社区还有 [vite-plugin-checker](https://github.com/fi3ework/vite-plugin-checker) 提供了类似的功能,请根据你的意愿选择一个来使用。 8 | 9 | ## 致谢 10 | 11 | 最初从 [gxmari007/vite-plugin-eslint](https://github.com/gxmari007/vite-plugin-eslint) 分叉出来。 12 | 13 | ## 贡献者们 14 | 15 | 该项目由 [ModyQyW](https://github.com/ModyQyW) 创建。 16 | 17 | 感谢 [所有贡献者](https://github.com/ModyQyW/vite-plugin-stylelint/graphs/contributors) 的付出! 18 | 19 | ## 赞助 20 | 21 | 如果这个包对你有所帮助,请考虑 [赞助](https://github.com/ModyQyW/sponsors) 支持,这将有利于项目持续开发和维护。 22 | 23 |

24 | 25 | 26 | 27 |

28 | -------------------------------------------------------------------------------- /docs/zh-Hans/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | # https://vitepress.dev/reference/default-theme-home-page 3 | layout: home 4 | 5 | hero: 6 | name: "vite-plugin-stylelint" 7 | tagline: "Vite Stylelint 插件" 8 | actions: 9 | - theme: brand 10 | text: 起步 → 11 | link: /zh-Hans/guide/getting-started 12 | - theme: alt 13 | text: 为什么? 14 | link: /zh-Hans/guide/why 15 | - theme: alt 16 | text: 在 GitHub 查看 17 | link: https://github.com/ModyQyW/vite-plugin-stylelint 18 | # image: 19 | # src: /logo.png 20 | # alt: _repo_ 21 | # features: 22 | # - title: "_特性_" 23 | # details: _特性细节_ 24 | # link: /zh-Hans/guide/_feature_ 25 | --- 26 | -------------------------------------------------------------------------------- /examples/react-ts/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /examples/react-ts/README.md: -------------------------------------------------------------------------------- 1 | # React + TypeScript + Vite 2 | 3 | This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. 4 | 5 | Currently, two official plugins are available: 6 | 7 | - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh 8 | - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh 9 | 10 | ## Expanding the ESLint configuration 11 | 12 | If you are developing a production application, we recommend updating the configuration to enable type aware lint rules: 13 | 14 | - Configure the top-level `parserOptions` property like this: 15 | 16 | ```js 17 | export default tseslint.config({ 18 | languageOptions: { 19 | // other options... 20 | parserOptions: { 21 | project: ['./tsconfig.node.json', './tsconfig.app.json'], 22 | tsconfigRootDir: import.meta.dirname, 23 | }, 24 | }, 25 | }) 26 | ``` 27 | 28 | - Replace `tseslint.configs.recommended` to `tseslint.configs.recommendedTypeChecked` or `tseslint.configs.strictTypeChecked` 29 | - Optionally add `...tseslint.configs.stylisticTypeChecked` 30 | - Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and update the config: 31 | 32 | ```js 33 | // eslint.config.js 34 | import react from 'eslint-plugin-react' 35 | 36 | export default tseslint.config({ 37 | // Set the react version 38 | settings: { react: { version: '18.3' } }, 39 | plugins: { 40 | // Add the react plugin 41 | react, 42 | }, 43 | rules: { 44 | // other rules... 45 | // Enable its recommended rules 46 | ...react.configs.recommended.rules, 47 | ...react.configs['jsx-runtime'].rules, 48 | }, 49 | }) 50 | ``` 51 | -------------------------------------------------------------------------------- /examples/react-ts/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + React + TS 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /examples/react-ts/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-ts", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc -b && vite build", 9 | "preview": "vite preview" 10 | }, 11 | "dependencies": { 12 | "react": "^18.3.1", 13 | "react-dom": "^18.3.1" 14 | }, 15 | "devDependencies": { 16 | "@types/react": "^18.3.12", 17 | "@types/react-dom": "^18.3.1", 18 | "@vitejs/plugin-react-swc": "^3.7.2", 19 | "less": "^4.2.1", 20 | "sass-embedded": "^1.81.0", 21 | "stylelint": "^16.10.0", 22 | "stylelint-config-recommended": "^14.0.1", 23 | "stylelint-config-recommended-scss": "^14.1.0", 24 | "stylus": "^0.64.0", 25 | "typescript": "^5.7.2", 26 | "vite": "^6.0.0", 27 | "vite-plugin-stylelint": "workspace: *" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /examples/react-ts/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/react-ts/src/App.css: -------------------------------------------------------------------------------- 1 | #root { 2 | max-width: 1280px; 3 | margin: 0 auto; 4 | padding: 2rem; 5 | text-align: center; 6 | } 7 | 8 | .logo { 9 | height: 6em; 10 | padding: 1.5em; 11 | will-change: filter; 12 | transition: filter 300ms; 13 | } 14 | .logo:hover { 15 | filter: drop-shadow(0 0 2em #646cffaa); 16 | } 17 | .logo.react:hover { 18 | filter: drop-shadow(0 0 2em #61dafbaa); 19 | } 20 | 21 | @keyframes logo-spin { 22 | from { 23 | transform: rotate(0deg); 24 | } 25 | to { 26 | transform: rotate(360deg); 27 | } 28 | } 29 | 30 | @media (prefers-reduced-motion: no-preference) { 31 | a:nth-of-type(2) .logo { 32 | animation: logo-spin infinite 20s linear; 33 | } 34 | } 35 | 36 | .card { 37 | padding: 2em; 38 | } 39 | 40 | .read-the-docs { 41 | color: #888; 42 | } 43 | -------------------------------------------------------------------------------- /examples/react-ts/src/App.tsx: -------------------------------------------------------------------------------- 1 | import { useState } from 'react' 2 | import reactLogo from './assets/react.svg' 3 | import viteLogo from '/vite.svg' 4 | import './App.css' 5 | 6 | function App() { 7 | const [count, setCount] = useState(0) 8 | 9 | return ( 10 | <> 11 |
12 | 13 | Vite logo 14 | 15 | 16 | React logo 17 | 18 |
19 |

Vite + React

20 |
21 | 24 |

25 | Edit src/App.tsx and save to test HMR 26 |

27 |
28 |

29 | Click on the Vite and React logos to learn more 30 |

31 | 32 | ) 33 | } 34 | 35 | export default App 36 | -------------------------------------------------------------------------------- /examples/react-ts/src/assets/react.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/react-ts/src/index.css: -------------------------------------------------------------------------------- 1 | :root { 2 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; 3 | line-height: 1.5; 4 | font-weight: 400; 5 | 6 | color-scheme: light dark; 7 | color: rgba(255, 255, 255, 0.87); 8 | background-color: #242424; 9 | 10 | font-synthesis: none; 11 | text-rendering: optimizeLegibility; 12 | -webkit-font-smoothing: antialiased; 13 | -moz-osx-font-smoothing: grayscale; 14 | } 15 | 16 | a { 17 | font-weight: 500; 18 | color: #646cff; 19 | text-decoration: inherit; 20 | } 21 | a:hover { 22 | color: #535bf2; 23 | } 24 | 25 | body { 26 | margin: 0; 27 | display: flex; 28 | place-items: center; 29 | min-width: 320px; 30 | min-height: 100vh; 31 | } 32 | 33 | h1 { 34 | font-size: 3.2em; 35 | line-height: 1.1; 36 | } 37 | 38 | button { 39 | border-radius: 8px; 40 | border: 1px solid transparent; 41 | padding: 0.6em 1.2em; 42 | font-size: 1em; 43 | font-weight: 500; 44 | font-family: inherit; 45 | background-color: #1a1a1a; 46 | cursor: pointer; 47 | transition: border-color 0.25s; 48 | } 49 | button:hover { 50 | border-color: #646cff; 51 | } 52 | button:focus, 53 | button:focus-visible { 54 | outline: 4px auto -webkit-focus-ring-color; 55 | } 56 | 57 | @media (prefers-color-scheme: light) { 58 | :root { 59 | color: #213547; 60 | background-color: #ffffff; 61 | } 62 | a:hover { 63 | color: #747bff; 64 | } 65 | button { 66 | background-color: #f9f9f9; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /examples/react-ts/src/main.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from "react"; 2 | import { createRoot } from "react-dom/client"; 3 | import App from "./App.tsx"; 4 | import "./index.css"; 5 | 6 | createRoot(document.getElementById("root")!).render( 7 | 8 | 9 | , 10 | ); 11 | -------------------------------------------------------------------------------- /examples/react-ts/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /examples/react-ts/stylelint.config.mjs: -------------------------------------------------------------------------------- 1 | export default { 2 | extends: ["stylelint-config-recommended-scss"], 3 | }; 4 | -------------------------------------------------------------------------------- /examples/react-ts/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "useDefineForClassFields": true, 5 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 6 | "module": "ESNext", 7 | "skipLibCheck": true, 8 | 9 | /* Bundler mode */ 10 | "moduleResolution": "bundler", 11 | "allowImportingTsExtensions": true, 12 | "isolatedModules": true, 13 | "moduleDetection": "force", 14 | "noEmit": true, 15 | "jsx": "react-jsx", 16 | 17 | /* Linting */ 18 | "strict": true, 19 | "noUnusedLocals": true, 20 | "noUnusedParameters": true, 21 | "noFallthroughCasesInSwitch": true 22 | }, 23 | "include": ["src"] 24 | } 25 | -------------------------------------------------------------------------------- /examples/react-ts/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [ 4 | { "path": "./tsconfig.app.json" }, 5 | { "path": "./tsconfig.node.json" } 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /examples/react-ts/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2022", 4 | "lib": ["ES2023"], 5 | "module": "ESNext", 6 | "skipLibCheck": true, 7 | 8 | /* Bundler mode */ 9 | "moduleResolution": "bundler", 10 | "allowImportingTsExtensions": true, 11 | "isolatedModules": true, 12 | "moduleDetection": "force", 13 | "noEmit": true, 14 | 15 | /* Linting */ 16 | "strict": true, 17 | "noUnusedLocals": true, 18 | "noUnusedParameters": true, 19 | "noFallthroughCasesInSwitch": true 20 | }, 21 | "include": ["vite.config.ts"] 22 | } 23 | -------------------------------------------------------------------------------- /examples/react-ts/vite.config.ts: -------------------------------------------------------------------------------- 1 | import react from "@vitejs/plugin-react-swc"; 2 | import { defineConfig } from "vite"; 3 | import stylelint from "vite-plugin-stylelint"; 4 | 5 | // https://vitejs.dev/config/ 6 | export default defineConfig({ 7 | plugins: [react(), stylelint()], 8 | }); 9 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "node_modules/@lerna-lite/cli/schemas/lerna-schema.json", 3 | "version": "6.0.0", 4 | "npmClient": "pnpm", 5 | "packages": [ 6 | "packages/*" 7 | ], 8 | "command": { 9 | "version": { 10 | "allowBranch": "main", 11 | "conventionalCommits": true, 12 | "changelogIncludeCommitsClientLogin": " - by @%l", 13 | "message": "chore: release %s", 14 | "remoteClient": "github" 15 | } 16 | }, 17 | "changelogPreset": "conventional-changelog-conventionalcommits", 18 | "ignoreChanges": [ 19 | "**/test/**", 20 | "**/tests/**", 21 | "**/__test__/**", 22 | "**/__tests__/**", 23 | "**/*.md" 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /lint-staged.config.mjs: -------------------------------------------------------------------------------- 1 | export default { 2 | "*": "biome check --write --no-errors-on-unmatched --files-ignore-unknown=true", 3 | }; 4 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "monorepo", 3 | "version": "0.0.0", 4 | "private": true, 5 | "homepage": "https://github.com/ModyQyW/vite-plugin-stylelint", 6 | "bugs": { 7 | "url": "https://github.com/ModyQyW/vite-plugin-stylelint/issues" 8 | }, 9 | "repository": "git+https://github.com/ModyQyW/vite-plugin-stylelint.git", 10 | "license": "MIT", 11 | "author": { 12 | "name": "ModyQyW", 13 | "email": "wurui.dev@gmail.com", 14 | "url": "https://modyqyw.top" 15 | }, 16 | "sideEffects": false, 17 | "type": "module", 18 | "scripts": { 19 | "build": "rimraf packages/*/dist --glob && pnpm -r --filter=./packages/* run build && pnpm -r run build-post", 20 | "check": "biome check --write --no-errors-on-unmatched --files-ignore-unknown=true", 21 | "dep-update": "taze -fw", 22 | "dev": "pnpm stub", 23 | "docs:build": "pnpm -C docs run build", 24 | "docs:dev": "pnpm -C docs run dev", 25 | "docs:preview": "pnpm -C docs run preview", 26 | "preinstall": "npx only-allow pnpm", 27 | "prepare": "is-ci || simple-git-hooks", 28 | "prepublishOnly": "pnpm run build", 29 | "release": "lerna version", 30 | "stub": "pnpm -r --filter=./packages/* --parallel run stub", 31 | "test": "vitest run --passWithNoTests", 32 | "test:coverage": "vitest run --passWithNoTests --coverage", 33 | "type-check": "tsc --noEmit", 34 | "preversion": "git-branch-is main && conc \"pnpm:check\" \"pnpm:type-check\" \"pnpm:test\"" 35 | }, 36 | "dependencies": { 37 | "@rollup/pluginutils": "^5.1.3", 38 | "debug": "^4.3.7" 39 | }, 40 | "devDependencies": { 41 | "@biomejs/biome": "^1.9.4", 42 | "@commitlint/cli": "^19.6.0", 43 | "@commitlint/config-conventional": "^19.6.0", 44 | "@commitlint/config-pnpm-scopes": "^19.5.0", 45 | "@lerna-lite/cli": "^3.10.0", 46 | "@lerna-lite/version": "^3.10.0", 47 | "@types/node": "^22.10.0", 48 | "@vitest/coverage-v8": "^2.1.6", 49 | "concurrently": "^9.1.0", 50 | "conventional-changelog-conventionalcommits": "^7.0.2", 51 | "git-branch-is": "^4.0.0", 52 | "is-ci": "^3.0.1", 53 | "lint-staged": "^15.2.10", 54 | "rimraf": "^6.0.1", 55 | "simple-git-hooks": "^2.11.1", 56 | "taze": "^0.18.0", 57 | "typescript": "^5.7.2", 58 | "unbuild": "^3.0.0-rc.11", 59 | "vitest": "^2.1.6" 60 | }, 61 | "packageManager": "pnpm@9.14.2", 62 | "engines": { 63 | "node": ">=20.11.0 || >=21.2.0" 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /packages/core/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [6.0.0](https://github.com/ModyQyW/vite-plugin-stylelint/compare/v6.0.0-beta.2...v6.0.0) (2024-11-26) 7 | 8 | **Note:** Version bump only for package vite-plugin-stylelint 9 | 10 | ## [6.0.0-beta.2](https://github.com/ModyQyW/vite-plugin-stylelint/compare/v6.0.0-beta.1...v6.0.0-beta.2) (2024-11-08) 11 | 12 | ### Bug Fixes 13 | 14 | * correct id & filePath params ([9c78976](https://github.com/ModyQyW/vite-plugin-stylelint/commit/9c7897659e63b4443569c72ca13b5ffe0b782a57)) - by @ 15 | 16 | ## [6.0.0-beta.1](https://github.com/ModyQyW/vite-plugin-stylelint/compare/v6.0.0-beta.0...v6.0.0-beta.1) (2024-10-19) 17 | 18 | **Note:** Version bump only for package vite-plugin-stylelint 19 | 20 | ## [6.0.0-beta.0](https://github.com/ModyQyW/vite-plugin-stylelint/compare/v5.3.1...v6.0.0-beta.0) (2024-10-14) 21 | 22 | ### ⚠ BREAKING CHANGES 23 | 24 | * remove chokidar, introduce another way to handle imported style files 25 | 26 | ### Features 27 | 28 | * remove chokidar, introduce another way to handle imported style files ([17f3d5d](https://github.com/ModyQyW/vite-plugin-stylelint/commit/17f3d5d9955fd98e28ac36ac70b413b5225903af)) - by @ModyQyW 29 | 30 | ### Bug Fixes 31 | 32 | * fix wrong colorize ([55eb4c3](https://github.com/ModyQyW/vite-plugin-stylelint/commit/55eb4c36e8e439810e4cad9bc5186552cb41fbf1)) - by @ModyQyW 33 | * remove extra parsing ([68906c1](https://github.com/ModyQyW/vite-plugin-stylelint/commit/68906c1be6d4c679f69c16d43af99546f8cc8a8f)) - by @ModyQyW 34 | * stylelintInstance may not be initialized when calling lintFiles in the worker ([2caf01c](https://github.com/ModyQyW/vite-plugin-stylelint/commit/2caf01c21c16e365f5929f0fbf5523af7bf703ac)) - by @ModyQyW 35 | * terminate worker if possible ([acd43ca](https://github.com/ModyQyW/vite-plugin-stylelint/commit/acd43caa49e628468d318679633ca4f73158ac2e)) - by @ModyQyW 36 | -------------------------------------------------------------------------------- /packages/core/README.md: -------------------------------------------------------------------------------- 1 | # vite-plugin-stylelint 2 | 3 | English | [简体中文](./README.zh-CN.md) 4 | 5 |
6 | 7 | License 8 | 9 | 10 | npm 11 | 12 | 13 | npm downloads 14 | 15 |
16 | 17 | ## Introduction 18 | 19 | Stylelint plugin for Vite. Supports Vite v2 ~ v6 and Stylelint v13 ~ v16. Requires `node>=18`. 20 | 21 | 👇 See the documentation for specific usage and examples. 22 | 23 | [Cloudflare Pages](https://vite-plugin-stylelint.modyqyw.top/) 24 | 25 | > You may also want [ESLint plugin for Vite](https://github.com/ModyQyW/vite-plugin-eslint2). 26 | 27 | ## Install 28 | 29 | ```sh 30 | npm install vite-plugin-stylelint -D 31 | ``` 32 | 33 | `vite-plugin-stylelint` does not install and config Stylelint for you. You should handle these yourself. 34 | 35 |
36 | 37 | Stylelint v16 38 | 39 | ```sh 40 | npm install stylelint@^16 -D 41 | ``` 42 | 43 |
44 | 45 |
46 | 47 | Stylelint v15 48 | 49 | ```sh 50 | npm install stylelint@^15 -D 51 | ``` 52 | 53 |
54 | 55 |
56 | 57 | Stylelint v14 58 | 59 | ```sh 60 | npm install stylelint@^14 -D 61 | ``` 62 | 63 |
64 | 65 |
66 | 67 | Stylelint v13 68 | 69 | ```sh 70 | npm install stylelint@^13 @types/stylelint@^13 -D 71 | ``` 72 | 73 |
74 | 75 | ## Usage 76 | 77 | ```typescript 78 | // vite.config.ts 79 | import { defineConfig } from "vite"; 80 | import stylelint from "vite-plugin-stylelint"; 81 | 82 | export default defineConfig({ 83 | plugins: [stylelint()], 84 | }); 85 | ``` 86 | 87 | 👇 See the documentation for specific usage and examples. 88 | 89 | [Cloudflare Pages](https://vite-plugin-stylelint.modyqyw.top/) 90 | 91 | ## Acknowledge 92 | 93 | Initially forked from [gxmari007/vite-plugin-eslint](https://github.com/gxmari007/vite-plugin-eslint). 94 | 95 | ## Contributors 96 | 97 | This project was created by [ModyQyW](https://github.com/ModyQyW). 98 | 99 | Thanks to [all contributors](https://github.com/ModyQyW/vite-plugin-stylelint/graphs/contributors) for their contributions! 100 | 101 | ## Sponsors 102 | 103 | If this package is helpful to you, please consider [sponsoring](https://github.com/ModyQyW/sponsors), which will benefit the ongoing development and maintenance of the project. 104 | 105 |

106 | 107 | 108 | 109 |

110 | -------------------------------------------------------------------------------- /packages/core/README.zh-CN.md: -------------------------------------------------------------------------------- 1 | # vite-plugin-stylelint 2 | 3 | [English](./README.md) | 简体中文 4 | 5 |
6 | 7 | License 8 | 9 | 10 | npm 11 | 12 | 13 | npm downloads 14 | 15 |
16 | 17 | ## 介绍 18 | 19 | Vite Stylelint 插件。支持 Vite v2 ~ v6 和 Stylelint v13 ~ v16。要求 `node>=18`。 20 | 21 | 👇 请查看文档了解具体用法和示例。 22 | 23 | [Cloudflare Pages](https://vite-plugin-stylelint.modyqyw.top/) 24 | 25 | > 你也可能想要 [Vite ESLint 插件](https://github.com/ModyQyW/vite-plugin-eslint2)。 26 | 27 | ## 安装 28 | 29 | ```sh 30 | npm install vite-plugin-stylelint -D 31 | ``` 32 | 33 | `vite-plugin-stylelint` 不会为你安装和配置 Stylelint。你应该自己处理这些。 34 | 35 |
36 | 37 | Stylelint v16 38 | 39 | ```sh 40 | npm install stylelint@^16 -D 41 | ``` 42 | 43 |
44 | 45 |
46 | 47 | Stylelint v15 48 | 49 | ```sh 50 | npm install stylelint@^15 -D 51 | ``` 52 | 53 |
54 | 55 |
56 | 57 | Stylelint v14 58 | 59 | ```sh 60 | npm install stylelint@^14 -D 61 | ``` 62 | 63 |
64 | 65 |
66 | 67 | Stylelint v13 68 | 69 | ```sh 70 | npm install stylelint@^13 @types/stylelint@^13 -D 71 | ``` 72 | 73 |
74 | 75 | ## 使用 76 | 77 | ```typescript 78 | // vite.config.ts 79 | import { defineConfig } from "vite"; 80 | import stylelint from "vite-plugin-stylelint"; 81 | 82 | export default defineConfig({ 83 | plugins: [stylelint()], 84 | }); 85 | ``` 86 | 87 | 👇 请查看文档了解具体用法和示例。 88 | 89 | [Cloudflare Pages](https://vite-plugin-stylelint.modyqyw.top/) 90 | 91 | ## 致谢 92 | 93 | 最初从 [gxmari007/vite-plugin-eslint](https://github.com/gxmari007/vite-plugin-eslint) 分叉出来。 94 | 95 | ## 贡献者们 96 | 97 | 该项目由 [ModyQyW](https://github.com/ModyQyW) 创建。 98 | 99 | 感谢 [所有贡献者](https://github.com/ModyQyW/vite-plugin-stylelint/graphs/contributors) 的付出! 100 | 101 | ## 赞助 102 | 103 | 如果这个包对你有所帮助,请考虑 [赞助](https://github.com/ModyQyW/sponsors) 支持,这将有利于项目持续开发和维护。 104 | 105 |

106 | 107 | 108 | 109 |

110 | -------------------------------------------------------------------------------- /packages/core/build.config.ts: -------------------------------------------------------------------------------- 1 | import { unlinkSync } from "node:fs"; 2 | import { resolve } from "node:path"; 3 | import { defineBuildConfig } from "unbuild"; 4 | 5 | export default defineBuildConfig({ 6 | entries: ["src/index", "src/worker"], 7 | clean: true, 8 | declaration: true, 9 | rollup: { 10 | emitCJS: true, 11 | inlineDependencies: true, 12 | esbuild: { 13 | target: "node18", 14 | }, 15 | }, 16 | hooks: { 17 | "build:done": (ctx) => { 18 | unlinkSync(resolve(ctx.options.outDir, "worker.d.ts")); 19 | }, 20 | }, 21 | }); 22 | -------------------------------------------------------------------------------- /packages/core/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vite-plugin-stylelint", 3 | "version": "6.0.0", 4 | "description": "Stylelint plugin for Vite.", 5 | "keywords": [ 6 | "stylelint", 7 | "vite-plugin" 8 | ], 9 | "homepage": "https://github.com/ModyQyW/vite-plugin-stylelint", 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/ModyQyW/vite-plugin-stylelint.git", 13 | "directory": "packages/core" 14 | }, 15 | "license": "MIT", 16 | "author": { 17 | "name": "ModyQyW", 18 | "email": "wurui.dev@gmail.com", 19 | "url": "https://modyqyw.top" 20 | }, 21 | "type": "module", 22 | "exports": { 23 | ".": { 24 | "types": { 25 | "import": "./dist/index.d.mts", 26 | "require": "./dist/index.d.cts" 27 | }, 28 | "import": "./dist/index.mjs", 29 | "require": "./dist/index.cjs" 30 | } 31 | }, 32 | "main": "./dist/index.cjs", 33 | "module": "./dist/index.mjs", 34 | "types": "./dist/index.d.ts", 35 | "typesVersions": { 36 | "*": { 37 | "*": [ 38 | "./dist/*", 39 | "./dist/index.d.ts" 40 | ] 41 | } 42 | }, 43 | "files": [ 44 | "dist" 45 | ], 46 | "scripts": { 47 | "build": "unbuild", 48 | "prepublishOnly": "pnpm build", 49 | "stub": "unbuild --stub" 50 | }, 51 | "dependencies": { 52 | "@rollup/pluginutils": "^5.1.3", 53 | "debug": "^4.3.7" 54 | }, 55 | "devDependencies": { 56 | "@types/debug": "^4.1.12", 57 | "picocolors": "^1.1.1", 58 | "postcss": "^8.4.49", 59 | "rollup": "^4.27.4", 60 | "typescript": "^5.7.2", 61 | "vite": "^6.0.0" 62 | }, 63 | "peerDependencies": { 64 | "@types/stylelint": "^13.0.0", 65 | "postcss": "^7.0.0 || ^8.0.0", 66 | "rollup": "^2.0.0 || ^3.0.0 || ^4.0.0", 67 | "stylelint": "^13.0.0 || ^14.0.0 || ^15.0.0 || ^16.0.0", 68 | "vite": "^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0" 69 | }, 70 | "peerDependenciesMeta": { 71 | "@types/stylelint": { 72 | "optional": true 73 | }, 74 | "postcss": { 75 | "optional": true 76 | }, 77 | "rollup": { 78 | "optional": true 79 | } 80 | }, 81 | "packageManager": "pnpm@9.14.2", 82 | "engines": { 83 | "node": ">=18" 84 | }, 85 | "publishConfig": { 86 | "access": "public", 87 | "registry": "https://registry.npmjs.org/" 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /packages/core/src/constants.ts: -------------------------------------------------------------------------------- 1 | import type { Colors } from "picocolors/types"; 2 | import type { TextType } from "./types"; 3 | 4 | export const STYLELINT_SEVERITY = { 5 | ERROR: "error", 6 | WARNING: "warning", 7 | } as const; 8 | 9 | export const PLUGIN_NAME = "vite:stylelint"; 10 | 11 | export const COLOR_MAPPING: Record< 12 | TextType, 13 | keyof Omit 14 | > = { 15 | error: "red", 16 | warning: "yellow", 17 | plugin: "magenta", 18 | }; 19 | -------------------------------------------------------------------------------- /packages/core/src/index.ts: -------------------------------------------------------------------------------- 1 | import { dirname, extname, resolve } from "node:path"; 2 | import { fileURLToPath } from "node:url"; 3 | import { Worker } from "node:worker_threads"; 4 | import debugWrap from "debug"; 5 | import type * as Vite from "vite"; 6 | import { PLUGIN_NAME } from "./constants"; 7 | import type { 8 | StylelintFormatter, 9 | StylelintInstance, 10 | StylelintPluginUserOptions, 11 | } from "./types"; 12 | import { 13 | getFilePath, 14 | getFilter, 15 | getOptions, 16 | initializeStylelint, 17 | lintFiles, 18 | shouldIgnoreModule, 19 | } from "./utils"; 20 | 21 | const debug = debugWrap(PLUGIN_NAME); 22 | const __filename = fileURLToPath(import.meta.url); 23 | const __dirname = dirname(__filename); 24 | const ext = extname(__filename); 25 | 26 | export default function StylelintPlugin( 27 | userOptions: StylelintPluginUserOptions = {}, 28 | ): Vite.Plugin { 29 | const options = getOptions(userOptions); 30 | 31 | let worker: Worker; 32 | 33 | const filter = getFilter(options); 34 | let stylelintInstance: StylelintInstance; 35 | let formatter: StylelintFormatter; 36 | 37 | return { 38 | name: PLUGIN_NAME, 39 | apply(config, { command }) { 40 | debug("==== apply hook ===="); 41 | if (config.mode === "test" || process.env.VITEST) return options.test; 42 | const shouldApply = 43 | (command === "serve" && options.dev) || 44 | (command === "build" && options.build); 45 | debug(`should apply this plugin: ${shouldApply}`); 46 | return shouldApply; 47 | }, 48 | async buildStart() { 49 | debug("==== buildStart hook ===="); 50 | // initialize worker 51 | if (options.lintInWorker) { 52 | if (worker) return; 53 | debug("Initialize worker"); 54 | worker = new Worker(resolve(__dirname, `worker${ext}`), { 55 | workerData: { options }, 56 | }); 57 | return; 58 | } 59 | // initialize Stylelint 60 | debug("Initial Stylelint"); 61 | const result = await initializeStylelint(options); 62 | stylelintInstance = result.stylelintInstance; 63 | formatter = result.formatter; 64 | // lint on start if needed 65 | if (options.lintOnStart) { 66 | debug("Lint on start"); 67 | await lintFiles( 68 | { 69 | files: options.include, 70 | stylelintInstance, 71 | formatter, 72 | options, 73 | }, 74 | this, // use buildStart hook context 75 | ); 76 | } 77 | }, 78 | async transform(_, id) { 79 | debug("==== transform hook ===="); 80 | debug(`id: ${id}`); 81 | const watchIds = this.getWatchFiles(); 82 | debug(`watchIds: ${watchIds}`); 83 | const ids = [id, ...watchIds]; 84 | debug(`ids: ${ids}`); 85 | // worker 86 | if (worker) { 87 | for (const id of ids) { 88 | worker.postMessage(id); 89 | } 90 | return; 91 | } 92 | // no worker 93 | // filtered 94 | const filteredIds = ids.filter((id) => !shouldIgnoreModule(id, filter)); 95 | debug(`filteredIds: ${filteredIds}`); 96 | const shouldIgnore = filteredIds.length === 0; 97 | debug(`should ignore: ${shouldIgnore}`); 98 | if (shouldIgnore) return; 99 | const filePaths = filteredIds.map((id) => getFilePath(id)); 100 | return await lintFiles( 101 | { 102 | files: options.lintDirtyOnly ? filePaths : options.include, 103 | stylelintInstance, 104 | formatter, 105 | options, 106 | }, 107 | this, // use transform hook context 108 | ); 109 | }, 110 | async buildEnd() { 111 | debug("==== buildEnd hook ===="); 112 | if (worker) await worker.terminate(); 113 | }, 114 | }; 115 | } 116 | 117 | export type { 118 | StylelintPluginOptions, 119 | StylelintPluginUserOptions, 120 | } from "./types"; 121 | -------------------------------------------------------------------------------- /packages/core/src/types.ts: -------------------------------------------------------------------------------- 1 | import type { CreateFilter } from "@rollup/pluginutils"; 2 | import type * as Rollup from "rollup"; 3 | import type * as Stylelint from "stylelint"; 4 | import type stylelint from "stylelint"; 5 | 6 | export type FilterPattern = string | string[]; 7 | export type Filter = ReturnType; 8 | 9 | export type StylelintLinterOptions = Partial; 10 | export type StylelintInstance = typeof stylelint; 11 | export type StylelintFormatter = Exclude< 12 | StylelintLinterOptions["formatter"], 13 | string | undefined 14 | >; 15 | export type StylelintFormatterType = Exclude< 16 | StylelintLinterOptions["formatter"], 17 | StylelintFormatter | undefined 18 | >; 19 | export type StylelintLinterResult = Stylelint.LinterResult; 20 | 21 | export interface StylelintPluginOptions extends StylelintLinterOptions { 22 | /** 23 | * Whether to enable the cache. This is disabled in Stylelint by default and enabled in plugin by default to improve speed. 24 | * 25 | * 是否启用缓存。Stylelint 默认禁用,插件默认启用以提高速度。 26 | * 27 | * @default true 28 | */ 29 | cache: boolean; 30 | 31 | /** 32 | * Run Stylelint under `test` mode. See [Command Line Interface](https://vitejs.dev/guide/#command-line-interface) and [Configuring Vitest](https://vitest.dev/guide/#configuring-vitest) for more. 33 | * 34 | * 在 `test` 模式下运行 Stylelint。查看 [命令行界面](https://cn.vitejs.dev/guide/#command-line-interface) 和 [配置 Vitest](https://cn.vitest.dev/guide/) 了解更多。 35 | * 36 | * @default false 37 | */ 38 | test: boolean; 39 | /** 40 | * Run Stylelint under `serve` command. See [Command Line Interface](https://vitejs.dev/guide/#command-line-interface) for more. 41 | * 42 | * 在 `serve` 命令下运行 Stylelint。查看 [命令行界面](https://cn.vitejs.dev/guide/#command-line-interface) 了解更多。 43 | * 44 | * @default true 45 | */ 46 | dev: boolean; 47 | /** 48 | * Run Stylelint under `build` command. See [Command Line Interface](https://vitejs.dev/guide/#command-line-interface) for more. 49 | * 50 | * 在 `build` 命令下运行 Stylelint。查看 [命令行界面](https://cn.vitejs.dev/guide/#command-line-interface) 了解更多。 51 | * 52 | * @default false 53 | */ 54 | build: boolean; 55 | /** 56 | * This option specifies the files you want to lint. You don't need to change it in most cases, unless the `include` and `exclude` ranges overlap. 57 | * 58 | * If you're using the plugin defaults, the plugin will only call [stylelint.lint](https://stylelint.io/user-guide/node-api/) in the `transform` hook. The option value will be used to [create a filter](https://github.com/rollup/plugins/blob/master/packages/pluginutils/README.md#createfilter) to determine if the call should be made and the parameter of the call, which means that the option value needs to fulfill the requirements of [picomatch@2.3.1](https://github.com/micromatch/picomatch/tree/2.3.1). 59 | * 60 | * If you enable the `lintOnStart` option, the plugin will also call [stylelint.lint](https://stylelint.io/user-guide/node-api/) in the `buildStart` hook. The option value will not be used to create a filter, but will be used directly as the call parameter, which means that the option value also needs to fulfill the [globby@11.1.0](https://github.com/sindresorhus/globby/tree/v11.1.0) requirement. 61 | * 62 | * If you disable the `lintDirtyOnly` option, the plugin will use the option value as the call parameter every time it calls [stylelint.lint](https://stylelint.io/user-guide/node-api/), which means that the option value also needs to fulfill the requirements of [globby@11.1.0](https://github.com/sindresorhus/globby/tree/v11.1.0). 63 | * 64 | * 这个选项指定你想要校验的文件模式。在绝大部分情况下,你并不需要调整它,除非 `include` 和 `exclude` 范围有重合。 65 | * 66 | * 如果你正在使用插件默认设置,插件只会在 `transform` 生命周期中调用 [stylelint.lint](https://stylelint.io/user-guide/node-api/)。这个选项值会被用于 [创建一个过滤器](https://github.com/rollup/plugins/blob/master/packages/pluginutils/README.md#createfilter) 来确定是否该调用以及调用参数。这意味着选项值需要满足 [picomatch@2.3.1](https://github.com/micromatch/picomatch/tree/2.3.1) 的要求。 67 | * 68 | * 如果你启用了 `lintOnStart` 选项,插件还会在 `buildStart` 生命周期中调用 [stylelint.lint](https://stylelint.io/user-guide/node-api/)。这个选项值不会用于创建过滤器,而是直接用作调用参数。这意味着这个选项值还需要满足 [globby@11.1.0](https://github.com/sindresorhus/globby/tree/v11.1.0) 的要求。 69 | * 70 | * 如果你禁用了 `lintDirtyOnly` 选项,插件每次调用 [stylelint.lint](https://stylelint.io/user-guide/node-api/) 时都会将该选项值作为调用参数。这意味着这个选项值也需要满足 [globby@11.1.0](https://github.com/sindresorhus/globby/tree/v11.1.0) 的要求。 71 | */ 72 | include: FilterPattern; 73 | /** 74 | * This option specifies the files you don't want to lint. You don't need to change it in most cases, unless the `include` and `exclude` ranges overlap. 75 | * 76 | * The plugin forces the virtual module to be ignored and you don't need to do any configuration related to it here. 77 | * 78 | * If you're using the plugin defaults, the plugin will only call [stylelint.lint](https://stylelint.io/user-guide/node-api/) in the `transform` hook. The option value will be used to [create a filter](https://github.com/rollup/plugins/blob/master/packages/pluginutils/README.md#createfilter) to determine if the call should be made and the parameter of the call, which means that the option value needs to fulfill the requirements of [picomatch@2.3.1](https://github.com/micromatch/picomatch/tree/2.3.1). 79 | * 80 | * If you enable the `lintOnStart` option or disable the `lintDirtyOnly` option, the option value will not take effect. You need to change `include` value to include this option value. 81 | * 82 | * 这个选项指定你不想要校验的文件模式。在绝大部分情况下,你并不需要调整它,除非 `include` 和 `exclude` 范围有重合。 83 | * 84 | * 插件强制忽略虚拟模块,你不需要在这里进行任何相关配置。 85 | * 86 | * 如果你正在使用插件默认设置,插件只会在 `transform` 生命周期中调用 [stylelint.lint](https://stylelint.io/user-guide/node-api/)。这个选项值会被用于 [创建一个过滤器](https://github.com/rollup/plugins/blob/master/packages/pluginutils/README.md#createfilter) 来确定是否该调用以及调用参数。这意味着选项值需要满足 [picomatch@2.3.1](https://github.com/micromatch/picomatch/tree/2.3.1) 的要求。 87 | * 88 | * 如果你启用了 `lintOnStart` 选项或者禁用了 `lintDirtyOnly` 选项,这个选项值不会生效。你需要调整 `include` 值以包含该选项值。 89 | */ 90 | exclude: FilterPattern; 91 | /** 92 | * Path to Stylelint that will be used for linting. Use [dynamic import](https://javascript.info/modules-dynamic-imports) under the hood. Read [Vite server.fs options](https://vitejs.dev/config/server-options.html#server-fs-strict) first. 93 | * 94 | * Stylelint 路径,用于校验文件。底层使用使用 [dynamic import](https://javascript.info/modules-dynamic-imports)。请先阅读 [Vite server.fs 选项](https://cn.vitejs.dev/config/server-options.html#server-fs-strict)。 95 | * 96 | * @default "stylelint" 97 | */ 98 | stylelintPath: string; 99 | /** 100 | * The name, the path or the function implementation of a formatter. This is used to [set a formatter](https://stylelint.io/user-guide/usage/options#formatter) in order to convert lint results to a human- or machine-readable string. 101 | * 102 | * 格式化器的名称、路径或函数实现。用于 [设置格式化器](https://stylelint.io/user-guide/usage/options#formatter),以便将校验结果转换为人类或机器可读的字符串。 103 | * 104 | * @default "string" 105 | */ 106 | formatter: StylelintFormatterType | StylelintFormatter; 107 | /** 108 | * Lint in [worker](https://nodejs.org/api/worker_threads.html#portpostmessagevalue-tran). This is disabled by default. 109 | * 110 | * When lint in worker, Vite build process will be faster. You will not see Vite error overlay, Vite build process will not be stopped, even with errors shown in terminal. 111 | * 112 | * It is similar with [vite-plugin-checker](https://github.com/fi3ework/vite-plugin-checker), but vite-plugin-checker can show you errors and warnings in browsers. 113 | * 114 | * 在 [worker](https://nodejs.org/api/worker_threads.html#portpostmessagevalue-tran) 校验。默认禁用。 115 | * 116 | * 在 worker 中校验时,Vite 的构建过程会更快。即使终端显示了 Stylelint 校验错误,你也不会看到 Vite 错误遮罩层,Vite 构建也不会停止。 117 | * 118 | * 这与 [vite-plugin-checker](https://github.com/fi3ework/vite-plugin-checker) 类似,但 [vite-plugin-checker](https://github.com/fi3ework/vite-plugin-checker) 可以在浏览器中显示错误。 119 | * 120 | * @default false 121 | */ 122 | lintInWorker: boolean; 123 | /** 124 | * Lint `include` option specified files once in `buildStart` hook to find potential errors. This is disabled by default. 125 | * 126 | * This will significantly slow down Vite first starting if you have no caches and don't enable `lintInWorker`. 127 | * 128 | * 在 `buildStart` 生命周期中校验 `include` 选项指定的文件一次以发现潜在的错误。默认禁用。 129 | * 130 | * 如果你没有缓存而且没有启用 `lintInWorker`,这将大大降低 Vite 的初次启动速度。 131 | * 132 | * @default false 133 | */ 134 | lintOnStart: boolean; 135 | /** 136 | * Whether or not to checkout only modified files that are not included in the `exclude` option value when running Stylelint outside of the `buildStart` lifecycle. Enabled by default. 137 | * 138 | * When disabled, files are checked against the `include` and `exclude` option values. 139 | * 140 | * 在 `buildStart` 生命周期之外运行 Stylelint 时,是否只校验修改过且没有包含在 `exclude` 选项值内的文件。默认启用。 141 | * 142 | * 禁用时,会根据 `include` 和 `exclude` 选项值确定需要校验文件。 143 | * 144 | * @default true 145 | */ 146 | lintDirtyOnly: boolean; 147 | /** 148 | * Emit found errors. This is enabled by default. 149 | * 150 | * 输出发现的错误。默认启用。 151 | * 152 | * @default true 153 | */ 154 | emitError: boolean; 155 | /** 156 | * Emit found errors as warnings. This is disabled by default but you may want it enabled when 157 | * prototyping. 158 | * 159 | * 将发现的错误作为警告输出。默认禁用,但你可能会在开发原型时启用这个。 160 | * 161 | * @default false 162 | */ 163 | emitErrorAsWarning: boolean; 164 | /** 165 | * Emit found warnings. This is enabled by default. 166 | * 167 | * 输出发现的警告。默认启用。 168 | * 169 | * @default true 170 | */ 171 | emitWarning: boolean; 172 | /** 173 | * Emit found warnings as errors when enabled. This is disabled by default. 174 | * 175 | * 将发现的警告作为错误输出。默认禁用。 176 | * 177 | * @default false 178 | */ 179 | emitWarningAsError: boolean; 180 | } 181 | export type StylelintPluginUserOptions = Partial; 182 | 183 | export type LintFiles = ( 184 | config: { 185 | files: FilterPattern; 186 | stylelintInstance: StylelintInstance; 187 | formatter: StylelintFormatter; 188 | options: StylelintPluginOptions; 189 | }, 190 | context?: Rollup.PluginContext, 191 | ) => Promise; 192 | 193 | export type TextType = "error" | "warning" | "plugin"; 194 | -------------------------------------------------------------------------------- /packages/core/src/utils.ts: -------------------------------------------------------------------------------- 1 | import { createFilter, normalizePath } from "@rollup/pluginutils"; 2 | import pico from "picocolors"; 3 | import type * as Rollup from "rollup"; 4 | import { COLOR_MAPPING, PLUGIN_NAME, STYLELINT_SEVERITY } from "./constants"; 5 | import type { 6 | Filter, 7 | LintFiles, 8 | StylelintFormatter, 9 | StylelintInstance, 10 | StylelintLinterOptions, 11 | StylelintLinterResult, 12 | StylelintPluginOptions, 13 | StylelintPluginUserOptions, 14 | TextType, 15 | } from "./types"; 16 | 17 | export const getOptions = ({ 18 | test, 19 | dev, 20 | build, 21 | cache, 22 | include, 23 | exclude, 24 | stylelintPath, 25 | formatter, 26 | lintInWorker, 27 | lintOnStart, 28 | lintDirtyOnly, 29 | emitError, 30 | emitErrorAsWarning, 31 | emitWarning, 32 | emitWarningAsError, 33 | ...stylelintOptions 34 | }: StylelintPluginUserOptions): StylelintPluginOptions => ({ 35 | test: test ?? false, 36 | dev: dev ?? true, 37 | build: build ?? false, 38 | cache: cache ?? true, 39 | include: include ?? ["src/**/*.{css,scss,sass,less,styl,vue,svelte}"], 40 | exclude: exclude ?? ["node_modules", "virtual:"], 41 | stylelintPath: stylelintPath ?? "stylelint", 42 | formatter: formatter ?? "string", 43 | lintInWorker: lintInWorker ?? false, 44 | lintOnStart: lintOnStart ?? false, 45 | lintDirtyOnly: lintDirtyOnly ?? true, 46 | emitError: emitError ?? true, 47 | emitErrorAsWarning: emitErrorAsWarning ?? false, 48 | emitWarning: emitWarning ?? true, 49 | emitWarningAsError: emitWarningAsError ?? false, 50 | ...stylelintOptions, 51 | }); 52 | 53 | export const getFilter = (options: StylelintPluginOptions) => 54 | createFilter(options.include, options.exclude); 55 | 56 | export const initializeStylelint = async (options: StylelintPluginOptions) => { 57 | const { stylelintPath, formatter } = options; 58 | try { 59 | const module = await import(stylelintPath); 60 | const stylelintInstance = (module?.default ?? module) as StylelintInstance; 61 | const loadedFormatter: StylelintFormatter = 62 | typeof formatter === "string" 63 | ? await stylelintInstance.formatters[formatter] 64 | : formatter; 65 | // use as here to avoid typescript error 66 | // src/utils.ts(58,14): error TS2742: The inferred type of 'initializeStylelint' cannot be named without a reference to '.pnpm/postcss@8.4.27/node_modules/postcss'. This is likely not portable. A type annotation is necessary. 67 | return { stylelintInstance, formatter: loadedFormatter } as { 68 | stylelintInstance: StylelintInstance; 69 | formatter: StylelintFormatter; 70 | }; 71 | } catch (error) { 72 | throw new Error( 73 | `Failed to initialize Stylelint. Have you installed and configured correctly? ${error}`, 74 | ); 75 | } 76 | }; 77 | 78 | export const getStylelintLinterOptions = ( 79 | options: StylelintPluginOptions, 80 | ): StylelintLinterOptions => ({ 81 | ...options, 82 | allowEmptyInput: true, 83 | }); 84 | 85 | // https://github.com/vitejs/vite/blob/main/packages/vite/src/node/plugins/importMetaGlob.ts 86 | // https://vitejs.dev/guide/api-plugin.html#virtual-modules-convention 87 | export const isVirtualModule = (id: string) => 88 | id.startsWith("virtual:") || id[0] === "\0" || !id.includes("/"); 89 | 90 | export const getFilePath = (id: string) => normalizePath(id).split("?")[0]; 91 | 92 | export const shouldIgnoreModule = (id: string, filter: Filter) => { 93 | // virtual module 94 | if (isVirtualModule(id)) return true; 95 | // not included 96 | if (!filter(id)) return true; 97 | // // xxx.vue?type=style or yyy.svelte?type=style style modules 98 | const filePath = getFilePath(id); 99 | if ([".vue", ".svelte"].some((extname) => filePath.endsWith(extname))) { 100 | return !(id.includes("?") && id.includes("type=style")); 101 | } 102 | return false; 103 | }; 104 | 105 | export const colorize = (text: string, textType: TextType) => 106 | pico[COLOR_MAPPING[textType]](text); 107 | 108 | export const log = ( 109 | text: string, 110 | textType: TextType, 111 | context?: Rollup.PluginContext, 112 | ) => { 113 | console.log(""); 114 | if (context) { 115 | if (textType === "error") context.error(text); 116 | else if (textType === "warning") context.warn(text); 117 | } else { 118 | console.log(`${text} Plugin: ${colorize(PLUGIN_NAME, "plugin")}\r\n`); 119 | } 120 | }; 121 | 122 | export const lintFiles: LintFiles = async ( 123 | { files, stylelintInstance, formatter, options }, 124 | context, 125 | ) => 126 | await stylelintInstance 127 | .lint({ ...getStylelintLinterOptions(options), files }) 128 | .then(async (linterResult: StylelintLinterResult) => { 129 | // do nothing when there are no results 130 | if (!linterResult || linterResult.results.length === 0) return; 131 | let results = linterResult.results.filter((item) => !item.ignored); 132 | if (!options.emitError) { 133 | results = results.map((item) => ({ 134 | ...item, 135 | warnings: item.warnings.filter( 136 | (warning) => warning.severity !== STYLELINT_SEVERITY.ERROR, 137 | ), 138 | })); 139 | linterResult.errored = false; 140 | } 141 | if (!options.emitWarning) { 142 | results = results.map((item) => ({ 143 | ...item, 144 | warnings: item.warnings.filter( 145 | (warning) => warning.severity !== STYLELINT_SEVERITY.WARNING, 146 | ), 147 | })); 148 | } 149 | results = results.filter((item) => item.warnings.length > 0); 150 | if (results.length === 0) return; 151 | 152 | linterResult.results = results; 153 | const formattedText = formatter(results, linterResult); 154 | const formattedTextType: TextType = linterResult.errored 155 | ? options.emitErrorAsWarning 156 | ? "warning" 157 | : "error" 158 | : options.emitWarningAsError 159 | ? "error" 160 | : "warning"; 161 | return log(formattedText, formattedTextType, context); 162 | }); 163 | -------------------------------------------------------------------------------- /packages/core/src/worker.ts: -------------------------------------------------------------------------------- 1 | import { parentPort, workerData } from "node:worker_threads"; 2 | import debugWrap from "debug"; 3 | import { PLUGIN_NAME } from "./constants"; 4 | import type { 5 | StylelintFormatter, 6 | StylelintInstance, 7 | StylelintPluginOptions, 8 | } from "./types"; 9 | import { 10 | getFilePath, 11 | getFilter, 12 | initializeStylelint, 13 | lintFiles, 14 | shouldIgnoreModule, 15 | } from "./utils"; 16 | 17 | const debug = debugWrap(`${PLUGIN_NAME}:worker`); 18 | 19 | const options = workerData.options as StylelintPluginOptions; 20 | const filter = getFilter(options); 21 | let stylelintInstance: StylelintInstance; 22 | let formatter: StylelintFormatter; 23 | 24 | const initPromise = initializeStylelint(options).then((result) => { 25 | stylelintInstance = result.stylelintInstance; 26 | formatter = result.formatter; 27 | return result; 28 | }); 29 | 30 | // this file needs to be compiled into cjs, which doesn't support top-level await 31 | // so we use iife here 32 | (async () => { 33 | debug("==== worker start ===="); 34 | debug("Initialize Stylelint"); 35 | // remove this line will cause ts2454 36 | const { stylelintInstance, formatter } = await initPromise; 37 | if (options.lintOnStart) { 38 | debug("Lint on start"); 39 | lintFiles({ 40 | files: options.include, 41 | stylelintInstance, 42 | formatter, 43 | options, 44 | }); // don't use context 45 | } 46 | })(); 47 | 48 | parentPort?.on("message", async (id) => { 49 | // make sure stylelintInstance is initialized 50 | if (!stylelintInstance) await initPromise; 51 | debug("==== message event ===="); 52 | debug(`id: ${id}`); 53 | const shouldIgnore = shouldIgnoreModule(id, filter); 54 | debug(`should ignore: ${shouldIgnore}`); 55 | if (shouldIgnore) return; 56 | const filePath = getFilePath(id); 57 | debug(`filePath: ${filePath}`); 58 | lintFiles({ 59 | files: options.lintDirtyOnly ? filePath : options.include, 60 | stylelintInstance, 61 | formatter, 62 | options, 63 | }); // don't use context 64 | }); 65 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - playground 3 | - docs 4 | - packages/* 5 | - examples/* 6 | -------------------------------------------------------------------------------- /simple-git-hooks.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "pre-commit": "npx lint-staged", 3 | "commit-msg": "npx commitlint --edit ${1}", 4 | }; 5 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "lib": ["DOM", "DOM.Iterable", "ESNext"], 5 | "module": "ESNext", 6 | "moduleResolution": "Bundler", 7 | "target": "ESNext", 8 | "resolveJsonModule": true, 9 | "paths": { 10 | "core": ["./packages/core/src/index.ts"] 11 | }, 12 | "strict": true, 13 | "esModuleInterop": true, 14 | "skipLibCheck": true, 15 | "skipDefaultLibCheck": true, 16 | "types": ["node"] 17 | }, 18 | "exclude": [ 19 | "**/dist/**", 20 | "**/node_modules/**", 21 | "**/client/**", 22 | "**/playground/**", 23 | "**/examples/**", 24 | "**/fixtures/**", 25 | "**/interactive/**", 26 | "**/test/dts/**" 27 | ] 28 | } 29 | --------------------------------------------------------------------------------