I’m submitting a bug report
Webpack version:
2.1.0-beta.21
Please tell us about your environment:
Linux
Current behavior:
I have a class named Car in the file car.ts and two other classes for the engines in another file engine.ts.
car.ts
import { V8Engine, Engine } from './engine';
class SportsCar {
constructor(private engine: Engine) {}
toString() {
return this.engine.toString() + ' Sports Car';
}
}
engine.ts
export interface Engine {
toString(): string;
}
export class V6Engine implements Engine {
toString() {
return 'V6';
}
}
export class V8Engine implements Engine {
toString() {
return 'V8';
}
}
export function getVersion() {
return '1.0';
}
console.log(new SportsCar(new V8Engine()).toString());
The car.ts file only imports the V8Engine class, but the V6Engine class also appears even in the minified file. The unused function i export from engine.ts is stripped.
When running Webpack without UglifyJS plugin, the V6Engine class is marked with /* unused harmony export V6Engine */
as expected.
But after adding the plugin i get this warning message from UglifyJS:
WARNING in car.prod.bundle.js from UglifyJs
Dropping unused function getVersion [car.prod.bundle.js:89,9]
Side effects in initialization of unused variable V6Engine [car.prod.bundle.js:73,132]
I have created a repository where the problem can be reproduced.
Cloning, installing and running npm run webpack
and npm run webpack-prod
reproduces the issue.
Don’t know if this is a bug with the Typescript transpilation, UglifyJS or the orchestration of these tools.
I’m using Typescript with es2015 modules and Webpack 2.
Expected/desired behavior:
The unused class should be removed in the minified file.
- What is the motivation / use case for changing the behavior?
- Browser: all
- Language: TypeScript 2.0-dev
I left @mishoo a message asking if he needs any help. This is pretty important to us and there is a large Typescript/Angular2 userbase.
Another possible complication is with static class fields that are initialized with a function call.
Removing the declaration of
Foo
will also remove the side-effect of the declaration.Currently, this is transpiled to defining a property in the constructor, so even with “perfect ES6 support” removing the class, the IIFE still runs, but this (and class decorators) might become a problem in the future…
We have a new kid on the block: Babili, it can strip unused classes after bundling.
See example here.
For now i only tried it with ES6 code, but it works. Only drawback it doesnt strip comments, but there is a ticket for that.
babel/minify#67
We might just need a Webpack plugin for Babili.
Any updates on this guys’n’gals?
Regarding unused classes: Transpiles (typescript, babel) need to annotate these transpiled class and minimizers need to handle this. webpack isn’t involved in this process (we already remove our reference to the export).
The spec says side effects in this package need to be evaluated. Annotating it with PURE would be incorrect according to the spec. But webpack 4 allows to opt-in into more aggressive optimization, which will do that. It will remove the module from the bundle.
TypeScript 2.5 and later emits an
@class
comment on classes to inform minifiers that there are transpiled from an ES6 class. See microsoft/TypeScript#13721 for more details.It is also worth nothing that to use this with uglify a string-replace plugin is needed to convert to
/** @class */
to/*@__PURE__*/
. see mishoo/UglifyJS#2279 for more details.