-
Notifications
You must be signed in to change notification settings - Fork 109
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
Emit /*@__PURE__*/ before class declaration #452
Comments
Do we recommend people to use uglify for dead code elimination? I thought
we'd rely on webpack for that?
|
Answering Igor's question from another thread: technically speaking, this would be very easy to do. |
@mprobst webpack doesn't eliminate anything that is reachable from the entry point via ES imports. It relies on Uglify to remove the module bodies and minify the code. Uglify however can't safely determine if a class downleveled to an IIFE is safe to remove, so it retains them all. @alexeagle I'm at the point in my research where this issue is overshadowing all the other issues and I can't make progress until this issue is fixed. Would you or someone else from the tooling team be able to implement this on a branch so that I can't test it and verify that the impact is as big as it seems? |
I imagine you can use a sed script to get most of this for experimentation purposes. Unfortunately it's a bit hard to hack this into tsickle. We either see the code before downlevelling (in which case it's a "class" keyword and there's no place to put the comment) or after downlevelling (in which case it's a soup of function calls and we don't know which ones are classes anymore). Hooking into the TS transformation pipeline would probably allow this kind of change but that's a new API that we don't use yet. |
@evmar this is exactly what I was afraid of :-( |
@evmar sed is kind of impractical, but I can try it. I wonder if forking typescript and experimenting with a fork would be better/faster way to get some reliable results that would allow me to estimate the impact of this change. |
TS is now a series of transformations. Here's the place where "class" is transformed into the function: However, I don't know how to adjust that to insert a comment. I think @rkirov has played with this API and would know. |
This would however mean that we'd need our toolchain updated to TypeScript HEAD/2.3, which is not an easy feat. |
Yeah. I think for experimentation purposes you can check out an old version of TS and hack in the change locally. I'm not sure if that's easier than doing something with sed. I think the fastest thing you can do is something like
followed by hacking up that output into a that finds those specific "var ..." lines and inserts your annotation. |
Even with TS 2.3 you can only add transforms at the beginning or the end, so it's the same power tsickle has now (just a more composable and performant implementation) I see you're saying that |
to my big surprise I found the following JS regexp replacement working quite well: function(fileBody) {
return fileBody
.replace(
/^(var (\S+) = )(\(function \(\) \{\n(?: (?:\/\*\*| \*|\*\/|\/\/)[^\n]*\n)* function \2\([^\)]*\) \{\n)/mg,
'$1/*@__PURE__*/$3'
)
.replace(
/^(var (\S+) = )(\(function \(_super\) \{\n __extends\(\2, _super\);\n)/mg,
'$1/*@__PURE__*/$3'
);
}; |
I like it! |
I dumped my hacky tool on github as a gist in case anyone wants to play with this before it's properly implemented either in typescript or in tsickle: https://gist.github.com/IgorMinar/09eadcb221a8253162078210639a344d |
Oh, and btw the size gains are totally worth the effort of rolling this out properly. |
For best
or the
|
AFAIK, there is not way to hook into the pipeline of transforms TS compiler does. The only options are run before all of them, or run after all of them. (side rant): I really wish the name picked was not 'PURE' and something more like 'UglifyHint' or 'ClassExpressionHint' etc. Purity and side-effects are concepts that everyone feels like they know, yet when hard-pressed to define them explicitly, turns out everyone has slightly different definition. People have spent years of research in trying to reshape their whole languages just to make purity and side-effects explicit (see Haskell, IO monad, etc). It is not clear how successful they are, but it is clearly not an easy task. I am forseeing 'Sticky_Pure', "pure" but pls keep it around :) |
If we really want this we could do a thing where we emit classes as /** @PURE */ class Foo and then let TS emit, and then in a second postprocessing step search for the @pure annotations and move them to the right place. Would be kind of a pain to implement though. :~( |
Re the semantics of "pure", obligatory link: |
Igor: just out of curiosity, what are the size gains like?
|
It depends on the app but basically all classes down leveled by tsc are
retained by uglify without this fix. Our code is mostly classes, so is rxjs
and material. So you can do the math. We are talking double digits. 60-70%
in some cases.
…On Thu, Mar 30, 2017, 10:01 AM Martin Probst ***@***.***> wrote:
Igor: just out of curiosity, what are the size gains like?
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#452 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AANM6NFyxOxTeyH3jd-Do45uY0E4rjNWks5rq9_WgaJpZM4Mp04Q>
.
|
The annotation was intentionally designed to be before the specific function call because it is unambiguous and the comment survives numerous uglify transforms including As for the name of the annotation, it's not important as it'd be in intermediate ES5 generated code never seen by coders. Also, the person who built the bike shed gets to name it.
Good stuff. Seems to be an easy win for your project. |
@kzc I tried using
in my webpack config, but it doesn't seem to have any effect. Why do you believe that it was supposed to make a difference? |
@IgorMinar See example in: mishoo/UglifyJS#1261 (comment) Remove the flags and see what happens. |
I'm going to close this issue, because if we were to implement this in tsickle, we'd be missing out on annotating anything that comes into the app from node_modules that has not been processed by tsickle. Instead we are either going to rely on |
Based on this research, I believe that if we were able to emit a newly supported
/*@__PURE__*/
annotation in front of class declaration and ensure that it gets preserved in the final down-leveled output,@angular/cli
and any other Uglify-based build tool chains would be able to use dead-code elimination tricks to remove all unused classes (pipes, directives and components) with the exception of unused services.There is a feature request microsoft/TypeScript#13721 to add this functionality to
tsc
, but it's unclear when/if it's going to be implemented, so I wonder how easy it would be to implement this kind of feature in tsickle so that we can experiment.What I'd like is given the following input:
I'd like tsc + tscikle to output downleveled es5 code that looks like this:
If for some reason we have a concern that
/*@__PURE__*/
could cause headaches for Closure, we can also use/*#__PURE__*/
, which is equally supported by Uglify.More info:
The text was updated successfully, but these errors were encountered: