babel / minify

:scissors: An ES6+ aware minifier based on the Babel toolchain (beta)
https://babeljs.io/repl
MIT License
4.39k stars 225 forks source link

Remove unused imports #586

Open hiendv opened 7 years ago

hiendv commented 7 years ago
// Map won't be eliminated when bundling
import Map from 'lodash.map'

There are non-pure modules with side effects. Is there any way to remove the unused import regardless of side-effect. Possible related rollup feature Thank you.

hiendv commented 7 years ago

In my case, I have a lib.esm.js file where the Map is used by one of the sub-module

import Map from 'lodash.map'
class Foo {}
const Bar = {}
class Acme {
// Map is used here
}
export { Foo, Bar, Acme }

When importing Foo from lib.esm.js and bundling

import { Foo } from './lib.esm.js'
console.log(Foo)

The bundle contains Map

boopathi commented 7 years ago

I think this is currently out of scope for Babili - imported module can have side-effects for example -

// https://example.com/foo.js
function foo() {
  console.log("foo");
}

foo(); // side effect

export default foo;
// https://example.com/bar.js
import foo from "/foo.js";
// foo is unused

Also, babili doesn't understand ES6 modules and doesn't resolve them - probably will not any time soon - as the resolution depends on the context where the modules are used - NodeJS, browsers, bundlers(webpack, rollup, browserify) with custom resolvers.

j-f1 commented 7 years ago

@boopathi You could remove the unused named exports (and then an empty {}), then remove the unused default export:

import foo, { bar, baz } from './quux'
import foo, {} from './quux'
import foo from './quux'
import './quux'

This way, you could shorten the imports without side effects.

boopathi commented 7 years ago

Oh yeah. True. That is possible. Thanks.

This could also be a part of DCE before bundling - related - https://github.com/webpack-contrib/babili-webpack-plugin/issues/8

hiendv commented 7 years ago

@boopathi

Also, babili doesn't understand ES6 modules and doesn't resolve them

Okay, I thought babili is "an ES6+ aware minifier based on the Babel toolchain" and does some magics behind the scene to resolve them. I also understand modules may have side effects but wondering if we can leverage babili for features like rollup's. Possible related rollup feature @j-f1 Sorry, could you explain more? Especially in my case. Thanks.

j-f1 commented 7 years ago

@hiendv I guess the difference is that tools like Babel/Babili are designed to operate either on single modules or the bundle as a whole; while tools like webpack or rollup take single modules and turn them into a bundle.

For example, how would Babili parse these statements?

import foo from 'bar'
// This could be any path — many bundlers let you choose how to resolve these

import foo from 'super-duper-loader?./bar'
// What if webpack changes their syntax?
// What if `super-duper-loader` actually loads content from a different file?
// What if it loads `./bar.superscript`?

Although Babili can’t necessarily understand the contents of imported files, it can remove unused parts of the imports, from import foo, { bar, baz } from './quux' toimport './quux' where possible.

hiendv commented 7 years ago

@j-f1 Thank you. So I guess the burden of pruning unused pure external imports should be on the bundler end, not babili.

probins commented 7 years ago

You could remove the unused named exports (and then an empty {}), then remove the unused default export:

import foo, { bar, baz } from './quux' import foo, {} from './quux' import foo from './quux' import './quux' This way, you could shorten the imports without side effects.

import foo where foo is unused is much the same as var foo where foo is unused, and ISTM that babili should handle both in the same way. But unused variables are a waste of space and developers should remove them from their code anyway. That's why we have linters to highlight the things :-)

hiendv commented 7 years ago

@probins You may want to read my comment for the scenario.

Alphapage commented 7 years ago

This would be a great feature, you could only check if import is used or if export binds to a declared syntax, then remove when unused. You don't need to care about file location.

abumalick commented 6 years ago

Did you find a solution for this ?

conartist6 commented 5 years ago

The feature should go in minify-dead-code-elimination right? And it should never remove and import entirely, it should only only removed unused symbols, shortening at most to import "path/to/file";.

Seems like it should be pretty easy to write.

conartist6 commented 5 years ago

Looks like the hardest part of supporting this is going to be figuring out how to make the tests. The current fixtures are all parsed as scripts, and scripts can't contain import or export keywords. So far I can't even figure out where the heck these fixture test cases are being searched for and loaded, let along how to configure whatever is loading and parsing them to treat some of them as modules.

conartist6 commented 5 years ago

Ah I figured it out. Utils is a lerna root, so test-runner is local code. It supports babel.json to set babel settings on the file. PR is up.