Knip

repository·main·Indexed 11 days ago

https://github.com/webpro-nl/knip

A tool to find unused dependencies, exports, and files in JavaScript and TypeScript projects. It includes a core CLI, a Language Server Protocol (LSP) implementation, a Model Context Protocol (MCP) server for AI agents, and a VS Code extension for integrated diagnostics and module graph navigation.

Tokens
102.9K
Snippets
376
Records
630
Agent score
93%

What's inside Knip

  1. What is Knip?

    main

    Knip is a project linter designed to declutter JavaScript and TypeScript projects. It performs advanced analysis to find and fix:

    • Unused dependencies: Packages in your package.json that are not actually used in your code.
    • Unused exports: Functions, variables, or components that are exported but never imported anywhere.
    • Unused files: Files within your project structure that are not part of the dependency graph.

    Knip uses fine-grained entry points based on your specific frameworks and tooling (especially in monorepos) to provide accurate and actionable results.

  2. Overview of Knip capabilities

    main

    Knip is a tool designed to find various types of issues in your codebase, such as unused files, dependencies, and exports. It provides a wide range of features to optimize the linting process, including:

    • Automation: Auto-fixing issues with --fix and auto-formatting modified files with --format.
    • Performance: Speeding up runs with --cache, using --watch for live updates, and utilizing --production mode to lint only production code.
    • Advanced Analysis: Using --trace to find where exports are used, --memory for memory insights, and --performance for timing insights.
    • Extensibility: Support for over 100 plugins, custom compilers (Astro, MDX, Svelte, Vue), and custom reporters.
    • Project Support: First-class support for monorepos/workspaces, CommonJS, and script parsing (shell scripts and package.json).
    • Customization: Using JSDoc tags to exclude exports, applying filters/rules to focus on specific issues, and using preprocessors to modify issues before reporting.
  3. Benefits of using Knip for code maintenance

    main

    Knip automates the discovery of unused files, exports, and dependencies. Using Knip helps achieve several maintenance goals:

    • Easier Maintenance: Reduces the volume of code to manage.
    • Improved Performance: Decreases startup time, build time, and bundle size by removing dead code that tree-shaking might miss.
    • Increased Security: Minimizes the attack surface by reducing the number of dependencies and code blocks.
    • Easier Onboarding: Provides clarity for new developers regarding which files and exports are actually in use.
    • Prevent Regressions: Acts as a linting tool for obsolete dependencies, exports, and files, similar to how TypeScript or ESLint work for code quality.
  4. How Knip handles Custom Elements

    main

    Knip prevents custom element classes from being reported as unused exports by recognizing their registration via web standards or specific framework decorators.

    • Native registration: Requires no configuration and is recognized automatically.
    • Framework registration: Credits the class via a framework-specific plugin. These plugins are automatically enabled when the corresponding framework is detected as a dependency in your project.
  5. Understand the performance improvements in Knip v4

    main

    Knip v4 introduces significant performance optimizations by moving away from a heavy reliance on the TypeScript findReferences method and implementing a serialization-friendly AST traversal approach.

    Key improvements include:

    • Reduced Memory Usage: Up to 50% lower memory usage because workspaces can be read and disposed of in isolation rather than keeping everything in memory.
    • Faster Execution: Up to 60% faster runs by decoupling the linting steps and optimizing the export/import matching process.
    • Serialization & Caching: Imports and exports are now stored in a format that can be serialized, paving the way for local disk caching and remote caching in the future.
    • Parallelization: The new architecture allows for potential parallelization of workspace analysis.

    Important Trade-off: In v4, unused class members are no longer reported by default. This change was made to allow the decoupling of the TypeScript language service from the linting process, which is essential for the performance gains mentioned above.

  6. How Knip plugins work

    main

    Knip plugins are automatically enabled if their related package is listed in your package.json (either in dependencies or devDependencies). For example, including astro enables the Astro plugin.

    When a plugin is enabled, it performs three main tasks:

    1. Handles configuration files: Dynamically loads and parses tool-specific config files (e.g., astro.config.mjs) to find referenced dependencies.
    2. Adds entry files: Automatically adds relevant files to the module graph (e.g., src/pages/**/*.astro) so Knip can resolve the dependency tree.
    3. Defines command-line arguments: Identifies arguments used in scripts (like -c for config files) to discover files and dependencies.
  7. Use JSDoc and TSDoc tags to manage Knip reports

    main

    Knip supports JSDoc and TSDoc tags to create exceptions for unused or duplicate exports. This allows you to include or exclude specific tagged exports from the Knip report without changing your configuration constantly.

    Important: Using tags to hide issues is generally discouraged as it can mask code smells. It is usually better to refactor the code or report a false positive to Knip.

    To use custom tags, add them to your JSDoc comments (starting with /**) and then use the --tags CLI flag to include (+) or exclude (-) them.

    Example of tagging an export:

    /** @lintignore */
    export const myUnusedExport = 1;

    Example of excluding the tag via CLI:

    knip --tags=-lintignore
    /** @lintignore */
    export const myUnusedExport = 1;
    
    /** @lintignore */
    import Unresolved from './generated/lib.js';
  8. How entry files affect Knip results

    main

    The accuracy of Knip's results depends entirely on the completeness of your entry files. If an entry file is missing from Knip's configuration, everything reachable only through that file will be incorrectly flagged as unused.

    Managing Entry Files

    • Defaults: Knip uses sensible defaults like src/index.ts automatically.
    • Plugins: Framework-specific plugins (e.g., Vitest, Astro) automatically add relevant entry points (like test files or pages) to the graph. Using the correct plugins is critical for ensuring Knip 'sees' your entire project structure.
  9. Use source conditions in package.json exports

    main

    For "source-first" monorepos, you can expose source files directly via custom conditions in the package.json#exports or #imports maps.

    If module resolution fails because the build targets (like default or import) do not exist on disk, Knip will automatically fall back to the first conditional target in the workspace package that does exist on disk, regardless of the condition's name. This allows Knip to find source files without requiring a build step or extra configuration.

    {
      "name": "@org/shared",
      "exports": {
        ".": {
          "@org/source": "./src/index.ts",
          "types": "./dist/index.d.ts",
          "default": "./dist/index.js"
        }
      }
    }
  10. How Knip handles dependencies in monorepos

    main

    Knip provides first-class support for monorepos and workspaces. It analyzes all workspaces and understands their relationships.

    By default, if a dependency is listed in the root package.json, Knip recognizes it as available to workspaces and does not require it to be listed in individual workspace package.json files. However, if you enable --strict checking, this behavior changes and dependencies may need to be explicitly declared in each workspace.

  11. Configure the `arg` object in a Knip plugin

    main

    When writing a Knip plugin, you can use an arg object to customize how command-line arguments for your tool's executables are parsed. This allows Knip to correctly identify dependencies and entry files from scripts (e.g., identifying which file is the entry point or which flag points to a configuration file).

    // Example of an arg object structure in a plugin
    const arg = {
      binaries: ['my-tool'],
      config: ['c', '--config'],
      positional: true
    };
  12. Understand the relationship between entry and project files

    main

    Knip uses entry and project patterns to determine which files to analyze and which are unused.

    • entry files: These are the starting points of your application. Knip does not report unused exports within files explicitly listed as entry files.
    • project files: This defines the scope of your codebase.

    Unused files are calculated using the formula: unused files = project files - (entry files + resolved files)

    To detect unused files correctly, ensure your project pattern covers your source code and your entry pattern covers your application entry points.