• Stars
    star
    441
  • Rank 98,861 (Top 2 %)
  • Language
  • License
    Other
  • Created about 8 years ago
  • Updated over 7 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

How to use Google's Closure Compiler

Introduction ๐Ÿ‘‹

Closure Compiler handbook logo

This handbook is designed to help you understand how to use Closure Compiler and learn its features.

The Closure Compiler is a tool for making JavaScript download and run faster. Instead of compiling from a source language to machine code, it compiles from JavaScript to better JavaScript. It parses your JavaScript, analyzes it, removes dead code and rewrites and minimizes what's left. It also checks syntax, variable references, and types, and warns about common JavaScript pitfalls.

Creative Commons License

Closure Compiler can compile, optimize and bundle JavaScript code. You can use it for building your JavaScript apps for production. It is the most advanced JavaScript optimization tool. It generates smallest bundle and emits efficient JavaScript code by doing whole program analysis and optimization, removing closures, inlining function calls, reusing variable names and pre-computing constant expressions.

React + ReactDOM build comparison

Tool Output size Gzipped
Webpack 2 139KB ย  ย  ย  42KB
Closure Compiler 90KB ย  ย  ย  ย  32KB

Here's an example of compiler's compilation output:

input

function hello(name) {
  const message = `Hello, ${name}!`;
  console.log(message);
}
hello('New user');

output

console.log("Hello, New user!");

Table of Contents ๐Ÿ“–

Getting started ๐Ÿ

Closure Compiler is written in Java, but it also has JavaScript port. The best way to use it is Splittable bundler.

Installation

npm i google-closure-compiler-js

Using with Node

const compile = require('google-closure-compiler-js').compile;

const flags = {
  jsCode: [{src: 'const inc = (x) => x + 1;'}]
};

const out = compile(flags);

console.log(out.compiledCode); // 'var inc=function(a){return a+1};'

Using with Webpack

const ClosureCompiler = require('google-closure-compiler-js').webpack;
const path = require('path');

module.exports = {
  entry: [
    path.join(__dirname, 'entry.js')
  ],
  output: {
    path: path.join(__dirname, 'build'),
    filename: 'bundle.js'
  },
  plugins: [
    new ClosureCompiler({
      options: {
        languageIn: 'ECMASCRIPT6',
        languageOut: 'ECMASCRIPT3',
        compilationLevel: 'ADVANCED'
      }
    })
  ]
};

Using with Gulp

const compiler = require('google-closure-compiler-js').gulp();

gulp.task('build', function() {
  return gulp.src('enrty.js', {base: './'})
      .pipe(compiler({
          compilationLevel: 'ADVANCED',
          jsOutputFile: 'bundle.js',
          createSourceMap: true
        }))
      .pipe(gulp.dest('./build'));
});

Splittable bundler

Splittable is a module bundler for JavaScript based on Closure Compiler. Basically it's a wrapper with zero configuration which supports ES6 and code splitting out of the box.

const splittable = require('splittable');

splittable({
  // Create bundles from 2 entry modules `./src/a` and `./src/b`.
  modules: ['./src/a', './src/b'],
  writeTo: 'dist/',
})
.then((info) => {
  console.info('Compilation successful');
  if (info.warnings) {
    console.warn(info.warnings);
  }
})
.catch((error) => console.error('Compilation failed', error));

Compilation levels ๐ŸŽš

Compilation level is a compiler setting which denotes optimizations level to be applied to JavaScript code.

WHITESPACE_ONLY

Removes comments, line breaks, unnecessary spaces and other whitespace.

SIMPLE (default)

Includes WHITESPACE_ONLY optimizations and renames variable names to shorter names to reduce the size of output code. It renames only variables local to functions, which means that it won't break references to third party code from global scope.

ADVANCED

Includes SIMPLE optimizations and performs aggressive transformations such as closures elimination, inlining function calls, reusing variable names, pre-computing constant expressions, tree-shaking, cross-module code motion and dead code elimination.

This kind of aggressive compression makes some assumptions about your code. If it doesn't conform to those assumptions, Closure Compiler will produce output that does not run.

Advanced compilation ๐Ÿ‘ท

With ADVANCED compilation level Closure Compiler renames global variables, function names and properties and removes unused code. This can lead to output that will not run if your code doesn't follow certain rules.

Referencing external code

If you want to use globally defined variables and functions in your code safely, you must tell the compiler about those references.

input

// `moment` is declared in global scope
window.moment().subtract(10, 'days').calendar();

output

