microsoft / TypeScript

TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
https://www.typescriptlang.org
Apache License 2.0
100.52k stars 12.43k forks source link

Suggestion: minification #8

Closed RyanCavanaugh closed 1 year ago

RyanCavanaugh commented 10 years ago

TypeScript should support emitting minified JavaScript.

There are several different things we could support:

  1. Just remove whitespace
  2. Minify unobservable identifiers
  3. Remove provably dead code
  4. Whole-program minification (i.e. closure compiler)
  5. (Others?)
ToddThomson commented 8 years ago

For anyone who is interested.. I've experimented with walking the container nodes and minimizing blockscopedvariables. This requires a minimal amount of code, so I'm going to add it to TsProject on NPM and GitHub . It will work only on bundles. As for whitespace removal, there is currently no way to change the way that indentation works in the js text writer. However, It is also a simple task to use the Typescript Scanner in a post emit step to remove all whitespace trivia and newline trivial.

bryanerayner commented 8 years ago

Fantastic! That's a great first step.

On Sat, Dec 12, 2015, 5:08 PM Todd Thomson notifications@github.com wrote:

For anyone who is interested.. I've experimented with walking the container nodes and minimizing blockscopedvariables. This requires a minimal amount of code, so I'm going to add it to TsProject. It will work only on bundles. As for whitespace elimination, there is currently no way to change the way the indentation works in the js text writer, so this will have to be done as a processing step after the bundle emit.

— Reply to this email directly or view it on GitHub https://github.com/Microsoft/TypeScript/issues/8#issuecomment-164200832.

richmwatts commented 8 years ago

Can someone please clarify if minification of the TypeScript output is likely to be problematic using tools such as uglify? Some of the files in a project I'm working on seem to minify correctly while others do not.

am11 commented 8 years ago

@richwatts, generally it should not be problematic but sometimes configuring the uglify is bit unpalatable. I recently had issues with jQuery and some other (non-AMD) plugins in the mix. I was using gruntfile.js to produce single minified file. Here is the how the configuration looks like:

(gruntfile.js in the root of simple 'website' project)

/// <binding ProjectOpened=uglify/>

// the above line is produced & parsed by VS2015's Task Runner Explorer for
// binding the grunt/node.js task with EnvDTE events.

module.exports = function (grunt) {
  require('load-grunt-tasks')(grunt); 
  var jsBinBase = 'assets/bin/'; 

  grunt.initConfig({
    uglify: { 
      options: { 
        compress: true, 
        mangle: { 
          except: ["$super"], 
          toplevel: true 
         }, 
        sourceMap: true 
       }, 
       target: { 
         src: [ // mixed sources, AMD and non-AMD
           'assets/js/rickshaw/vendor/d3.v3.js',  // needs to be in order
           'assets/js/jquery-2.1.1.js', // needs to be in order
           'assets/js/jquery-ui/jquery-ui.js',  // needs to be in order
           'assets/js/**/*.js', // include all js files generated by tsc or otherwise
           '!assets/bin/**'  // this is exclusion
         ], 
         dest: jsBinBase + 'app.min.js' 
       } 
     }
  });

  grunt.registerTask('default', ['uglify']);
};

(package.json side by side with grunt.js)

{ 
   "version": "0.0.1", 
   "name": "Dummy", 
   "private": true, 
   "devDependencies": { 
     "grunt": "^0.4.5", 
     "grunt-contrib-uglify": "^0.11.0",
     "load-grunt-tasks": "^3.3.0" 
  } 
} 

As you can see, i had to hand pick some dependencies in targets to make it work. But in case you are using everything-AMD, you wouldn't need to care about the targets order.

If you have similar setup, you can generate the combined output from tsc with source maps and then in the above grunt example change sourceMap: true to sourceMap: 'path/to/your-output.js.map'. With that, uglify will generate mapping between min file and the actual ts file (not just min.js to js), which comes handy when debugging with browser dev tools.

NoelAbrahams commented 8 years ago

@richwatts, uglify will not minify private methods.

ghost commented 8 years ago

@NoelAbrahams, private method has nothing to do with uglify.

