Plugins
This page describes why Knip uses plugins and the difference between config
and entry
files.
Knip has an extensive and growing list of built-in plugins. Feel free to request a plugin or even write a plugin so others can benefit too!
What does a plugin do?
Plugins are enabled if the related package is listed in the list of dependencies
in package.json
. For instance, if astro
is listed in dependencies
or
devDependencies
, then the Astro plugin is enabled. And this means that this
plugin will:
- Handle configuration files like
astro.config.mjs
- Add entry files such as
src/pages/**/*.astro
- Define command-line arguments
Configuration files
Knip uses entry files as starting points to scan your source code and
resolve other internal files and external dependencies. The dependency graph can
be statically resolved through the require
and import
statements in those
source files. However, configuration files reference external dependencies in
various ways. Knip uses a plugin for each tool to parse configuration files and
find those dependencies.
Example: ESLint
In the first example we look at the ESLint plugin. The default config
file patterns include .eslintrc.json
. Here’s a minimal example:
Configuration files like this don’t import
or require
anything, but they do
require the referenced dependencies to be installed.
In this case, the plugin will return three dependencies:
eslint-config-airbnb
eslint-config-prettier
@typescript-eslint/eslint-plugin
Knip will then look for missing dependencies in package.json
and report those
as unlisted. And vice versa, if there are any ESLint plugins listed in
package.json
, but unused, those will be reported as well.
Example: Vitest
The second example uses the Vitest plugin. Here’s a minimal example of a Vitest configuration file:
The Vitest plugin reads this configuration and return two dependencies:
@vitest/coverage-istanbul
vitest-environment-happy-dom
Knip will look for missing and unused dependencies in package.json
and report
accordingly.
Some tools allow configuration to be stored in package.json
, that’s why some
plugins contain package.json
in the list of config
files.
Entry files
Many plugins have default entry
files configured. When the plugin is enabled,
Knip will add entry files as configured by the plugin to resolve used files and
dependencies.
For example, if next
is listed as a dependency in package.json
, the Next.js
plugin will automatically add multiple patterns as entry files, such as
pages/**/*.{js,jsx,ts,tsx}
. If vitest
is listed, the Vitest plugin adds
**/*.{test,test-d,spec}.ts
as entry file patterns. Most plugins have entry
files configured, so you don’t have to.
It’s mostly plugins for meta frameworks and test runners that have entry
files
configured.
For example, let’s say your Playwright configuration contains the following:
The Playwright plugin will read this configuration file and return those entry
patterns (integration/**/*-test.ts
). Knip will then not use the default entry
patterns.
You can still override this behavior in your Knip configuration:
This should not be necessary though. Please consider opening a pull request or a bug report if any plugin is not behaving as expected.
Entry files from config files
Entry files are part of plugin configuration (as described in the previous section). Yet plugins can also return additional entry files after parsing configuration files. Below are some examples of configuration files parsed by plugins to return additional entry files. The goal of these examples is to give you an idea about the various ways Knip and its plugins try to find entry files so you don’t need to configure them yourself.
Angular
The Angular plugin parses the Angular configuration file. Here’s a fragment:
This will result in src/main.ts
being added as an entry file (and
@angular-devkit/build-angular
as a referenced dependency).
Additionally, the Angular plugin returns tsconfig.app.json
as a configuration
file for the TypeScript plugin.
GitHub Actions
This plugin parses workflow YAML files. This fragment contains three run
scripts:
From these scripts, the scripts/build.js
and scripts/deploy.ts
files will be
added as entry files by the GitHub Actions plugin.
Additionally, the file e2e/playwright.web.config.ts
is detected and will be
handed over as a Playwright configuration file.
Read more about this in command-line arguments.
webpack
Let’s take a look at this example webpack configuration file:
The webpack plugin will parse this and add ./src/app.ts
and ./src/vendor.ts
as entry files. It will also add base64-inline-loader
as a referenced
dependency.
Bringing it all together
Sometimes a configuration file is a JavaScript or TypeScript file that imports dependencies, but also contains configuration that needs to be parsed by a plugin to find additional dependencies.
Let’s take a look at this example Vite configuration file:
This file imports vite
and @vitejs/plugin-react
directly, but also
indirectly references the happy-dom
and @vitest/coverage-c8
packages.
The Vite plugin of Knip will dynamically load this configuration file and
parse the exported configuration. But it’s not aware of the vite
and
@vitejs/plugin-react
imports. This is why such config
files are also
automatically added as entry
files for Knip to statically resolve the
import
and require
statements.
Additionally, ./setup-tests.ts
will be added as an entry
file.
Command-Line Arguments
Plugins may define the arguments where Knip should look for entry files, configuration files and dependencies. We’ve already seen some examples above:
Please see script parser for more details.
Summary
ISC License © 2024 Lars Kappert