// `moment` was renamed to `a`
// this will not run
window.a().b(10, 'days').calendar();

The way you do it is via externs. See Externs section for more information.

Referencing compiled code

If you are about to build a library that exports to global scope, you must tell the compiler about variables that should be exported safely.

input

// `MY_APP` is declared in global scope
window.MY_APP = {};

output

// `MY_APP` was renamed to `a`
// it's no longer possible to reference `MY_APP`
window.a = {};

This should be done by exporting symbols into global scope. See Exporting to global scope section for more information.

Referencing to object properties using both dot and bracket notations

Closure Compiler never rewrites strings. You should use only one way of declaring and accessing a property:

  • declare with a symbol, access with dot notation
  • declare with a string, access with a string

input

// `msg` property is declared and accessed in different ways
obj = { msg: 'Hey!' };
console.log(obj['msg']);

output

// `msg` symbol is renamed to `a`, but `'msg'` text is not
obj = { a: 'Hey!' };
console.log(obj.msg);

Compiler optimizations ๐ŸŽ›

Closure Compiler performs a number of optimizations to produce a small output size. Some of them are being applied in intermediate compilation pass to produce AST which is suited best for further code optimization.

NOTE: Below is a list of the most interesting optimizations that compiler does. But there are more of them, you can find them all in comments in the source code of the compiler.

Dead code elimination and Tree-shaking

โ€œDead codeโ€ is a code that is never going to be called in your program. Closure Compiler can efficiently determine and remove such code because it is a whole-program optimization compiler, which means that it performs analysis of the whole program (in comparison to less effective analysis on module level). It constructs a graph of all variables and dependencies which are declared in your code, does graph traversal to find what should be included and dismisses the rest, which is a dead code.

input

/* log.js module */
export const logWithMsg = (msg, arg) => console.log(msg, arg);
export const log = (arg) => console.log(arg);

/* math.js module */
export const min = (a, b) => Math.min(a, b);
export const max = (a, b) => Math.max(a, b);
export const exp = (x) => x * x;
export const sum = (xs) => xs.reduce((a, b) => a + b, 0);

/* entry.js entry point */
import * as math from './math';
import * as logger from './log';

const nums = [0, 1, 2, 3, 4, 5];
const msg = 'Result:';

if (false) {
  logger.log('nothing');
} else {
  logger.logWithMsg(msg, math.sum(nums));
}

output

// Even though the entire modules namespace was imported,
// tree-shaking didn't include dependency code that is not used here.
// Also a dead code within `if (false) { ... }` was removed.
var c = function(a) {
  return a.reduce(function(a, b) {
    return a + b;
  }, 0);
}([0,1,2,3,4,5]);

console.log("Result:",c);

Unreachable and redundant code elimination

This optimization is a little different from dead code elimination. It removes โ€œlive codeโ€ that doesn't have an impact on a program, e.g. statements without side effects (true;), useless break, continue and return.

Cross-module code motion

Closure Compiler moves variables, functions and methods between modules. It moves the code along modules tree down to those modules where this code is needed. This can reduce parsing time before actual execution. This technique is especially useful for advanced code splitting which works on variables level, rather than modules level.

input

/* math.js module */
export const sum = (xs) => xs.reduce((a, b) => a + b, 0);
export const mult = (xs) => xs.reduce((a, b) => a * b, 1);

/* entry-1.js module */
import * as math from './math';

console.log(math.sum(nums));

/* entry-2.js module */
import * as math from './math';

console.log(math.sum([4, 5, 6]) + math.mult([3, 5, 6]));

output

/* common.js shared code */
function c(a) {
  return a.reduce(function(a, b) {
    return a + b;
  }, 0);
};

/* entry-1.bundle.js */
console.log(c(nums)); // using shared code

/* entry-2.bundle.js */
console.log(
  // using shared code
  c([4,5,6]) +
  // moved from `math.js` module
  function(a) {
    return a.reduce(function(a, b) {
      return a * b;
    }, 1);
  }([3,5,6])
);

Constant folding

Constant folding is the process of recognizing and evaluating constant expressions at compile time rather than computing them at runtime. Terms in constant expressions are typically simple literals, such as the integer literal 2 , but they may also be variables whose values are known at compile time.

input

const years = 14;
const monthsInYear = 12;
const daysInMonth = 30;

console.log(years * monthsInYear * daysInMonth);

output

console.log(5040);
// `years * monthsInYear * daysInMonth` computed at compile time
// because they are known as constants

Function call inlining

