npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@stealthscale/vite-config-css

v0.2.0

Published

Runs Stylelint over the stylesheets a package imports.

Readme

@stealthscale/vite-config-css

@stealthscale/vite-config-css runs Stylelint over the stylesheets a package imports, as one layer the package's Vite configuration extends beside its tier. The guide is stylelint-config-standard, with seven rules over it covering selector specificity, the cascade, declaration order and the cost of an animation. The check runs during a build and behind a development server alike, and a violation fails the build unless you demote it.

Install

pnpm add -D @stealthscale/vite-config-css

The package peers on @stealthscale/vite-config-core, stylelint, stylelint-config-standard, stylelint-order, stylelint-use-nesting, stylelint-high-performance-animation, vite-plugin-stylelint, vite and vitest. Install all nine. Stylelint is handed an absolute path to the shared guide and to each plugin, resolved while this module loads, so a peer nobody installed fails the configuration rather than the check.

Usage

A package extends one tier and lists css.layers() among its other add-ons.

import * as css from "@stealthscale/vite-config-css";
import { defineConfig } from "@stealthscale/vite-config/preset/web";

export default defineConfig(import.meta.dirname, { extends: [css.layers()] });

The call returns a single contribution, and its position among the other add-ons does not change the result. The contribution appends to Vite's plugins array and does not read a key another layer sets.

A workspace root calls css.workspace(), which contributes no layer.

import * as css from "@stealthscale/vite-config-css";
import { defineConfig } from "@stealthscale/vite-config/preset/workspace";

export default defineConfig(import.meta.dirname, { extends: [css.workspace()] });

A stylesheet is checked while the package importing it builds, and a root builds no package. The call exists so a root configuration lists every add-on the same way, and dropping it changes nothing about what gets checked.

Reference

| Export | Signature | What it returns | | ----------- | ---------------------------------------- | ------------------------------------------------ | | layers | (stated?: Checked) => readonly Layer[] | One contribution named css.check | | warn | (stated: Warned) => readonly Layer[] | A removal of css.check, then a reporting check | | workspace | () => readonly Layer[] | An empty array |

Checked states what the check reads and how hard it fails. Every field is optional. Warned takes the same four and adds a required because, which is recorded against the removal and read back when somebody asks what took the check away.

| Field | Type | What it does | | -------- | ----------------------------------- | ----------------------------------------- | | also | readonly string[] | Names the globs to check | | except | readonly string[] | Names the globs to leave unchecked | | rules | Readonly<Record<string, unknown>> | Rules layered over the four sets, by name | | warn | boolean | Warns instead of failing the build |

Note: also and except replace the plugin's own lists rather than adding to them. Stating also means the check reads those globs and no others, in place of the default src/**/*.{css,scss,sass,less,styl,vue,svelte}. Stating except replaces the default node_modules and virtual:.

A name in rules that one of the four sets already declares takes the value given here. Nothing is cached between runs, so a rule you change applies on the next run rather than after a cache is thrown away.

Blocks

| Block | What it publishes | | ------- | ------------------------------------------------------------ | | rules | The four rule sets, and all() merging them into one record |

Rules

rules.all() merges the four sets into the record the check hands Stylelint.

| Rule | Set | What it refuses | | ------------------------------------------------ | ----------- | ------------------------------------------- | | selector-max-id | SELECTOR | An id in a selector | | selector-no-qualifying-type | SELECTOR | A class qualified by an element type | | declaration-no-important | CASCADE | !important on a declaration | | no-descending-specificity | CASCADE | A looser selector after a stricter one | | no-duplicate-selectors | CASCADE | The same selector written twice | | order/properties-alphabetical-order | ORDER | A block sorted any other way | | plugin/no-low-performance-animation-properties | ANIMATION | Animating anything but transform or opacity |

The shared guide leaves all seven rules to this package, and each name belongs to one set only. A test here fails when an upgrade moves one of them into the guide. Put a rule of your own in Checked.rules, which overrides the merged record rather than editing a set.

The check loads stylelint-order, stylelint-high-performance-animation and stylelint-use-nesting, because Stylelint reports a rule from a plugin it has not loaded as unknown and fails the run. Only ORDER and ANIMATION use a plugin rule, which leaves csstools/use-nesting free for you to turn on in rules.

Reporting instead of failing

Demote the check where a repository has a backlog of violations to work through.

export default defineConfig(import.meta.dirname, {
  extends: [
    css.layers(),
    css.warn({ because: "the theme package has violations to work through" }),
  ],
});

warn() takes css.check back by name and states a reporting check called css.warn in its place. Everything layers() accepts is accepted here too, so a demoted check keeps the globs and rules a repository had already configured.

Warning: the removal resolves against the layers stated above it. A configuration that lists css.warn() before css.layers(), or without it, throws while it loads. A removal that matched nothing would otherwise pass and leave the failing check in place.

Licence

MIT. See LICENSE.