Skip to content
This repository has been archived by the owner on Mar 10, 2024. It is now read-only.

smeijer/unimported

Repository files navigation

Archived

Important

This project is no longer maintained. There's a project called knip which has more features, and is actively maintained by Lars Kappert. Thank you for using unimported over the years! Enjoy knip, and say hi to me on Twitter/X.


unimported

Find unused source files in javascript / typescript projects.

screenshot of unimported results

While adding new code to our projects, we might forget to remove the old code. Linters warn us for unused code in a module, but they fail to report unused files.

unimported analyzes your code by following the require/import statements starting from your entry file.

The result is a report showing which files are unimported, which dependencies are missing from your package.json, and which dependencies can be removed from your package.json.

Usage

Run the following command in the root of your project (next to package.json). The result will be as shown under example

npx unimported

When running unimported from a directory that doesn't contain a package.json, it will run from the first parent directory that does. To override this behavior, and run from an alternative work directory, use the [cwd] positional argument:

npx unimported ~/dev/leaflet-geosearch

By providing the path as argument, unimported will start looking for the project root, starting at that location.

Options

Output all options in your terminal:

npx unimported --help

Init

This option will write the default ignore patterns to the .unimportedrc.json settings files. This will enable you to easily adjust them to your needs.

npx unimported --init

Update

Update, will write the current results to the ignore lists in .unimportedrc.json. You want to use this option after running and verifying a full scan. Ignore lists are used to ignore certain false positives that could not be resolved properly. This is especially useful when running unimported on a regular basis, or for example as part of a CI pipeline.

npx unimported --update

Fix

Running with the --fix argument will automatically remove unimported files from your project. This is a destructive action, so make sure that any changes you find important, are committed to your repo.

npx unimported --fix

Flow Type

By default, flow types are stripped from files containing the @flow pragma. When the --flow argument is provided, types will be stripped from all files, regardless of the pragma. This flag defaults to false, but when flow-bin is detected in one of the dependency lists in package.json.

npx unimported --flow

CI Usage

You can drop in npx unimported into your CI. It will fail if it finds any unimported files that are not explicitly set up in the unimported config file.

Cache

Unimported uses a caching system to speed up recurring checks. This cache can be disabled using --no-cache. Note that the cache should only be disabled if you are experiencing caching related problems.

npx unimported --no-cache

If you need to clear the cache, use --clear-cache.

Clear Cache

Delete the cache file and then exits without running. Note that clearing the cache will reduce performance.

npx unimported --clear-cache

Show Config

Show the runtime config and then exists without running. The config displayed is a working copy created by merging arguments, your config file, and the applied preset.

npx unimported --show-config

Show Preset

Show the preset being used and then exists without running. Note that presets are dynamic and based on your project structure. The same preset can show a different setup for different projects based on the installed packages and available files.

npx unimported --show-preset react

Omit the preset name to get a list of available presets.

npx unimported --show-preset

Example Config File

Save the file as .unimportedrc.json in the root of your project (next to package.json)

{
  "entry": ["src/main.ts", "src/pages/**/*.{js,ts}"],
  "extensions": [".ts", ".js"],
  "ignorePatterns": ["**/node_modules/**", "private/**"],
  "ignoreUnresolved": ["some-npm-dependency"],
  "ignoreUnimported": ["src/i18n/locales/en.ts", "src/i18n/locales/nl.ts"],
  "ignoreUnused": ["bcrypt", "create-emotion"],
  "respectGitignore": true,
  "scannedDirs": ["./modules"]
}

Custom module directory You can also add an optional moduleDirectory option to your configuration file to resolve dependencies from other directories than node_modules. This setting defaults to node_modules.

{
  "moduleDirectory": ["node_modules", "src/app"]
}

Custom aliases If you wish to use aliases to import your modules & these can't be imported directly (e.g. tsconfig.json in the case of Typescript or jsconfig.json if you have one), there is an option aliases to provide the correct path mapping:

{
  "aliases": {
    "@components/*": ["./components", "./components/*"]
  }
}

Note: you may wish to also add the rootDir option to specify the base path to start looking for the aliases from:

{
  "rootDir": "./src"
}

