Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: webpro-nl/knip
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 3.3.3
Choose a base ref
...
head repository: webpro-nl/knip
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 3.3.4
Choose a head ref
  • 4 commits
  • 6 files changed
  • 1 contributor

Commits on Nov 30, 2023

  1. Add nice tweet to testimonials

    webpro committed Nov 30, 2023

    Verified

    This commit was signed with the committer’s verified signature.
    mrdrogdrog Mr. DrogDrog
    Copy the full SHA
    f947b0a View commit details
  2. Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    6292c7f View commit details
  3. Copy the full SHA
    7513521 View commit details
  4. Release 3.3.4

    webpro committed Nov 30, 2023
    Copy the full SHA
    b6c284e View commit details
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion packages/docs/src/components/Tweets.astro
Original file line number Diff line number Diff line change
@@ -10,14 +10,15 @@ const BEARER_TOKEN = import.meta.env.BEARER_TOKEN;
const isFetch = ENVIRONMENT !== 'development' && Boolean(BEARER_TOKEN);
const tweetIds = [
'1730180003453927560',
'1691460974518353920',
'1729181106715632088',
'1729157761215369264',
'1727040036334424406',
'1726807293583609935',
'1714023231689031941',
'1696221274039595363',
'1693944495472046382',
'1691460974518353920',
'1691120132901240832',
'1685298103094554625',
'1581910299846012928',
99 changes: 99 additions & 0 deletions packages/docs/src/content/docs/guides/performance.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
---
title: Performance
---

This page describes a few topics around Knip's performance, and how you might
improve it.

Knip does not want to tell you how to structure files or how to write your code,
but it might still be good to understand inefficient patterns for Knip.

## Star Imports and Barrel Files

Knip builds up a simplified graph of imports and exports and can quickly match
them against each other to find unused exports. However, there might not be a
literal match for exports that are imported using the `import *` syntax. In this
case, Knip will ask the TypeScript compiler to find references, which is a lot
more work. More levels of re-exports and star imports are more expensive.

Barrel files with re-exports look like this:

```ts
export * from './model';
export * from './util';
```

Example of a star import:

```ts
import * as MyNamespace from './helpers';
```

Use the [`--performance` flag](../reference/cli.md#--performance) to see how
often `findReferences` is used and how much time is spent there.

This article explains the issue in more detail: [Speeding up the JavaScript
ecosystem - The barrel file debacle][1]. The conclusion: "Get rid of all barrel
files".

## Workspace Sharing

Knip "bundles" files from separate workspaces into a single TypeScript program
if the configuration in `tsconfig.json` allows. This saves memory and time. The
relevant compiler options are `baseUrl` and `paths`:

- If the `compilerOptions.baseUrl` is not set explicitly
- If there are no conflicting keys in `compilerOptions.paths`

With the `--debug` flag you can see how many programs Knip uses. Look for
messages like this:

```sh
...
[*] Installed 2 principals for 29 workspaces
...
[*] Analyzing used resolved files [P1/1] (123)
...
[*] Analyzing used resolved files [P1/2] (8)
...
[*] Analyzing used resolved files [P2/1] (41)
...
```

The first number in `P1/1` is the number of the program, the second number
indicates additional entry files were found in and added to the same program
during the first round.

## GitIgnore

Knip looks up `.gitignore` files and uses them to filter out matching entry and
project files. This increases correctness. Your project may have multiple
`.gitignore` files across all folders. It slows down finding files using glob
patterns and in some cases significantly.

You might want see if it's possible to disable that with `--no-gitignore` and
enjoy a performance boost.

To help determine whether this trade-off might be worth it for you, first check
the difference in unused files:

```sh
diff <(knip --no-gitignore --include files) <(knip --include files)
```

And to measure the difference of this flag in seconds:

```sh
SECONDS=0; knip > /dev/null; t1=$SECONDS; SECONDS=0; knip --no-gitignore > /dev/null; t2=$SECONDS; echo "Difference: $((t1 - t2)) seconds"
```

Analysis on a sample large project went down from 33 to 9 seconds (that's >70%
faster).

## A Last Resort

In case Knip is unbearable slow (or even crashes), you could resort to [lint
individual workspaces][2].

[1]: https://marvinh.dev/blog/speeding-up-javascript-ecosystem-part-7/
[2]: ../features/monorepos-and-workspaces.md#lint-a-single-workspace
2 changes: 1 addition & 1 deletion packages/knip/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "knip",
"version": "3.3.3",
"version": "3.3.4",
"description": "Find unused files, dependencies and exports in your TypeScript and JavaScript projects",
"homepage": "https://knip.dev",
"repository": {
4 changes: 3 additions & 1 deletion packages/knip/src/typescript/resolveModuleNames.ts
Original file line number Diff line number Diff line change
@@ -27,7 +27,9 @@ export function createCustomModuleResolver(
) {
function resolveModuleNames(moduleNames: string[], containingFile: string): Array<ts.ResolvedModuleFull | undefined> {
return moduleNames.map(moduleName => {
const key = `${containingFile}:${moduleName}`;
const key = moduleName.startsWith('.')
? join(dirname(containingFile), moduleName)
: `${containingFile}:${moduleName}`;
if (resolutionCache.has(key)) return resolutionCache.get(key)!;
const resolvedModule = resolveModuleName(moduleName, containingFile);
resolutionCache.set(key, resolvedModule);
2 changes: 1 addition & 1 deletion packages/knip/src/version.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export const version = '3.3.3';
export const version = '3.3.4';