To inline a function means to replace a function call with its body. The function definition can be dismissed and it also eliminates an additional function call. If the compiler couldn't perform this type of inlining, it can inline function declaration with a call it in place.

input

const person = {
  fname: 'John',
  lname: 'Doe',
};

function getFullName({ fname, lname }) {
  return fname + ' ' + lname;
}

console.log(getFullName(person));

output

var a = { a: "John", b: "Doe" };
console.log(a.a + " " + a.b);

Property flattening (collapsing)

Collapsing object properties into separate variables enables such optimizations as variable renaming, inlining and better dead code removal.

input

const person = {
  fname: 'John',
  lname: 'Doe'
};

console.log(person.fname);

output

var person$fname = "John",
    person$lname = "Doe"; // <- is not used, can be removed

console.log(person$fname);

Variable and property renaming

Small output size is partially achieved by renaming all variables and object properties. Because the compiler renames object properties you have to make sure that you are referencing and declaring properties either with symbol (obj.prop) or string (obj['prop']).

input

const user = window.session.user;
console.log(user.apiToken, user.tokenExpireDate);

output

var a = window.b.f;
console.log(a.a, a.c);

Statement fusion (merging) & variable declarations grouping

Statement fusion tries to merge multiple statements in a single one. And variable declarations grouping groups multiple variable declarations into a single one.

input

const fname = 'John';
const lname = 'Doe';

if (fname) {
  console.log(fname);
}

output

var fname = "John", lname = "Doe";
fname && console.log(fname);

Alternate syntax substitution

Simplifies conditional expressions, replaces ifs with ternary operator, object and array constructs with literals and simplifies returns.

RegExp optimization

Removes unnecessary flags and reorders them for better gzip.

Known methods folding

This precomputes known methods such as join, indexOf, substring, substr, parseInt and parseFloat when they are called with constants.

input

[0, 1, 2, 3, 4, 5].join('');

output

"012345"

Property assignment collection

Looks for assignments to properties of object/array immediately following its creation using the abbreviated syntax and merges assigned values into object/array creation construct.

input

const coll = [];
coll[0] = 0;
coll[2] = 5;

const obj = { x: 1 };

obj.y = 2;

output

var coll = [0, , 5], obj = { x:1, y:2 };

Anonymous functions naming

Gives anonymous function names. This makes it way easier to debug because debuggers and stack traces use the function names.

input

math.simple.add = function(a, b) {
  return a + b;
};

output

math.simple.add = function $math$simple$add$(a, b) {
  return a + b;
};

Compiler flags ๐Ÿšฉ

There are much more compiler flags, see all of them in google/closure-compiler-js repo.

Flag Default Usage
applyInputSourceMaps true Compose input source maps into output source map
assumeFunctionWrapper false Enable additional optimizations based on the assumption that the output will be wrapped with a function wrapper. This flag is used to indicate that "global" declarations will not actually be global but instead isolated to the compilation unit. This enables additional optimizations.
compilationLevel SIMPLE Specifies the compilation level to use: WHITESPACE_ONLY, SIMPLE, ADVANCED
env BROWSER Determines the set of builtin externs to load: BROWSER, CUSTOM
languageIn ES6 Sets what language spec that input sources conform to.
languageOut ES5 Sets what language spec the output should conform to.
newTypeInf false Checks for type errors using the new type inference algorithm.
outputWrapper null Interpolate output into this string, replacing the token %output%
processCommonJsModules false Process CommonJS modules to a concatenable form, i.e., support require statements.
rewritePolyfills false Rewrite ES6 library calls to use polyfills provided by the compiler's runtime.
warningLevel DEFAULT Specifies the warning level to use: QUIET, DEFAULT, VERBOSE
jsCode [] Specifies the source code to compile.
externs [] Additional externs to use for this compile.
createSourceMap false Generates a source map mapping the generated source file back to its original sources.

Supported languages ๐Ÿ™Š

Language Option name Input Output
ES3 ECMASCRIPT3 โœ… โœ…
ES5 ECMASCRIPT5 โœ… โœ…
ES5 ECMASCRIPT5_STRICT โœ… โœ…
ES2015 ECMASCRIPT6 โœ…
ES2015 ECMASCRIPT6_STRICT โœ…
ES2015 ECMASCRIPT6_TYPED โœ… โœ…

JavaScript modules ๐ŸŒฏ

Recipes ๐Ÿœ

Externs

Extern is a JavaScript file which describes an interface of the external code. If you are going to use external function, you should declare a function with the same name, but without its body. In case when it is an object โ€” declare an object with the same name and describe its shape by provinding property names.