Path transformations If you wish to transform paths before module resolution, there is an option pathTransforms to specify regex search patterns and corresponding replacement values. Search patterns will be applied with the global flag and should not be enclosed by / characters. Replacement values support all special replacement patterns supported by String.prototype.replaceAll().

Here is an example for transforming the extension for relative imports from ".js" to ".ts" (this is useful for TypeScript projects configured to output pure ESM).

{
  "pathTransforms": {
    "(\\..+)\\.js$": "$1.ts"
  }
}

Scanned dirs By default the unimported files are only scanned from dir ./src. If you also wish to scan files outside ./src, add other dirs in the option scannedDirs:

{
  "scannedDirs": ["./modules", "./lib"]
}

Report

The report will look something like below. When a particular check didn't have any positive results, it's section will be excluded from the output.

summary

Summary displays a quick overview of the results, showing the entry points that were used, and some statistics about the outcome.

unresolved imports

These import statements could not be resolved. This can either be a reference to a local file. Or to a node_module. In case of a node module, it can be that nothing is wrong. Maybe you're importing only types from a DefinitelyTyped package. But as unimported only compares against dependencies, it can also be that you've added your module to the devDependencies, and that's a problem.

To ignore specific results, add them to .unimportedrc.json#ignoreUnresolved.

unused dependencies

Some dependencies that are declared in your package.json, were not imported by your code. It should be possible to remove those packages from your project.

But, please double check. Maybe you need to move some dependencies to devDependencies, or maybe it's a peer-dependency from another package. These are hints that something might be wrong. It's no guarantee.

To ignore specific results, add them to .unimportedrc.json#ignoreUnused.

unimported files

The files listed under unimported files, are the files that exist in your code base, but are not part of your final bundle. It should be safe to delete those files.

For your convenience, some files are not shown, as we treat those as 'dev only' files which you might need. More about that below.

To ignore specific results, add them to .unimportedrc.json#ignoreUnimported.

example

       summary
────────────────────────────────────────────────
       entry file 1        : src/client/main.js
       entry file 2        : src/server/main.js

       unresolved imports  : 2
       unused dependencies : 29
       unimported files    : 86


─────┬──────────────────────────────────────────
     β”‚ 2 unresolved imports
─────┼──────────────────────────────────────────
   1 β”‚ geojson
   2 β”‚ csstype
─────┴──────────────────────────────────────────


─────┬──────────────────────────────────────────
     β”‚ 29 unused dependencies
─────┼──────────────────────────────────────────
   1 β”‚ @babel/polyfill
   2 β”‚ @babel/runtime
  .. β”‚ ...
─────┴──────────────────────────────────────────


─────┬──────────────────────────────────────────
     β”‚ 7 unimported files
─────┼──────────────────────────────────────────
   1 β”‚ src/common/components/Button/messages.ts
   2 β”‚ src/common/configs/sentry/graphql.js
  .. β”‚ ...
─────┴──────────────────────────────────────────

How

Unimported follows your import statements starting from one or more entry files. For nextjs projects, the entry files default to pages/**. For Meteor projects, the entry files are read from the package.json#meteor.mainModule key. Meteors eager loading is not supported, as that mode will load all files within your directory, regardless of import statements.

For all other project types, the entry point is looked up in the following order:

  1. ./package.json#source
  2. ./src/index
  3. ./src/main
  4. ./index
  5. ./main
  6. ./package.json#main

The last option is most likely never what you want, as the main field often points to a dist folder. Analyzing a bundled asset is likely to result in false positives.

To specify custom entry points, add them to .unimportedrc.json#entry.

extensions

The resolver scans for files with the following extensions, in this specific order:

  1. .js
  2. .jsx
  3. .ts
  4. .tsx

All other files are ignored.

To specify custom extensions, add your own list to .unimportedrc.json#extensions. Note thatunimported` won't merge settings! The custom list needs to be the full list of extension that you want to support.

ignored

Also ignored are files with paths matching the following patterns:

**/node_modules/**
**/*.tests.{js,jsx,ts,tsx}
**/*.spec.{js,jsx,ts,tsx}

In case unimported is running in a Meteor project, the following paths are being ignored as well:

packages/**
public/**
private/**
tests/**

To specify custom ignore paths, add your own patterns to .unimportedrc.json#ignorePatterns. Note that unimported won't merge settings! The custom list needs to be the full list of patterns that you want to ignore.

In addition unimported will also ignore files that match your .gitignore patterns. To disable this behavior, set respectGitignore to false in your .unimportedrc.json file.

{
  "respectGitignore": false
}

Troubleshooting

Common issues or known limitations of unimported.

Export default

At this moment, we don't support the export default from './x' export syntax. Parsing files that contain those exports, will result in an error with a message like '\';\' expected. If you make use of that part of the export default from proposal, you can consider a find/replace before running unimported.

Please search for:

export default from

and replace it with

export { default } from

Unexpected results / stale cache

Please try clearing the cache if you have unexpected results, or keep getting the same results after changing the config file.

npx unimported --clear-cache

TypeScript declaration files

If you import declaration (.d.ts) files in a TypeScript project you will need to add it as an extension to .unimportedrc.json. Otherwise you will get "unresolved imports" warnings for imported declaration files.

{
  "extensions": [".ts", ".d.ts"]
}

See Also

License

MIT License

Contributors ✨

Thanks goes to these wonderful people (emoji key):

Stephan Meijer
Stephan Meijer

πŸ€” πŸ’» πŸš‡ 🚧
Punit Makwana
Punit Makwana

πŸ“–
Dane Wilson
Dane Wilson

πŸ’»
Michael Peyper
Michael Peyper

⚠️ πŸ’»
Marco Moretti
Marco Moretti

⚠️
Peter HozΓ‘k
Peter HozΓ‘k

⚠️
Jacob M-G Evans
Jacob M-G Evans

⚠️
Datner
Datner

⚠️
Cody Rose
Cody Rose

⚠️
Ahmed ElDessouki
Ahmed ElDessouki

⚠️ πŸ’»
Yago Pereira Azevedo
Yago Pereira Azevedo

⚠️
Juhana Jauhiainen
Juhana Jauhiainen

⚠️
Braydon Hall
Braydon Hall

⚠️
abeprincec
abeprincec

⚠️
Lucas Westermann
Lucas Westermann

πŸ’» ⚠️
Simon Winter
Simon Winter

πŸ’» ⚠️
Martin Ε Ε₯ovíček
Martin Ε Ε₯ovíček

πŸ“–
Kevin Decker
Kevin Decker

πŸ’» ⚠️
olidacombe
olidacombe

πŸ’»
Punit Makwana
Punit Makwana

πŸ“–
Palanisamy KK
Palanisamy KK

πŸ“–
Daniel Bartholomae
Daniel Bartholomae

πŸ“–
Danil Gontovnik
Danil Gontovnik

πŸ’»
Nathan Smyth
Nathan Smyth

πŸ’»
Peter Sieg
Peter Sieg

πŸ’» ⚠️
Joshua May
Joshua May

πŸ’» ⚠️
Nathan Weber
Nathan Weber

πŸ’»
Wlad Paiva
Wlad Paiva

πŸ’»
Tanner B. Hess Webber
Tanner B. Hess Webber

πŸ’»
Tomas Fagerbekk
Tomas Fagerbekk

πŸ’»
Valerio Belli
Valerio Belli

πŸ’»
Umut Topuzoğlu
Umut Topuzoğlu

πŸ’»
slapbox
slapbox

πŸ“–
Michael
Michael

πŸ’»
Karl Horky
Karl Horky

πŸ“–
Aditya Vandan Sharma
Aditya Vandan Sharma

πŸ’»
Aru Hyunseung Jeon
Aru Hyunseung Jeon

πŸ’»
Eric Cornelissen
Eric Cornelissen

πŸ“–
Georget Julien
Georget Julien

πŸ’»
yu-yamanoi
yu-yamanoi

πŸ’» ⚠️
Vantroy
Vantroy

πŸ’»
Lukasz Grela
Lukasz Grela

πŸ’»
Ryan Wilson-Perkin
Ryan Wilson-Perkin

πŸ’» ⚠️
Riting LIU
Riting LIU

πŸ’» ⚠️
Lukas Fritsch
Lukas Fritsch

πŸ’» ⚠️
Mathias Van de Pol
Mathias Van de Pol

πŸ’»
Foucauld Degeorges
Foucauld Degeorges

πŸ’»

This project follows the all-contributors specification. Contributions of any kind welcome!