Private visibility is a design-time construct; it is enforced during static type checking but does not imply any runtime enforcement. ... TypeScript enforces encapsulation of implementation in classes at design time (by restricting use of private members), but cannot enforce encapsulation at runtime because all object properties are accessible at runtime. Future versions of JavaScript may provide private names which would enable runtime enforcement of private members

He (@richwatts) is not uglifying a "typescript file" but the "typescript output", which is JavaScript file..

NoelAbrahams commented 8 years ago

@jasonwilliams200OK, well yes. I think most people on this forum understand private methods without recourse to a quote.

NoelAbrahams commented 8 years ago

The point about private methods is, given the following TypeScript

class Foo {

    public myPublicMethod(){
        this.myPrivateMethod();
    }

    private myPrivateMethod(){
    }
}

We get JavaScript output:

var Foo = (function () {
    function Foo() {
    }
    Foo.prototype.myPublicMethod = function () {
        this.myPrivateMethod();
    };
    Foo.prototype.myPrivateMethod = function () {
    };
    return Foo;
})();

Running the JavaScript output through uglify produces:

var Foo=function(){function t(){}
return t.prototype.myPublicMethod=function(){
this.myPrivateMethod()},
t.prototype.myPrivateMethod=function(){},t}();

This minification is inefficient, because the private method should have been reduced to a single character, say a instead of myPrivateMethod. Doing so would improve minification by 4% for this simple example. Unfortunately, uglify cannot do anything about it (without further annotation) because the TypeScript compiler emits both the private and public methods on the prototype, so that there is no distinguishing between the two.

Those writing JavaScript libraries would typically write their code in such a way as to obtain better minification, for example:

    function Foo() {
    }
    Foo.prototype.myPublicMethod = function () {
        myPrivateMethod.call(this);
    };

    function myPrivateMethod() {
    };

It is therefore likely that many library developers are put off from using TypeScript because of these inefficiencies.

So, while using uglify is not "problematic" as such, it will not be as efficient as minification generated by a system that understands private methods, that is, minification generated directly by TypeScript.

electricessence commented 8 years ago

^^ yes! Exactly. :)

ghost commented 8 years ago

@NoelAbrahams, while I agree that TypeScript has better context to improve the compression, the private methods issue you are describing is non-existent with UglifyJS if you use the correct switches:

npm install uglify-js

:: with --mangle-props
.\node_modules\.bin\uglifyjs --mangle --mangle-props -- yourexample.js
var Foo=function(){function o(){}o.prototype.a=function(){this.b()};o.prototype.b=function(){};return o}();
:: ^107 chars

:: without --mangle-props
.\node_modules\.bin\uglifyjs --mangle -- yourexample.js
var Foo=function(){function t(){}t.prototype.myPublicMethod=function(){this.myPrivateMethod()};t.prototype.myPrivateMethod=function(){};return t}();
:: ^148 chars
eggers commented 8 years ago

but, don't you want publicMethod not to be mangled?

ghost commented 8 years ago

@eggers, then you use an additional switch --mangle-regex="/Private/". As a library author, if you are using some convention like underscrore before/after the private properties names, then this option is for you.

kitsonk commented 8 years ago

Which is why it is best left to tools that are designed to minify. While TypeScript might have more context, there has been a lot put into the minfication tools to make them work in the myriad of use cases. The only improvement I can really see is that it "intelligent" minification is built into a build pipeline that utilises the language services of tsc to provide some guidance. Integrating that directly into TypeScript though seems to be an anti-design goal:

  1. Provide an end-to-end build pipeline. Instead, make the system extensible so that external tools can use the compiler for more complex build workflows.

as well as:

  1. Aggressively optimize the runtime performance of programs. Instead, emit idiomatic JavaScript code that plays well with the performance characteristics of runtime platforms.

Which is why I guess I am still surprised @RyanCavanaugh is suggesting it.

ghost commented 8 years ago

@kitsonk, I agree.

postcss is an AST for CSS. Any CSS utility (compiler, compressor, linter) which implements postcss gives the free advantage of integrating all the other utilities built on top of postcss via piping. This integration is not "just" pipe contract either; they can share the context (the actual AST!) with each other.

I wonder if there is any general purpose AST built for JavaScript, which TypeScript, CoffeeScript, Uglify, SweetJS, LiveScript, JSHint, JSCS etc. can get compliant with to be able to "share the context" with each other and yet provide legendary experience -- as opposed to each implementing redundant features in different ways which BTW also goes against the DRY and single responsibility principles.

NoelAbrahams commented 8 years ago

Unfortunately, this discussion has been sidetracked by spurious arguments (by those, I suspect, not really familiar with real-world minification problems).

As I said above

uglify cannot [minify private methods] _(without further annotation)_

Without asking owners of code-bases spanning tens of thousands of LOC to carry out special annotation, there is _no tool in the present evironment_ that can effectively minify _TypeScript generated_ code.

A number of real-world problems have been discussed above, such as dealing with properties that are bound to the DOM (which shouldn't be minified). TypeScript can make a difference here. Please do take the time to read through the comments.

We are at present facing a script that is approaching many hundreds of KB and this feature suggestion remains critical for us.

ghost commented 8 years ago

I am well familiar with real-world minification problems. I am simply explaining what is possible with Uglify today.

Please do take the time to read through the comments.

Have you read mine? I am not against this proposal.

Please speak for yourself only and don't be sarcastic. So we are sharing thoughts here and this conversation is well on topic (Uglify is relevant).

NoelAbrahams commented 8 years ago

@jasonwilliams200OK, sorry, no offence intended. I do urge you to stop making impractical suggestions, though :smile:.

kitsonk commented 8 years ago

Unfortunately, this discussion has been sidetracked by spurious arguments (by those, I suspect, not really familiar with real-world minification problems).

That was a bit rude and uncalled for, and rather ill-informed.

I am very familiar with real-world minification challenges. Also you stated:

It is therefore likely that many library developers are put off from using TypeScript because of these inefficiencies.

I can tell you, as a CTO of a major company behind one of the largest open source JavaScript libraries hasn't dissuaded us from TypeScript. Maybe you should do a bit of research before you toss out throw away comments like that.

You originally stated:

uglify will not minify private methods.

@jasonwilliams200OK indicated that you could, providing a working example, which you dismiss out of hand. How does that become?

I do urge you to stop making impractical suggestions, though

Even with a smiley, that is uncalled for...

NoelAbrahams commented 8 years ago

Congratulations on your job.

The first suggestion was impractical, because it also minifies public methods. The second suggestion is intrusive, because it involves annotating private methods and/or following some sort of convention, such as an underscore prefix.

ghost commented 8 years ago

You are seeing it as intrusive, I take it as room for improvement in Uglify, on which many users rely today. Turned out I am not alone as I have found this: https://github.com/mishoo/UglifyJS2/issues/103. See the comments by @jrhite. It is possible to control what properties to mangle in uglify today with programmatic usage, though further improvements might be required as the issue is still opened. TypeScript team can still take dependency on UglfiyJS in implementing this feature by injecting the context and controlling the internal steps.

Like i mentioned earlier, if TypeScript support some common AST core with foreign interface like postcss provides for CSS (so you can plug/swap minifier of your choice or any utility) and LLVM provides for native langs, then these features can be provided more effectively in a modular and extensible manner.

Please do implement this feature, preferably by engaging Uglify.

To sum up, we can achieve the same goal with one of the following approaches:

@NoelAbrahams, no problem. Same goal, different approaches. Like i said earlier, we are sharing thoughts and I provided information on what can be achieved today. Final decision on how will come from TypeScript team.

jrhite commented 8 years ago

@jasonwilliams200OK - I have no skin in this, but just an update. mishoo/UglifyJS2#103 should be closed as full support is already there. Additionally, another feature was added which allows very useful control over which properties do and don't get mangled. Check the uglify2 docs for more info.

--mangle-regex Only mangle property names matching the regex

Cheers!

DanielRosenwasser commented 8 years ago

I know everyone's looking for the best direction for the project, so let's keep that in mind and try to keep the discussion civil and driven by the issue at hand.

NoelAbrahams commented 8 years ago

@jasonwilliams200OK,

I think your suggestion of TypeScript producing JavaScript output annotated in a language that Uglify (and perhaps other minifiers) can understand is probably the easiest route forward at present. This would work for us as we already use Uglify for our minification.

RyanCavanaugh commented 8 years ago

Which is why I guess I am still surprised @RyanCavanaugh is suggesting it.

@kitsonk TypeScript issues 1 through 22 were manually ported by me from the old CodePlex site based on number of votes they had at the time. I don't really remember why we picked that number.

Honestly for all the comments that have been logged here, I'm shocked that there doesn't seem be be a reference implementation based on some very straightforward usage of the language service.

NoelAbrahams commented 8 years ago

@RyanCavanaugh,

Honestly for all the comments that have been logged here, I'm shocked that there doesn't seem be be a reference implementation based on some very straightforward usage of the language service.

If the TypeScript team is not going to implement this feature then I suggest this issue be closed. That may motivate someone to take this up. It would also help us in the decision to consider looking for alternatives.

This was one of the earliest issues raised (7th of October 2012 - just a few days after TypeScript went public), received a large number of votes before being moved to GitHub (6th in terms of number of votes), and three years later there has been no resolution.

RyanCavanaugh commented 8 years ago

We haven't ruled it out. If someone has waited three years without looking for an alternative, they apparently don't need minification all that badly and I'm inclined to not proceed with it.

This has been sitting in "Needs Proposal" because, as I've outlined here many times, we're looking for someone to present a compelling case that TypeScript itself can do a substantially better job than off-the-shelf minifiers, in a way that is general-purpose enough to work for most people.

Our current belief is that this might be possible, but is almost certainly a huge amount of work that we could spend in more productive ways. I don't think it would be a great trade-off for us to invest engineer-months in a minifier that is 3% better than what's sitting on NPM today in exchange for not having a smarter type system or not having better editor support or not having the compiler be 15% faster.

If someone put up a fork with a prototype minification algorithm that produced substantial minification gains over the competition, we'd find that very convincing. If no one is bothering, that really is a sign that while everyone might enjoy the pleasant convenience of built-in minification, it's not a area where we can deliver a lot of value.

NoelAbrahams commented 8 years ago

If someone has waited three years without looking for an alternative, they apparently don't need minification all that badly

In our own case, this was initially not a big concern, because the code-base was smaller. But as we deal with more feature requests, each accompanied by growth in code, this is becoming critical.

If no one is bothering

My point is that so long as this feature is open, the expectation is that TypeScirpt will do something about it.

we're looking for someone to present a compelling case that TypeScript itself can do a substantially better job than off-the-shelf minifiers,

I agree that something more than simply minification of private methods would be required for TS to implement minification entirely by themselves. But providing output that Uglify can understand might be a start. I might have a go at providing more justification, but can't promise anything at the moment due to work commitments.

Our current belief is that this might be possible, but is almost certainly a huge amount of work that we could spend in more productive ways

Not sure how "a reference implementation based on some very straightforward usage of the language service" suddenly turned into a "huge amout of work" :smiley:

ivogabe commented 8 years ago

With a transform based compiler (#5595) this would probably be a lot easier to implement in the compiler or using an external project.

joelgwebber commented 8 years ago

[apologies for the wall of text]

I think Ryan's suggestion that the state "NeedsProposal" means "it's not yet been made clear how to do this in a way that's a clear win over alternatives" is perfectly reasonable. There does need to be some way to express that concept.

I can speak a little to whether the current state of affairs is "good enough". Our current deployment process produces two output scripts, one of which is fairly small (~45k uncompressed) but highly size-sensitive because it's loaded in customers' pages, the other being larger (~500k uncompressed) and growing rapidly as we add features. These are produced via tsc --out [...] and closure --compilation_level=SIMPLE_OPTIMIZATIONS. I've tested various options through uglifyjs and gotten similar output, so I think we can safely assume this is close to the best we can do without type-aware optimization. This is "good enough" for the time being, but it's going to become a problem eventually. The issues we're likely to run into are download time over slow networks; but more importantly, parse time on mobile devices. The latter can be significant because parsing blocks the UI thread, and happens every time the script's evaluated (i.e., the parsed output is in-memory only, and thus not cached).

Eyeballing the final output and comparing it to the GWT output I pasted above (or any code run through either GWT or closure with "advanced" optimizations), I'd be willing to bet that we could cut these files by about 40% pre-gzipping. That's a bit of a wild-assed guess, but with the enormous number of unmangled identifiers in the output, along with the lack of inlining and other relatively simple optimizations (c.f. https://www.fullstory.com/s/fs.js), I doubt it's far off. And that kind of improvement would give us a lot more headroom for future development.

So, what's required to get this level of optimization? Reliable type information. If you look at the approach that tools like uglifyjs uses, e.g. to mangle property names, you'll see that it's kind of a hack (which is the best you can do without type information) -- you have to give it a list or pattern of identifiers that are "safe" to rename, and if you miss anything the output will be broken in unpredictable ways. OTOH, if you look at either the GWT or Closure (in "advanced" mode) compilers, you'll see that they carefully track the types of all expressions. This allows them to know not just which identifiers are private and can be renamed, but also which are external to the program (e.g., if I write window.ExposedThing = internalFunction, I need to know both that I can mangle internalFunction, and not ExposedThing).

I've considered digging into tsc to see whether it's feasible to do something similar, but have put it off both because of time constraints, and because I'm not certain whether it's compatible with the team's goals. My biggest concern is that there seems to be more of a focus on single-file compilation and working with the various --module options, than there is on monolithic compilation using ///<reference> directives. But producing globally-optimized output conflicts to a certain degree with single-file compilation. If anyone on the team could offer some insight into whether continuing to improve monolithic compilation is an explicit goal, that would help me decide whether to devote time to the problem (and recruit others I know using Typescript to contribute to optimizations).

joelgwebber commented 8 years ago

It's probably worth roughly sketching out what I think could work in the context of Typescript:

Because the language allows untyped expressions, and that they're fairly common, it's likely unrealistic to take quite the same approach as when compiling a much stricter source language like Java. Because the GWT compiler can rely on knowing the precise (and generally singular or very small) set of types for each expression, it can be extremely aggressive in renaming identifiers and allocating those names. Referring to the output fragment I pasted above, you'll see lots of things like:

function abc(a,b) { if (a.a == b.a) {b.b(a, b); }
// ...

Outside of external references, you'll see essentially no human-readable identifiers, and the names are mostly linearly allocated in small scopes (so you get lots of a, b, ..., aa, ab, etc). If you're careful about sorting the output, you can even get significant improvements in gzip performance by reducing entropy within the compression window.

With less-reliable type information, I suspect it would be much easier to rely on a single scope for allocating mangled identifiers (with the possible exception of function parameters, which most optimizers already rename locally). So in essence you'd end up with a single "rename dictionary" which would contain all the identifiers that can be safely renamed, such that all instances of someIdentifier get renamed to abc, regardless of their scope. This is sub-optimal, but works fairly well in practice (I believe most products that use Closure do so with the set of flags that causes it to work this way, or at least did as of a few years ago).

An identifier would be considered "rename safe" if the scopes of all references to it can be determined to originate within Typescript source. Any reference via an expression of unknown type (e.g., bar in var foo = untypedFunc(); foo.bar()) or an explicitly external type (e.g., via some_lib.d.ts) would be excluded from renaming. This works to the extent the code contains explicit or inferred type information, and removes the need for an explicit "externs" file, which is very error-prone.

It would be nice to get function/method inlining working as well, but it has stricter requirements. To get much benefit from it, you need to be able to precisely identify all references to the function. Otherwise you can't remove it. This may sound like a small win, but in code with lots of trivial accessor methods, it can really add up.

ToddThomson commented 8 years ago

I'll be posting the minification feature to TsProject this coming week. I am working out the last bits of the implementation for ES5 vs ES6 ( block scoped identifiers using let ).

ToddThomson commented 8 years ago

Here is an example of minifier in TsProject ( whitespace elimination turned off ). Source:

export class TestClass {

    private gerb1: number = 1;
    private gerb2: number = 2;
    private gerb3: number = 3;
    private gerb4: number = 4;

    public fPublic(): number {
        let result = this.f1();

        return result;
    }

    private f1(): number {
        let result = this.f2( 5, 2 ) + this.f3( 19 );

        return result;
    }

    private f2( parm1: number, parm2: number ): number {
        let result = parm1 + parm2;

        return result;
    }
    private f3( parm1: number ): number {
        return parm1 + this.f2( 1, 2 );
    }
}

var test = new TestClass();
var t1 = test.fPublic();
console.log( t1 );

min.js output...

var TestClass = (function () {
    function TestClass() {
        this.a = 1;
        this.b = 2;
        this.c = 3;
        this.d = 4;
    }
    TestClass.prototype.fPublic = function () {
        var a = this.e();
        return a;
    };
    TestClass.prototype.e = function () {
        var a = this.f(5, 2) + this.g(19);
        return a;
    };
    TestClass.prototype.f = function (a, b) {
        var c = a + b;
        return c;
    };
    TestClass.prototype.g = function (a) {
        return a + this.f(1, 2);
    };
    return TestClass;
})();
exports.TestClass = TestClass;
var a = new TestClass();
var b = a.fPublic();
console.log(b);
ivogabe commented 8 years ago

@ToddThomson Can you compare and post the minified (without whitespace elimination) gzipped file size with the normal gzipped size? Gzip stores a long identifier name that is used multiple only once, so I suspect that mangling private identifiers won't make a big difference.

ToddThomson commented 8 years ago

@ivogabe I'll post statistics when the minifier feature is production ready. I suspect that there won't be great gains over post compilation gulp build tools like uglifyjs. However, my goal is to be able to realize some gains by shortening private identifiers and knowing that the resulting transformed sourcefile will work 100% of the time.

bryanerayner commented 8 years ago

Entropy can be reduced by mangling the names of private variables. If you have 25 instances of separate long names, this will be 25 different new symbols that need to be put into the Huffman table. Comparatively, 25 instances of this.a would only result in one key being added to the Huffman table (a),

I expect the compression of the latter case would be much higher.

This is great work Todd!

joelgwebber commented 8 years ago

@ToddThomson Glad to hear you're working on this! A couple of quick questions:

ToddThomson commented 8 years ago

@joelgwebber Yes, the main reason I use TsProject is to produce a single bundled output for multiple ES6 modules in separate source files. Yes, it is a public GitHub repository. There's a link above to the TsProject bundle minification issue that will take you to the repository.

joelgwebber commented 8 years ago

Thanks, @ToddThomson. Got a 404 for that branch, but I see now that it's been merged.

ToddThomson commented 8 years ago

@joelgwebber , @bryanerayner I've published TsProject 1.2.0-rc.3 to NPM. It now includes proper handling of class inheritance. I've also added a sample minified typescript app to the GitHub repository.

ToddThomson commented 8 years ago

@RyanCavanaugh I'm not sure how my basic support for identifier minimizing and whitespace elimination can be brought to Typescript. It appears to me that what I've provided in TsProject would be easily achievable within Typescript, but it is something that should be designed and implemented by the core group.

ToddThomson commented 8 years ago

Last post concerning minification in TsProject. With the latest NPM release, I've built TsProject.min.js with full whitespace elimination. I also took the non-minified tsproject.js and ran it through the online JSCompress tool: Here are the results: TsProject.js 110,908 TsProject.min.js 42,125 TsProject.js through jscompress online: 47,940. TsProject.js through Uglify online: 42,722 Not startling results, but a pretty good start.

Final update - With non-external functions, classes and import namespace aliases minified:

TsProject.js 132,963 TsProject.min.js 40,389

TsProject.min.js is a node package built using TsProject.min.js.

mmacfadden commented 8 years ago

Just to pile on to this issue... We are currently starting a new JS project and are primarily trying to decide between TypeScript and the Google Closure Compiler. Both offer the ability to add static typing to JavaScript (ish) applications. In my view, TypeScript has much better tooling and is in general a more pleasant development experience. It's integration with IDE's is good, the compiler is much faster than closure, the syntax is better (less verbose), and to tool chain is better.

However, we really do like the ADVANCED_COMPILATION mode. It can:

It does significantly better than using something like UglifyJS on transpiled TypeScript. The files output by the closure compiler are significantly smaller. Although I a no expert in how this is achieved, as others have mentioned it seems to be that the fact that the "minifier" in closure is type-aware allows it to do more aggressive minification. UglifyJS (and the like) do not have this benefit. Doing optimizations and minification inside the type script transpiler should allow it to outperform "bolt on" minifiers.

I am not sure if we will use Closure or TypeScript, but I can say that this particular issue is one of the main decision points for us.

mhegazy commented 8 years ago

@mmacfadden, I do not see this as an either/or. I know of many teams including Google Angular 2 team that use Typescript + Google Closure Compiler advanced optimizations and are satisfied by the results. You will need something like https://github.com/angular/sickle to convert TS types into JSDoc comments.

mmacfadden commented 8 years ago

@mhegazy, thanks for the reply we had seen a few TS -> closure projects out there but they seemed very out of date. Although I had searched, I had not come across this project before. It may be a viable option. I have two comments:

  1. I do get worried with projects like this only because there are now three things that have to work well together in order for my build to work. If type script adds a new (relevant) feature, it then needs to be added to sickle. It also then needs to be something that actually is possible to do in closure. The Sickle developers are (perhaps) not on the TypeScript team nor the Closure team, so there is some risk there that at some point in the future the two will not play nice together. Or that the Sickle tool becomes unmaintained. There is just some risk there.
  2. From a build complexity standpoint I now have two things I need to wrangle instead of one. Not a big deal, but still a small consideration.

So if I had a magic wand I would love to see this capability right in TypeScript. I do realize, being a developer myself) that the TS team needs to focus on their sweet spot of functionality and that building a Type Aware minifcation system probably is slightly out of their sweet spot. I am totally willing to take a look at Sickle and if it works... great, I think my immediate issue will be solved. But again, assuming a magic wand, I would still love to see this in TS directly.

Again thanks for pointing this project out. I will definitely take a look.

mhegazy commented 8 years ago

type aware minification is not all what advanced optimizations in closure compiler. if that is the only thing you need @ToddThomson's work should do the trick.

mmacfadden commented 8 years ago

You are correct. I am looking for more than just Type Aware minification. Being type aware does let you do some other interesting optimizations, but you are correct there are more things that it does. I am also interested in what @ToddThomson is doing.

raphaelfeng commented 8 years ago

Hi @mhegazy, would like to know how the angular 2 team use the TypeScript together with Google Closure Compiler. Looks that the uglify is used in the angular2 github repository https://github.com/angular/angular/blob/4a414420e940bf4a5eea2c870ddff6e33f0343b9/gulpfile.js#L1273.

mhegazy commented 8 years ago

//CC @mprobst from the angular team to answer this question.,

mprobst commented 8 years ago

@mmacfadden @raphaelfeng we're still experimenting around, there's no definite answer from our side yet. We're using uglify and seeing good results with that.

We're also building sickle and a compilation toolchain that pipes from TypeScript through Closure Compiler. We hope to possibly give better optimization results from that than uglify itself - mostly due to property renaming, dead code elimination, but also inlining, type specialization, and a host of other tricks. However it is true that it will cause a more complicated build setup expect (e.g. users will need to install Java), and issues when the two tools might not agree. It's hard to know if the end result will be nice to use before trying.

We don't quite know yet where this will lead, but will keep people posted. Keep an eye on https://github.com/angular/sickle for our progress.

mmacfadden commented 8 years ago

@mprobst, thanks! I am optimistic that something like sickle could be more successful because the angular team and the typescript teams are working closely together and also because Closure is a Google product. So it's not as though some independent and unrelated folks are trying to do the work. Definitely interested in sickle and will monitor the project.