Skip to content

Commit 55e3f3b

Browse files
committed
Overhaul docs
1 parent be34178 commit 55e3f3b

49 files changed

Lines changed: 1555 additions & 1100 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

packages/docs/astro.config.ts

Lines changed: 59 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -46,37 +46,80 @@ export default defineConfig({
4646
},
4747
sidebar: [
4848
{
49-
label: 'Overview',
50-
items: [{ autogenerate: { directory: 'overview' } }],
49+
label: 'Start here',
50+
items: [
51+
'overview/getting-started',
52+
'explanations/how-knip-works',
53+
'overview/first-cleanup',
54+
'overview/configuration',
55+
'explanations/why-use-knip',
56+
],
5157
},
5258
{
53-
label: 'Understanding Knip',
54-
items: [{ autogenerate: { directory: 'explanations' } }],
59+
label: 'Configuration & discovery',
60+
items: [
61+
'explanations/entry-files',
62+
'explanations/plugins',
63+
'guides/configuring-project-files',
64+
'features/production-mode',
65+
'reference/configuration-hints',
66+
'features/compilers',
67+
'features/script-parser',
68+
'features/source-mapping',
69+
'features/custom-elements',
70+
'guides/namespace-imports',
71+
'guides/working-with-commonjs',
72+
],
5573
},
5674
{
57-
label: 'Features',
58-
items: [{ autogenerate: { directory: 'features' } }],
75+
label: 'Monorepos',
76+
items: ['features/monorepos-and-workspaces', 'features/integrated-monorepos', 'features/catalogs'],
5977
},
6078
{
61-
label: 'Guides',
62-
items: [{ autogenerate: { directory: 'guides' } }],
79+
label: 'Troubleshooting',
80+
items: [
81+
'guides/troubleshooting',
82+
'guides/handling-issues',
83+
'reference/known-issues',
84+
'features/auto-fix',
85+
'reference/faq',
86+
'reference/related-tooling',
87+
],
6388
},
6489
{
65-
label: 'Writing a Plugin',
66-
items: [{ autogenerate: { directory: 'writing-a-plugin' } }],
90+
label: 'Integration',
91+
items: ['guides/adopt-gradually', 'guides/using-knip-in-ci', 'guides/performance', 'reference/integrations'],
6792
},
6893
{
6994
label: 'Reference',
70-
items: [{ autogenerate: { directory: 'reference' } }],
95+
items: [
96+
'reference/cli',
97+
'reference/configuration',
98+
'reference/dynamic-configuration',
99+
'reference/issue-types',
100+
'features/rules-and-filters',
101+
'reference/jsdoc-tsdoc-tags',
102+
'features/reporters',
103+
'reference/plugins',
104+
'overview/features',
105+
'explanations/comparison-and-migration',
106+
'playground',
107+
],
71108
},
72109
{
73-
label: 'Blog',
74-
items: [{ autogenerate: { directory: 'blog' } }],
110+
label: 'Contributing',
111+
items: [
112+
'guides/contributing',
113+
'guides/issue-reproduction',
114+
{
115+
label: 'Writing A Plugin',
116+
items: ['writing-a-plugin', 'writing-a-plugin/inputs', 'writing-a-plugin/argument-parsing'],
117+
},
118+
],
75119
},
76120
{
77-
label: 'Read more',
78-
collapsed: true,
79-
items: [{ autogenerate: { directory: 'typescript' } }],
121+
label: 'Blog',
122+
items: [{ autogenerate: { directory: 'blog' } }],
80123
},
81124
],
82125
expressiveCode: {

packages/docs/scripts/generate-plugin-docs.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,11 @@ for await (const dir of directories) {
5353

5454
plugins.push([title, pluginName]);
5555

56-
const frontmatter = u('yaml', `title: ${JSON.stringify(title)}\nsidebar:\n hidden: true`);
56+
const description = `How Knip's ${title} plugin detects entry files, config files and dependencies.`;
57+
const frontmatter = u(
58+
'yaml',
59+
`title: ${JSON.stringify(title)}\ndescription: ${JSON.stringify(description)}\nsidebar:\n hidden: true`
60+
);
5761

5862
const defaults: Record<string, string[]> = {};
5963
const configFiles = typeof config === 'function' ? config({ cwd: pluginDir }) : config;
@@ -152,7 +156,12 @@ for await (const dir of directories) {
152156

153157
plugins.sort((a, b) => (a[1] < b[1] ? -1 : 1));
154158

155-
const frontmatter = u('yaml', `title: Plugins (${plugins.length})\ntableOfContents: false`);
159+
const listDescription =
160+
'The full list of Knip plugins for frameworks, build tools, test runners and linters, each linking to its reference page.';
161+
const frontmatter = u(
162+
'yaml',
163+
`title: Plugins (${plugins.length})\ndescription: ${JSON.stringify(listDescription)}\ntableOfContents: false`
164+
);
156165

157166
const tree = u('root', [
158167
frontmatter,

packages/docs/src/content/docs/explanations/comparison-and-migration.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
---
22
title: Comparison & Migration
3+
description: How Knip compares to depcheck, unimported, ts-prune, ts-unused-exports and tsr, and how to migrate from them.
34
---
45

56
First of all, Knip owes a lot to the projects on this page and they've all been

packages/docs/src/content/docs/explanations/entry-files.md

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
---
22
title: Entry Files
3-
sidebar:
4-
order: 1
3+
description: What entry files are and how Knip and its plugins find them automatically from defaults, `package.json`, plugins and dynamic imports.
54
---
65

76
Entry files are the starting point for Knip to determine what files are used in
@@ -37,34 +36,52 @@ a monorepo, this is done for each workspace separately.
3736

3837
The values you set override the default values, they are not merged.
3938

40-
Also see [FAQ: Where does Knip look for entry files?][2]
41-
4239
## Plugins
4340

44-
Plugins often add entry files. For instance, if the Remix, Storybook and Vitest
45-
plugins are enabled in your project, they'll add additional entry files. See
46-
[the next page about plugins][3] for more details about this.
41+
Plugins often add entry files. For instance, the Remix, Storybook and Vitest
42+
plugins add additional entry files. See [the next page about plugins][2] for
43+
more details about this.
4744

4845
## Scripts in package.json
4946

5047
The `package.json` is scanned for entry files. The `main`, `bin`, and `exports`
5148
fields may contain entry files. The `scripts` are also parsed to find entry
52-
files and dependencies. See [Script Parser][4] for more details.
49+
files and dependencies. See [Script Parser][3] for more details.
5350

5451
## Ignored files
5552

5653
Knip respects `.gitignore` files. By default, ignored files are not added as
57-
entry files. This behavior can be disabled by using the [`--no-gitignore`][5]
54+
entry files. This behavior can be disabled by using the [`--no-gitignore`][4]
5855
flag on the CLI.
5956

6057
## Configuring project files
6158

62-
See [configuring project files][6] for guidance on tuning `entry` and `project`
59+
See [configuring project files][5] for guidance on tuning `entry` and `project`
6360
and when to use `ignore`.
6461

62+
## Where Knip looks for entry files
63+
64+
Putting it together, Knip discovers entry files from:
65+
66+
- Default locations such as `index.js` and `src/index.ts`
67+
- The `main`, `bin` and `exports` fields in `package.json`
68+
- Entry and config files added by enabled plugins (the config files are entry
69+
files too)
70+
- Dynamic imports: `require()` and `import()`
71+
- `require.resolve()` and `import.meta.resolve()`
72+
- `new URL('./file.js', import.meta.url)`
73+
- `new Worker(…)` and `child_process` `fork`/`spawn`/`execFile` when the target
74+
is `path.join(__dirname, …)`
75+
- `module.register('./loader.js')` loader registration
76+
- Scripts the [script parser][3] extracts: `package.json` scripts, CI workflow
77+
`run` commands, and source-code calls (tagged `$` templates,
78+
`node:child_process`, `execa`, `nano-spawn`)
79+
80+
Entry files are added to the module graph, and module resolution may pull in
81+
further entry files recursively until none remain.
82+
6583
[1]: ../overview/configuration.md#defaults
66-
[2]: ../reference/faq.md#where-does-knip-look-for-entry-files
67-
[3]: ./plugins.md
68-
[4]: ../features/script-parser.md
69-
[5]: ../reference/cli.md#--no-gitignore
70-
[6]: ../guides/configuring-project-files.md
84+
[2]: ./plugins.md
85+
[3]: ../features/script-parser.md
86+
[4]: ../reference/cli.md#--no-gitignore
87+
[5]: ../guides/configuring-project-files.md
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
---
2+
title: How Knip works
3+
description: The mental model behind Knip. How entry files, the module graph and reachability decide what counts as unused, and why surprising results trace back to them.
4+
---
5+
6+
Knip finds and removes unused code and dependencies. It starts at your entry
7+
files, follows every import to the files they reach, and builds a graph of
8+
everything connected. Anything left out is reported as unused: a file no entry
9+
reaches, an export no file imports, a dependency no file uses.
10+
11+
This page explains how Knip produces its results.
12+
13+
## Build and analyze
14+
15+
Knip runs in two phases.
16+
17+
The build phase starts from the entry files. Knip reads a file, parses it,
18+
collects its imports and exports, resolves each import to another file, and
19+
repeats for every newly reached file. The result is a graph of the project:
20+
every reachable file, what it imports, and what imports it.
21+
22+
Resolution is broad by design. Knip follows custom path aliases and extensions,
23+
reads references out of config files and [shell scripts][1], and "[compiles][2]"
24+
non-standard files like `.vue` and `.svelte` so their imports are in the graph
25+
too.
26+
27+
The analysis phase queries that graph. It never re-parses anything. It walks the
28+
edges already recorded:
29+
30+
- a **file** is unused when no entry reaches it
31+
- an **export** is unused when no other file imports it
32+
- a **dependency** is unused when no file imports it (and _unlisted_ when a file
33+
imports it but `package.json` doesn't list it)
34+
35+
Analysis happens by quering the graph. Your results are only as accurate as the
36+
graph is complete. And the graph depends on your entry files.
37+
38+
## Entry files decide what Knip can see
39+
40+
The graph contains only what's reachable from an entry file. Miss one entry, and
41+
everything reachable _only_ from it looks unused.
42+
43+
Ideally you don't need to list entries by hand. Knip starts from sensible
44+
[defaults][3] like `src/index.ts`, and [plugins][4] automatically add the entry
45+
points specific to your frameworks and libraries. The Vitest plugin adds your
46+
test files, the Astro plugin adds your pages, and so on. This is why plugins are
47+
important: each one tells Knip about a whole class of files it might otherwise
48+
never reach.
49+
50+
## Findings come in chains
51+
52+
Unused results cascade. They don't appear in isolation. Say a tool generates an
53+
entry file Knip doesn't know about:
54+
55+
- that file looks unused, because nothing reaches it
56+
- every file it imports looks unused too, because nothing else reaches them
57+
- every export in those files looks unused
58+
- every dependency only those files used looks unused
59+
60+
One unreached entry can turn into dozens of findings. The chain also runs in
61+
reverse: add the entry, and the whole cascade collapses at once.
62+
63+
So read the output from the root down: **unused files first, then exports, then
64+
dependencies.** A single unused file usually explains a long list of results
65+
below it. Fix causes at the root and the rest disappears.
66+
67+
## A surprising result might be a gap, not a bug
68+
69+
When Knip flags something you're sure is used, it's based on the graph: it
70+
couldn't reach that code from an entry. The cause is usually one of:
71+
72+
- a missing entry for a tool or convention Knip doesn't know yet
73+
- a dynamic import Knip can't follow statically, or a path it can't resolve
74+
- a transitive dependency of a package that resolves only because something else
75+
installs it
76+
77+
In each case the fix is to teach Knip: add the entry, configure the plugin, list
78+
the dependency. Don't hide the result. [Configuring project files][5] and
79+
[resolving reported issues][6] cover how, issue type by issue type.
80+
81+
[1]: ../features/script-parser.md
82+
[2]: ../features/compilers.md
83+
[3]: ./entry-files.md
84+
[4]: ./plugins.md
85+
[5]: ../guides/configuring-project-files.md
86+
[6]: ../guides/handling-issues.mdx

packages/docs/src/content/docs/explanations/plugins.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
---
22
title: Plugins
3-
sidebar:
4-
order: 2
3+
description: How Knip plugins work and the difference between `config` files (parsed for dependencies) and `entry` files (added to the module graph).
54
---
65

76
This page describes why Knip uses plugins and the difference between `config`
@@ -108,7 +107,7 @@ configured.
108107

109108
:::tip[Plugins result in less configuration]
110109

111-
Plugins uses entry file patterns as defined in your configuration file of these
110+
Plugins use entry file patterns as defined in your configuration file of these
112111
tools. So you don't need to repeat this in your Knip configuration.
113112

114113
:::
@@ -202,7 +201,7 @@ jobs:
202201
- run: node scripts/build.js
203202
- run: node --loader tsx scripts/deploy.ts
204203
- run: playwright test -c playwright.web.config.ts
205-
working-dir: e2e
204+
working-directory: e2e
206205
```
207206
208207
From these scripts, the `scripts/build.js` and `scripts/deploy.ts` files will be

0 commit comments

Comments
 (0)