Once you have all of required externs, they should be passed to compiler using --externs flag per extern file, or as a value to externs property in compiler configuration if you are using a tool on top of the compiler.

input

// `moment` is declared in global scope
window.moment().subtract(10, 'days').calendar();

extern

function moment() {}

moment.prototype = {
  subtract: function() {},
  calendar: function() {}
};

output

// `moment` and its prototype methods was not renamed
window.moment().subtract(10, 'days').calendar();

Externs can be generated for most libraries, see JavaScript Externs Generator.

Exporting to global scope

If you are building a library and not using JavaScript modules, you can export functions and variables safely using bracket notation and quoted property names, since Closure Compiler doesn't rename strings.

input

function logger(x) {
  console.log('LOG:', x);
}

window['logger'] = logger;

output

// `logger` function is exported properly into global scope
window.logger = function(a) {
  console.log('LOG:', a);
};

Code splitting

Code splitting is a technique used to reduce initial script loading time by splitting a program into a number of bundles that are loaded later. This is especially important for modern web apps. With code splitting you could have a separate bundle for every route in a program, so initially browser will load only minimal amount of code to run and show requested view to a user and other code can be lazy-loaded later.

Who is using it?

More Repositories

1

html-to-react-components

Converts HTML pages into React components
JavaScript
2,131
star
2

webpack-closure-compiler

[DEPRECATED] Google Closure Compiler plugin for Webpack
JavaScript
464
star
3

uix

Idiomatic ClojureScript interface to modern React.js
HTML
431
star
4

threegn

Procedural 3D graphics editor for the web
JavaScript
309
star
5

react-native-babel

Configuration to build React Native apps with ES6 using webpack and Babel
Objective-C
234
star
6

clj-wasm

Clojure-flavored WASM's text format
Clojure
159
star
7

react-flux-workshop

ะœะฐั‚ะตั€ะธะฐะปั‹ ะบ ะฒะพั€ะบัˆะพะฟัƒ ยซReact.js ะธ ะฐั€ั…ะธั‚ะตะบั‚ัƒั€ะฐ Fluxยป
JavaScript
128
star
8

react-horizon

React Horizon makes it easier to use your React application with horizon.io realtime backend
JavaScript
119
star
9

JSONFormData

HTML JSON form submission polyfill
JavaScript
104
star
10

javascript-to-clojurescript

JavaScript to ClojureScript translator
JavaScript
102
star
11

react-webrtc

WebRTC React mixins for real-time communication in React components
JavaScript
85
star
12

slack-traductor

Slack bot to translate chat messages of any language into specified language
JavaScript
85
star
13

babel-plugin-stateful-functional-react-components

Stateful functional React components without runtime overhead
JavaScript
83
star
14

proton-native-cljs

Clojure
79
star
15

prum

ClojureScript's Rum with Preact.js instead of React
HTML
64
star
16

anybar-webpack

Webpack build status plugin for menubar status indicator applications
JavaScript
62
star
17

js-memory-usage

Data Structures Memory Usage in JavaScript
JavaScript
59
star
18

minimax

Minimalist 3D game engine in Clojure
Clojure
59
star
19

scrum-ssr-example

HN clone app with server-side rendering built with Scrum
Clojure
57
star
20

solid-cljs

ClojureScript bindings to SolidJS
Clojure
57
star
21

cljs-rum-realworld-example-app

ClojureScript + Rum codebase containing real world examples
Clojure
53
star
22

github-issues

Sample React application built with Flux
JavaScript
48
star
23

threejs-cljs-playground

three.js playground in ClojureScript
CSS
44
star
24

figcup

Converts Figma designs into Reagent/Hiccup components to render in the browser
Clojure
40
star
25

cljs-async-await

Experimental ClojureScript's compiler extension that enables JavaScript's async/await
Clojure
36
star
26

clojurescript-workshop

Repository of related materials to the workshop
Clojure
36
star
27

recursion-exercises

Recursion exercises in JavaScript
JavaScript
34
star
28

cljs-react-devtools

React DevTools for ClojureScript wrappers
Clojure
30
star
29

react-horizon-example

Example React application built with React Horizon connector to horizon.io realtime backend
JavaScript
29
star
30

amsterdamjs-clojurescript-workshop

Educational materials for ClojureScript workshop @ AmsterdamJS '18
Clojure
28
star
31

hooks

React Hooks for ClojureScript
Clojure
22
star
32

grunt-load-perf

Grunt task for generating visual report to measure web applications loading and rendering performance.
JavaScript
21
star
33

impact-node

Node.js CLI for game development with Impact HTML5 game engine
JavaScript
21
star
34

react-dom-visualizer

Visualize components structure in your React application as a tree chart
JavaScript
20
star
35

babel-plugin-react-hyperscript

HyperScript syntax for React components without runtime overhead
JavaScript
20
star
36

cljs-source-mapped-stack-traces

Displays exceptions with stack frames mapped to ClojureScript source
JavaScript
19
star
37

path-following

JavaScript implementation of Craig Reynoldsโ€™s path-following algorithm
JavaScript
18
star
38

adapton

A Minimal Implementation of Incremental Computation in Clojure and ClojureScript
Clojure
17
star
39

imtbl

Immutable operations for JavaScript data structures
JavaScript
17
star
40

web-components-polyfills

A set of lightweight polyfills to enable Web Components support in major browsers, including IE9+
JavaScript
16
star
41

cljs-worklet

Run ClojureScript functions on a worklet thread in React Native
Clojure
16
star
42

voice-to-chat

A small CLI and menubar app that transcribes voice recording and rewrites it in a style of a written text
JavaScript
14
star
43

0ui

A set of utilities for building UIs with React
JavaScript
14
star
44

leap-motion-controlled-hand

Leap Motion controlled 3D hand made with Three.js
JavaScript
14
star
45

vscode-structed

Structured editing in JavaScript extension for VS Code
JavaScript
13
star
46

part-js

Persistent Adaptive Radix Tree (PART) for JavaScript
TypeScript
13
star
47

zfort-js-course

JavaScript course for Zfort company.
JavaScript
13
star
48

postcss-camel-case

PostCSS plugin to convert CSS selector names to camelCase
JavaScript
13
star
49

clojurescript-studio

Online coding sandbox tailored for web development
Clojure
13
star
50

react-a11y-video

Accessible HTML5 Video player React component
JavaScript
10
star
51

node-stm

Multiversion Concurrency Control (MVCC) based Software Transactional Memory (STM)
JavaScript
10
star
52

atom-cljs-doc

ClojureScript core library documentation viewer for Atom
JavaScript
9
star
53

kottans-intro-into-fp

Introduction into functional programming
JavaScript
8
star
54

virtual.list

Virtual list component for Prum
Clojure
8
star
55

grunt-mocha-casperjs

Grunt wrapper for mocha-casperjs
JavaScript
8
star
56

websockets-device-controller

WebGL demo powered by WebSockets and device accelerometer data to control things on the web.
JavaScript
7
star
57

generator-website

A website generator for Yeoman
JavaScript
7
star
58

advent-of-code-2018

Solutions to puzzles from Advent of Code 2018
Clojure
6
star
59

shapy

Web-based UI design tool
Clojure
6
star
60

roman01la-devtools

Custom UI theme for Chrome's DevTools
HTML
5
star
61

structed

Structured editing for JavaScript
JavaScript
5
star
62

jsbin-cljs

ClojureScript for JS Bin
Clojure
5
star
63

zprint-atom

Atom plugin for zprint-clj
JavaScript
5
star
64

rc-cljs-workshop

ClojureScript Workshop @ ReactiveConf '17
5
star
65

uix.css

CSS-in-CLJS
4
star
66

react-images-preloader

HOC to preload images before rendering
JavaScript
4
star
67

babel-plugin-inline

Array map/filter/reduce inliner plugin
JavaScript
4
star
68

webpack-sri

Subresource Integrity hash generator plugin for Webpack
JavaScript
4
star
69

clojure-hacking-day

Clojure
4
star
70

pwl-kyiv

Papers We Love @ Kyiv
HTML
3
star
71

re-frame-chat

Clojure
3
star
72

uix-cookbook

UIx Cookbook is a set of recipes that will assist you in creating web apps with UIx
2
star
73

rc18-clojure-workshop

Clojure
2
star
74

happy-paw

HappyPaw + Tinder
Clojure
2
star
75

sqlite-vector-search

A demo of vector search with HNSW and SQLite
JavaScript
2
star
76

create-uix-app

Scaffolding tool for UIx
JavaScript
1
star
77

rum-code-splitting

Clojure
1
star
78

roman01la

1
star
79

sub-deep

Transcribe and translate audio with AI
JavaScript
1
star
80

canvas-text-layout

JavaScript
1
star
81

slack-yue

Clojure
1
star
82

subform-css-layout-worklet

Subformโ€™s Layout engine via CSS Layout API
JavaScript
1
star
83

libx.core

Enhanced Clojure's standard library
Clojure
1
star