DEV Community

Dementii K
Dementii K

Posted on

Stylelint plugin using Typescript

Stylelint is a useful tool to maintain styles code quality and lint CSS as well as its preprocessors. It already has a vast amount of rules and plugins that will cover most of the cases. But from time to time, you may need something specific to your project that has little or no value for other teams and therefore isn't worth a place in npm.

In the case of my project, global CSS imports were used multiple times across different components. This mistake, without proper attention, resulted in an additional 700kb of useless CSS. However, it could have been easily avoided with the help of a pre-commit hook and a custom Stylelint plugin.

But this article is not about the plugin itself (it is well described in a doc), but about using its TypeScript version.

What's the problem with that?

Languages used in a Stylelint project

Since Stylelint is written in JS, it is not possible to just add a reference to a plugin written in TS, meaning there can be several possible solutions:

  • precompile the TS before launching Stylelint
  • use ts-node

ts-node - TS execution engine that lets you run TS code without compiling it.

The easiest way to use a plugin

Just register ts-node in a JS config. That being said styleling.config.js needs only a few lines of code besides including the plugin in the config.

require('ts-node').register({
    project: require('node:path').join(__dirname, 'tsconfig.json')
});
Enter fullscreen mode Exit fullscreen mode

But this ease of use comes with a price. It may be suitable for smaller projects with a small number of styling files to lint. Or when Stylelint is used in a pre-commit hook (which means there will not be that many files in most cases).

Several dozen files already cause a noticeable delay of several seconds. Linting all files for rather large projects results in a Node exception since a new instance of ts-node will be created for every linted file.

Fix performance penalty

The solution for the problem described above is to register ts-node once. This can be achieved with a modified command that launches Stylelint.

node --require ts-node/register ./node_modules/stylelint/bin/stylelint.js
Enter fullscreen mode Exit fullscreen mode

Stylelint API

If you don't want to mix TS and JS in a config file making, it invalid, it is also possible to create a script that will use the Stylelint API. The benefit is that it is possible to run linting without a custom plugin, and it is also slightly faster.

package.json
"stylelint": "node ts-node --project tsconfig.json stylelint.ts"
Enter fullscreen mode Exit fullscreen mode

stylelint.ts
import stylelint from 'stylelint';
import config from './stylelint.config';

const [n, cmd, ...files] = process.argv;

async function lint() {
  try {
    const report = await stylelint.lint({
        files: !files.length ? ['**/*.less'] : files,
        config: {
            ...config,
            plugins: [
                // path to plugin
            ],
            rules: {
                ...config.rules
                'my-custom-rule': true
            }
        }
    });

    // check if the report has errors and exit if any
  } catch {
    process.exit(1);
  }
};

lint();
Enter fullscreen mode Exit fullscreen mode

Performance comparison

1 file 50 files 800 files
Vanilla JS Plugin 0.55s 1.8s 16.1s
Stylelint API 0.93s 1.8s 14.6s
ts-node singleton 2s 3.5s 16.5s
ts-node in config file 2s 4.9s max call stack error

Top comments (0)