-
Notifications
You must be signed in to change notification settings - Fork 12.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Pure annotation in downlevel emits #13721
Comments
If uglify adds this support we can consider emitting the comment. I am assuming this does not apply to classes with static intializers or decorated ones. |
Thanks. We'll see what happens but whether TS would be willing to add the comment is a big factor. The static initializers and decorators were brought up in the Uglify comments as well. @mammal
class Animal {
static frob = 24;
} turns into this: // The class definition itself is pure
var Animal = /** #pure */(function () {
function Animal() {
}
return Animal;
}());
// Uglify will need to decide what to do with the following (if it can drop them or not)
Animal.frob = 24;
Animal = __decorate([
mammal
], Animal); Static initializers and decorators are less common, so that's already a big step forward. Enums and namespaces are also less common and smaller than classes so they were not discussed AFAIK. I guess anything that could help drop unused code is welcome. |
@mhegazy Uglify now merged support for pure statements. |
For reference, the implementation details are here: |
For what it's worth, the pure function call comment annotation feature has been released in
|
Also switches TypeScript to emit ES2015 modules instead of CommonJS so we can take advantage of tree shaking to reduce bundle sizes. The gains here are barely noticeable though (there's an outstanding issue with how TypeScript emits classes and how Uglify interacts with that that may help once that's fixed), but every little bit helps. mishoo/UglifyJS#1261 microsoft/TypeScript#13721 webpack/webpack#2899 TODO: Look to see if we can convert more of our more imports to ES2015 to impove tree shaking.
I was musing some more and while you're considering this issue I'd like to try to push it further. Adding Because it's impossible to prove that decorators are side-effect free (and in the strict sense they most often are not), any class that has a decorator cannot be tree-shaken, no matter if ES5 or ES6. I think it is possible, with two changes:
// Turn this Typescript code:
/*#__PURE__*/
@cacheable
class Frob { }
// Into this ES6 emit:
var Frob = class { };
Frob = /*#__PURE__*/__decorate([cacheable], Frob);
var Frob = __decorate([cacheable], class {}); And this can be tree-shaken if decorated with a pure comment. This comment from Uglify team explains the various patterns that work (or not) in more details. Bonus round: |
I explored this for the use in Angular and can confirm that all downleveled classes previously retained by Uglify are being correctly removed if the IIFEs are prefixed with the annotation. I'd love to see TS emit the |
@DanielRosenwasser please follow up with relevant teams to see what we can do |
This could solve a considerable amount of size bloat problems for angular users attempting to minify their transpiled TS. |
We have some reservations on the use of Would |
Uglify already supports Barring that, could you have the typescript compiler allow the user to override the annotation string? |
I understand.
I am saying this convention is wrong; pure functions already have a well defined meanings in the realm of programming languages, compilers and optimizers. using the same term to mean something different is misleading at best. |
Not in love with any I have come up with but |
Maybe |
We discussed this int he last design meeting, and the conclusion was to use something declarative like
|
This small change has a fairly significant impact on our tests. While I'm not opposed to the change, do we want to always emit the |
Fixed, pending PR. |
@AlgusDark I don't think it will improve on the surprising ways the compiler can remove comments, at least not in general. It will however directly address the underlying feature you're trying to implement. Namely annotating each class so that Uglify can tree-shake it. After PR #16631 lands you can just have to replace |
@Koslun the problem here is that I'm doing it in a function, not a class transpiled by TypeScript. So I believe that we need to check why compiler is removing that comment at the beginning of the function call, since that's something I want to keep. My code is in a HOC from React: const HOC = /*@__PURE__*/withHelpersModifiers(Component)
export default HOC; |
Minifiers like Uglify try to remove dead code from minified builds.
To completely remove a declaration, they have to prove that it is side-effect free.
Unfortunately in JS this is often not possible as pretty much anything can have arbitrary effects.
An important issue is that ES5 emit for
class
can't easily be determined to be side-effect free.As a result, tree-shaking is ineffective. In simple words: no class is removed from the output, even if it is never used.
A very simple solution could be to have a hint for the minifier, inside a special comment.
If the emit added a
/** #pure */
comment at the beginning of ES5 classes it could easily be detected and removed by Uglify.This is an important enhancement that can dramatically reduce the size of unused code, especially in large libraries like Angular or Aurelia.
Is this something the TS team would consider?
Original discussion in Uglify: mishoo/UglifyJS#1261
I am aware of #3882 and #7770 and this is not the same.
Those issues are about extending the language to include some "pure" annotations.
This issue is just about adding a hint (comment) inside the emit template.
The text was updated successfully, but these errors were encountered: