Hacker News new | past | comments | ask | show | jobs | submit login
Closure Compiler in JavaScript (googleblog.com)
228 points by espeed on Dec 6, 2016 | hide | past | favorite | 104 comments



    > How does this work?
    > 
    > This isn't a rewrite of Closure in JavaScript. Instead, we compile 
    > the Java source to JS to run under Node, or even inside a plain old
    > browser. Every post or resource you see about Closure Compiler will
    > also apply to this version.
Pretty wild.


I'm really interested in how they did that. Do they have an internal Emscripten equivalent for Java bytecode? Or would it be more like a source code conversion compiler a la Nim or Haxe?


Far less glamorous and way more old school, it's the later case - GWT can compile Java to JavaScript.


Wait, how is that a thing? I'm a pure JS developer (for now) but I don't understand how something framed on desktop OSs could compile to JS, a browser language. Does it compile to Node maybe? Which version of JS?

EDIT: I'm googling now to learn more but I'm not asking to challenge anybody, I'm asking because probably you guys know more than me and I wanna know how this works.


There's no intrinsic property of “desktop” languages preventing them targeting “browser” languages. Any Turing-complete language can be compiled to and from any other.

And you don't even need to go down to that level of abstraction for Java-to-JavaScript, the two share many commonalities. Java classes can become JavaScript objects, Java methods can become JavaScript functions, Java exceptions can become JavaScript exceptions, and so on.

There's some things you can't directly translate (64-bit integer math, for instance), but these can be emulated.

As for “desktop” OS facilities, the browser may not be able to provide all of these, but whatever you need can be substituted (file access can be replaced with e.g. localStorage) or worked around.


So I don't know much about Java, but I was under the impression that it compiles to a binary fie (like C), and thus could do things that directly affect the hardware like malloc. How would Javascript handle something like that? I'm not aware of Javascript being able to perform these kinds of tasks. I guess they just have workarounds, like what you're saying for file access?


It's java source to javascript source compilation(/translation/transpilation), so you only need to follow the semantics of the language, not the actual implementation.

As a simple example, if you create an array of numbers in Java, you don't need to worry about how the memory for that is allocated as long as you get an array of numbers in javascript.

The difficulties are more in how you get around where the two languages differ widely and making sure you match the semantics (often subtle) of the source language without tanking performance in the target language.

For that example of a numeric array, Java has very different expectations when it comes to bounds checking and exactly what numeric type is in there, for instance, and that has to be enforced by the code you generate if you are going to have any sort of sanity while authoring in the source language.


>...so you only need to follow the semantics of the language, not the actual implementation.

Wouldn't you need to follow the syntax and not the semantics? Aren't the semantics what the syntax is abstracting? (I'm genuinely curious, not trying to flame.)


Not OP, but I'm pretty sure you care more about the semantics here.

The syntax is really just one way to express an intention. What you care about are the intensions--the meanings. That's exactly what the semantics are. For example, the semantics of this statement in Java

    int foo = 1 / 0;
are very different from the semantics of this statement in JavaScript:

    var foo = 1 / 0;
even though the two are syntactically rather similar.

(In the former, Java will throw an ArithmeticException, whereas in JavaScript it will return Infinity.)

So you want to ensure that your translation is meaning preserving, that is, that the source code and the generated code are semantically the same.


In this case it doesn't apply, but Emscripten actually compiles LLVM assembly to JavaScript. The way they deal with malloc is by implement it in JS, that is, instead of calling the kernel malloc(), you're just calling a JS function that expands an array of bytes (specifically: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...)


What do you mean by 'affecting hardware'?

Compiling is separate from linking. In C, a simple program calling malloc() and nothing else will include malloc.h. That results in a lot of definitions being brought in, but no implementations. Compiling will produce an object file. Again, no implementations for malloc(), it's an empty address waiting to be filled in. When you link, it all comes together, assuming the linker can find an implementation for malloc() (and there can be many implementations).

So compiling is rather straightforward. The harder part is automatic linking -- anything Java-specific that doesn't directly exist in JS (like long ints -- https://github.com/dcodeIO/long.js), or any calls to some library that also doesn't have a direct equivalent (like, say, some Swing draw commands), will have errors at link time. You can resolve that by creating an interface-equivalent version in JS and telling the linker about it, or you can go all the way to emulating a CPU and other hardware for an OS: https://win95.ajf.me/


It compiles the Java source, not the Java bytecode, but even if it did....

Take your malloc example, you can compile a C program that uses malloc to JS, you just have write a malloc in JS that will behave the way you expect it to.

C gets compiled to assembly, assembly to machine code.

Their compiler just takes Java source and emits JS source instead of JVM bytecode.


> do things that directly affect the hardware like malloc

All your code affects the hardware in the sense of read/write RAM and run on CPUs. C and malloc has fewer layers than JS and new, but they're similar.


I mean, ultimately all a compiler really does is take one symbol stream as input, apply some rules and produce another symbol stream as output.

There's a series of steps to make this happen, but as long as the input can be represented in the output, this should always be possible. JavaScript is Turing Complete.

http://steve-yegge.blogspot.com/2007/06/rich-programmer-food...


Node is JS. And JS isn't a browser language. And similar things like Scala.js [1] have been quite popular for quite a while.

https://www.scala-js.org/


> but I don't understand how something framed on desktop OSs could compile to JS, a browser language

GWT compiles Java to JS. If the Closure Compiler is mostly Java code, you only need to implement a few native code things (like replace file loading with just giving it source code as strings) in JS to do a cross compile to javascript.



You're going to bust an internal organ when you check out Emscripten. :-)


GWT has a Java->Javascript compiler.


This is Google's JavaScript to JavaScript compiler, originally written in Java, but compiled with their Java to JavaScript compiler so that it runs in JavaScript... fair enough...


I'm not sure this is what Gosling had in mind when he said "compile once, run anywhere" :P


It's 2016, the mantra now is "Compile thee times, run slowly in a handful of web browsers"


To nitpick they are compiling separately for the js version ;)


Though if you consider JS the universal runtime (Node, Nashorn, browser), then it is just once.


We need to go deeper...


... which is JIT-compiled with their JavaScript-to-machine-code compiler.


You forgot to include V8!


Technically, this is the last "JavaScript" in the sentence.


Yeah I was trying to figure that out..haha


Can anyone comment on the state of Typescript - Google Closure integration ?


This is a great question, and to clarify for anyone not following along closely:

Some of us using TypeScript dream of a day when TypeScript emits JavaScript already annotated with type meditations which express as much of the typescript type system as possible in a way that Closure can understand, thereby making it possible for Closure to perform maximally efficient tree shaking and other magic with code that started as TypeScript. Such a thing as necessary and helpful because the addition of this detailed type data makes it possible for Closure to do a much better job that it can do with "just" untyped JavaScript.


We are working on this here:

https://github.com/angular/tsickle

It's already used within Google to effectively optimize TypeScript apps. However, someone still needs to write the integrations between tsickle and the multitude of public JS build systems and there's not a lot of pressure on me to do it (I have lots of other work to do).


Oh yes, I've been following this, at least the bits of information that emerge publicly.

But my dream is that this work could make it back into typescript itself - that a future version could possibly be persuaded to emit Closure type limitations without the help of a parallel/postprocessing pass by a tool.


I wonder if that would that change your workflow in any way? Usually people use typescript compiler to compile TS into JS and usually it's being executed by some runner (grunt, gulp, bazel...). Adding tsickle + closure compiler to the process should be essentially just adding couple of lines in the build process. I agree that it may be slower and have bugs - is that the worry?


Both Closure and TypeScript support (some of) the JSDoc type annotations and syntax (http://usejsdoc.org/). AFAICT, TypeScript supports a subset of what Closure does - so anything here should be portable between the two:

https://github.com/Microsoft/TypeScript/wiki/JSDoc-support-i...


Tsickle isn't that great, Webpack plugings are not not letting CC do the bundling. In general it's not good!


I commented elsewhere in this thread, but: tsickle is mostly the work of one person (me) who also has other responsibilities. I'd love some help on it, particularly in integrating it into the world of webpack etc.

https://github.com/angular/tsickle/graphs/contributors


I just tested moving my Typescript/React template to Google Closure using a webpack plugin. It came in at 148KB with UglifyJS, and 102KB with Google Closure running after Typescript did the ES5 conversion.

This may not be the "integration" some are seeking but it's sure a step ahead.


What do you mean by Typescript Google closure integration?

Typescript understands most of closure comment syntax. They should throw typechecking errors which they currently aren't doing.


TypeScript understands some of the comment syntax, but the type systems are different, the module systems are different, and a ton of other stuff is different. Look through the test cases in https://github.com/angular/tsickle/tree/master/test_files to see the difference between TypeScript-annotated code and Closure-annotated code.


That's a pretty awesome project. Didn't realize something like that existed.

In this case, I think closure should start to understand typescript syntax. Or typescript needs to borrow ideas from closure on minifying and dead code removal.


Does anyone know what this means for clojurescript?


Nothing. Zero benefits here for typical usage of ClojureScript. Potentially interesting for 3rd party bootstrap efforts like Planck, Lumo, etc.


True, but it helps fix the TTFX metric -- "Time to First XML" ;-) -- Derek Slager made a case for this in his talk at the Conj:

"ClojureScript for Skeptics" https://youtu.be/gsffg5xxFQI?t=20m9s

The remaining bit of Java is like "a little piece of kelp that's stuck to the hull, and even though it's little, you don't want anything stuck to the hull" (http://www.tv-quotes.com/shows/the-west-wing/quote_14096.htm...).

TTFX 1: http://clojurescript.org/guides/quick-start


To be fair, the XML is listed at the very bottom as the last of the options for getting your dependencies.


Zero technical benefits for sure, but it may help with ClojureScript's marketing. I've seen many JS developers outright dismiss ClojureScript / Closure because they don't want anything that involves Java - which is completely irrational, but a reality still.


It makes a completely self-hosted ClojureScript compiler possible.


It already is, except for the final Closure Compiler pass.


And that is precisely why this makes a completely self-hosted compiler pass possible.


is java a requirement though? or was it only a requirement because of google closure?


Java is no longer required.


clojurescript still requires clojure for macros, no?


No, ClojureScript has been bootstrappable since late summer 2015. Everything already runs in JavaScript. It's just that now the final optional optimization pass can also run in JavaScript.


I created a ticket and posted this to the ClojureScript discussion group a few mins ago:

https://groups.google.com/d/msg/clojurescript/jMSQChpCdhg/p7...


So this is a shameless, inexcusable plug but as it's relevant to the blog post...

If you're using Google Closure with Gulp in your work flow, you may find gulp-gjslint useful (https://github.com/TomSeldon/gulp-gjslint).

It's a gulp wrapper around gjslint, I. E. a Google Closure linter. :)


Thanks! I'm fairly new to JS. I introduced a new dependency on a node module and for some reason gulp-uglify isn't working on production mode. I'm going to give this a try.


What's with all these similar and confusing names; Closure Compiler, Clojure, Clozure CL?


So "Closure" is a real comp sci word used to describe variable scope lifetimes in languages includes JavaScript and others. So when google named their project, they basically took a word from JavaScript/CompSci that starts with the same letter as "Compiler" (plus other similar sounds). I don't think there's much more to it than that.

"Clojure" is a programming language again based on the regular word "closure" but with some twists: The "j" is a tip of the hat to Java and the JVM where clojure is designed to run. This also has the nice property that the "zh" sound of the "s" in closure is also used with "j" sometimes (I think due to French). Thirdly I believe the "CL" letters of clojure are a tip to Common Lisp.

I'm not familiar with "Clozure CL" but the history is here: http://ccl.clozure.com/history.html


> So when google named their project, they basically took a word from JavaScript/CompSci that starts with the same letter as "Compiler" (plus other similar sounds). I don't think there's much more to it than that.

Isn't it because it can optimize the output so that it only includes those dependencies that the program references, i.e. the whole program is like a closure that closes over its dependencies?


Thanks for explaining, but it remains confusing! And it seems so unnecessary.

In general, I think you should not pick names from the domain where your product/tool operates in. For example, it would be equally confusing if a car manufacturer would brand its cars "Engine" or "Wheel". Such naming is worse than just choosing a fantasy name.

P.S.: As another example, "Java" was a good name. But then Netscape invented a language and called it "JavaScript", which was of course a very poor choice.


Right? Keep that in mind when you name your next language or project :)


I call dibs on "Cloxure."


I heard that Rich Hickey chose Clojure because it has both `CLR` and `J` - initially he thought Clojure will be adopted in both - .Net CLR and JVM


I may be reading more into 'initially he thought' than you meant but Clojure CLR is real and has been around for years: https://github.com/clojure/clojure-clr


