find-unused-exports
find-unused-exports copied to clipboard
Support import maps
Support for aliases would make this tool useful in my project.
Interesting 🤔
Webpack opens a can of works because you can modify anything to do anything else via webpack config. Generally, I keep bundler config to a minimum and avoid clever aliasing and things so that tooling such as import path linting and this one doesn’t get confused.
What is your specific use case (a monorepo?), and what would be the ideal way this package could support it (as in, how would it work)?
There are probably quick hack ways, that would break down in a lot of situations.
We could sniff a webpack config file, and extract the resolve
config and use enhanced-resolve
when converting the import specifiers to absolute file paths in here:
https://github.com/jaydenseric/find-unused-exports/blob/v1.1.1/public/findUnusedExports.js
But, that is very fragile:
- Webpack can have an array of configs for multiple builds (e.g. server, browser, etc.), that could have totally different
resolve
config. We can only use one at a time, so do we do multiple passes, one for each config, and consider exports unused across all the builds to be unused? - Webpack
resolve
config actually doesn't apply to every file in the project; it applies to files bundled by Webpack. You could have a script file for example in the project that doesn't get bundled at all, and it would be incorrect to resolve it's import specifiers using the webpack config. So how do you know what files are bundled by Webpack? Only webpack knows, and after building everything.
Probably the most efficient way to deal with the these problems is to use a webpack plugin to find unused exports; some already exist. Although, it is possible for a project file to be used by both bundled and non-bundled code, and an export could be unused according to the webpack plugin when in fact is is used by an seperate non-bundled script.
Moral of the story, stick to standards, don't be too clever with your build tooling, webpack config is the devil 😅
Another thing to consider is that there are other bundlers than just webpack; an ideal solution would work for all users.
The "dumbest" approach would be to add an alias
option, that accepts a hardcoded map. We could use cosmiconfig
to load find-unused-exports
config, since it's a map is a little unwieldy to pass in as CLI arguments. A user could potentially use the .js
format for the config, and import their webpack config and manually extract the alias
config from it and massage it to the find-unused-exports
alias format (if we don't exactly match the webpack format), so that way the config is DRY and shared by both tools.
This feature would be a huge help! I'm sure it's nightmarish to implement and support every edge case, but any sort of workaround would be great. We use aliases for some of our packages to facilitate importing based on the environment (Electron vs React Native for example.) Manually copying our aliases to something like a .unusedexportsrc
file would be trivial compared with the benefits of this project.
Thank you for your hard work @jaydenseric!
Thinking about this fresh, and especially after working with web standard import maps in browsers and Deno with JSPM, adding support for import maps is probably the best way forward.
I'm currently retooling from Node.js to Deno, so if import maps are relatively easy to add here there is a chance I will get to it in the course of doing client Node.js project work. Otherwise, I might leave it for a bigger Deno rewrite. A lot of things we're doing here are vastly easier in Deno (e.g. globs), but I'm not sure yet how much we want to stick with Babel as there might be better options in Deno land.
Wow cool, I'd never even heard of import maps!
I won't pretend to understand the full difficulties of supporting aliases, but those sound like a really great approach.
As far as Babel support goes, my guess is that they'll end up supporting Deno since it's increasingly gaining traction. There's at least a hint that they might decide to support Deno in 8.x or above.
+1
My project uses create react app. At first it didn't work cause it was not seeing my babel config on the root folder. I added babel with preset react and the tool started to work but it wasn't taking the path alias into account. With CRA I'm using path aliases through jsconfig however, since I noticed this tool wanted my babel config to work I tried setting up aliases through babel config but it didn't work there.
My project would also benefit from alias support. Even if it is a dumb alias of some kind that we set it ourselves the config.
:+1: for a simple map,
I use aliases to anchor local imports to the module root, so you don't have to think about ../components
vs ../../components
.
(Webpack: resolve.alias = { src: resolve(__dirname, '../src') }
, tsconfig: "paths": { "src/*": ["src/*"] }
, imports ...from 'src/components'
)
Something like find-unused-exports --map='src -> ./src'
would be enough for this use case.
(My workaround for now is
perl -i -pe 's/from '\''src\//from '\''..\//' src/*/*.*
perl -i -pe 's/from '\''src\//from '\''..\/..\//' src/*/*/*.*
perl -i -pe 's/from '\''src\//from '\''..\/..\/..\//' src/*/*/*/*.*
npx find-unused-exports --module-glob 'src/**/*.{js,ts,jsx,tsx}' --resolve-file-extensions 'tsx,ts,jsx,js' --resolve-index-files
perl -i -pe 's/from '\''\.\.\//from '\''src\//' src/*/*.*
perl -i -pe 's/from '\''\.\.\/\.\.\//from '\''src\//' src/*/*/*.*
perl -i -pe 's/from '\''\.\.\/\.\.\/\.\.\//from '\''src\//' src/*/*/*/*.*
)