I'd love to see benchmarks comparing Closure Compiler JS, UglifyJS, and Babili.



This is fantastic. I never thought I'd be celebrating yet another "now-in-JS" release, but clojure being Java was a constant pain in the CI gonads. Wonderful to finally be able to include this in generic npm packages without any crazy extraneous build steps.


Also probably 10x slower, at least! Still cool because JavaScript I guess


Interesting to see what the use case for this will be - will removing the JVM dependency really outweigh the increase in compilation time?


For portability and use within the node/npm ecosystem? Yes I think so.


Wow! The center of the maze. Now it's just a matter of time before clojurescript is self hosted and the Eschaton is Immanentized.


Earlier post: https://news.ycombinator.com/item?id=12415512

(PS Is it possible to have a biased account? I see a lot of articles I had posted, later posted by someone else make it to the front page.)


I think it's mostly just a timing issue. To make it to the front page a submission needs to garner enough upvotes at a specific rate, and it's competing with other submissions at the same time.


offtopic: googleblog.com vs blog.google?


could be a security measure.


They're both currently in use by Google.


confusingly, ClojureScript compiles to JavaScript which is compatible with Google Closure -- thereby coming full circle.

http://clojurescript.org/


    > As this compiler runs in pure JavaScript, the compiler cannot load or save files from your filesystem directly.
Why? Node.js has the fs library for that. Why do I have to use gulp?


They also support webpack out of the box. You can most likely add build tools by doing your own integration as well.


I normally don't use neither. I'm just curious on why they say that.

Would prefer a cli version like browserify. And then integrate it on other tools.


Closure compiler is awesome, and the need to spin up a JVM to run it is really my only knock against it. This should lead to a nice boost in its usage.


Bah. It still requires a build step. I will stick with Pretty Diff and its "correct" option.


performance is significantly worse for the simple example, anecdotally feels maybe 300%-400% slower.

not sure if it's just bootup time or actual compilation passes, hopefully the former and does not explode exponentially (or even linearly) with code size.


I'm sure it's just the Java-on-Node overhead. 3-4x isn't awful considering.


Why would I use this over babel?


The advanced compilation mode does some pretty powerful dead code removal and minification [1]. I guess that is available from plugins in Babel as well but Google has been using it for Gmail, Google.com etc, so it's quite battle tested.

[1]: https://developers.google.com/closure/compiler/docs/api-tuto...


Dead code removal relies heavily on writing JS in a style that allows for static analysis. Dynamic requires, heavy usage of closures, knowledge of external/global variables are all things that prevent a lot of commonjs code from being removed. https://developers.google.com/closure/compiler/docs/limitati... has more information if you're interested in the assumptions that the compiler makes.

Interestingly, we're finally starting to see these ideas get more mainstream as people adopt es6 modules and publish bundled code with explicit externs in tools like Webpack 2 and Rollup.


Works very nicely as an LLVM of sort for alt.js languages though, as they can generate JS in such a way that it matches clojure's constraints and requirements.


In my experience Babel minified better than Closure Compiler with less maintenance of the externs on my part.


Only possible in simplified mode. I highly doubt Babel comes close with full optimizations turned on in a nontrivial codebase.


With what plugins? Babel without any plugins or with the common ES2015 plugins doesn't do any minification.



Perhaps you meant UglifyJS or Babili instead?

Babel can be used in the same toolchain as Closure Compiler, they're not mutually exclusive or redundant as they perform different tasks.


They do different things.



It's not the same as Babel. You'd use it instead of Webpack, for example.


afaik babel isn't about performance, but linguistic traits.


you like lisp


Old news, article dated Wednesday, August 31, 2016


Interesting stories that haven't had significant attention yet are welcome here.


I'd appreciate if titles at least mentioned when this is the case. I thought this was an update to the Closure Compiler they released months ago.


Often that is the case. If you see one (such as this), and suggest adding a date (such as 2016-08) in a comment, it's often updated. Even having such a comment, while not visible from the front page, can be useful in and of itself.


Clojure or Closure?

What language are they talking about?


As mentioned in the article, this is the Google Closure Compiler, which is used for compiling JavaScript. There is also the Closure Compiler (for compiling JavaScript) written in Java. As the title indicates, this is about a new implementation written in JavaScript.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: