{"id":18855001,"url":"https://github.com/roman01la/closure-compiler-handbook","last_synced_at":"2026-02-05T19:30:17.880Z","repository":{"id":74176518,"uuid":"73221676","full_name":"roman01la/closure-compiler-handbook","owner":"roman01la","description":"How to use Google's Closure Compiler","archived":false,"fork":false,"pushed_at":"2017-03-02T15:14:47.000Z","size":67,"stargazers_count":443,"open_issues_count":1,"forks_count":1,"subscribers_count":11,"default_branch":"master","last_synced_at":"2025-02-16T03:32:49.797Z","etag":null,"topics":["closure-compiler","compiler-optimizations","handbook","optimization-compiler"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/roman01la.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-11-08T19:53:11.000Z","updated_at":"2025-02-15T11:41:39.000Z","dependencies_parsed_at":null,"dependency_job_id":"3d092d68-e950-4382-8770-903393588e34","html_url":"https://github.com/roman01la/closure-compiler-handbook","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/roman01la%2Fclosure-compiler-handbook","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/roman01la%2Fclosure-compiler-handbook/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/roman01la%2Fclosure-compiler-handbook/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/roman01la%2Fclosure-compiler-handbook/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/roman01la","download_url":"https://codeload.github.com/roman01la/closure-compiler-handbook/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239793064,"owners_count":19697893,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["closure-compiler","compiler-optimizations","handbook","optimization-compiler"],"created_at":"2024-11-08T03:52:28.569Z","updated_at":"2026-02-05T19:30:17.834Z","avatar_url":"https://github.com/roman01la.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Introduction 👋\n\n\u003cimg src=\"logo.png\" alt=\"Closure Compiler handbook logo\" width=\"322\" height=\"114\" /\u003e\n\nThis handbook is designed to help you understand how to use Closure Compiler and learn its features.\n\n\u003e 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.\n\n\u003ca rel=\"license\" href=\"http://creativecommons.org/licenses/by-sa/4.0/\"\u003e\u003cimg alt=\"Creative Commons License\" src=\"https://i.creativecommons.org/l/by-sa/4.0/80x15.png\" /\u003e\u003c/a\u003e\n\n[Closure Compiler](https://developers.google.com/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.\n\nReact + ReactDOM build comparison\n\nTool            | Output size | Gzipped |\n----------------|-------------|---------|\nWebpack 2       |139KB        |42KB     |\nClosure Compiler|90KB         |32KB     |\n\nHere's an example of compiler's compilation output:\n\n*input*\n```js\nfunction hello(name) {\n  const message = `Hello, ${name}!`;\n  console.log(message);\n}\nhello('New user');\n```\n\n*output*\n```js\nconsole.log(\"Hello, New user!\");\n```\n\n# Table of Contents 📖\n- [Introduction](#introduction-)\n- [Table of Contents](#table-of-contents-)\n- [Getting started](#getting-started-)\n  - [Installation](#installation)\n  - [Using with Node](#using-with-node)\n  - [Using with Webpack](#using-with-webpack)\n  - [Using with Gulp](#using-with-gulp)\n  - [Splittable bundler](#splittable-bundler)\n- [Compilation levels](#compilation-levels-)\n- [Advanced compilation](#advanced-compilation-)\n  - [Referencing external code](#referencing-external-code)\n  - [Referencing compiled code](#referencing-compiled-code)\n  - [Referencing to object properties using both dot and bracket notations](#referencing-to-object-properties-using-both-dot-and-bracket-notations)\n- [Compiler optimizations](#compiler-optimizations-)\n  - [Dead code elimination and Tree-shaking](#dead-code-elimination-and-tree-shaking)\n  - [Unreachable and redundant code elimination](#unreachable-and-redundant-code-elimination)\n  - [Cross-module code motion](#cross-module-code-motion)\n  - [Constant folding](#constant-folding)\n  - [Function call inlining](#function-call-inlining)\n  - [Property flattening (collapsing)](#property-flattening-collapsing)\n  - [Variable and property renaming](#variable-and-property-renaming)\n  - [Statement fusion (merging) \u0026 variable declarations grouping](#statement-fusion-merging--variable-declarations-grouping)\n  - [Alternate syntax substitution](#alternate-syntax-substitution)\n  - [RegExp optimization](#regexp-optimization)\n  - [Known methods folding](#known-methods-folding)\n  - [Property assignment collection](#property-assignment-collection)\n  - [Anonymous functions naming](#anonymous-functions-naming)\n- [Compiler flags](#compiler-flags-)\n- [Supported languages](#supported-languages-)\n- [JavaScript modules](#javascript-modules-)\n- [Recipes](#recipes-)\n  - [Externs](#externs)\n  - [Exporting to global scope](#exporting-to-global-scope)\n  - [Code splitting](#code-splitting)\n- [Who is using it?](#who-is-using-it)\n\n# Getting started 🏁\n\nClosure Compiler is written in Java, but it also has JavaScript port.\nThe best way to use it is [Splittable](https://github.com/cramforce/splittable) bundler.\n\n- [google/closure-compiler](https://github.com/google/closure-compiler)\n- [google/closure-compiler-js](https://github.com/google/closure-compiler-js)\n- [Splittable](https://github.com/cramforce/splittable)\n\n## Installation\n\n```bash\nnpm i google-closure-compiler-js\n```\n\n## Using with Node\n\n```js\nconst compile = require('google-closure-compiler-js').compile;\n\nconst flags = {\n  jsCode: [{src: 'const inc = (x) =\u003e x + 1;'}]\n};\n\nconst out = compile(flags);\n\nconsole.log(out.compiledCode); // 'var inc=function(a){return a+1};'\n```\n\n## Using with Webpack\n\n```js\nconst ClosureCompiler = require('google-closure-compiler-js').webpack;\nconst path = require('path');\n\nmodule.exports = {\n  entry: [\n    path.join(__dirname, 'entry.js')\n  ],\n  output: {\n    path: path.join(__dirname, 'build'),\n    filename: 'bundle.js'\n  },\n  plugins: [\n    new ClosureCompiler({\n      options: {\n        languageIn: 'ECMASCRIPT6',\n        languageOut: 'ECMASCRIPT3',\n        compilationLevel: 'ADVANCED'\n      }\n    })\n  ]\n};\n```\n\n## Using with Gulp\n\n```js\nconst compiler = require('google-closure-compiler-js').gulp();\n\ngulp.task('build', function() {\n  return gulp.src('enrty.js', {base: './'})\n      .pipe(compiler({\n          compilationLevel: 'ADVANCED',\n          jsOutputFile: 'bundle.js',\n          createSourceMap: true\n        }))\n      .pipe(gulp.dest('./build'));\n});\n```\n\n## Splittable bundler\n\n[Splittable](https://github.com/cramforce/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.\n\n```js\nconst splittable = require('splittable');\n\nsplittable({\n  // Create bundles from 2 entry modules `./src/a` and `./src/b`.\n  modules: ['./src/a', './src/b'],\n  writeTo: 'dist/',\n})\n.then((info) =\u003e {\n  console.info('Compilation successful');\n  if (info.warnings) {\n    console.warn(info.warnings);\n  }\n})\n.catch((error) =\u003e console.error('Compilation failed', error));\n```\n\n# Compilation levels 🎚\n\nCompilation level is a compiler setting which denotes optimizations level to be applied to JavaScript code.\n\n`WHITESPACE_ONLY`\n\nRemoves comments, line breaks, unnecessary spaces and other whitespace.\n\n`SIMPLE` *(default)*\n\nIncludes `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.\n\n`ADVANCED`\n\nIncludes `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.\n\nThis 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.\n\n# Advanced compilation 👷\n\nWith `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.\n\n## Referencing external code\n\nIf you want to use globally defined variables and functions in your code safely, you must tell the compiler about those references.\n\n*input*\n```js\n// `moment` is declared in global scope\nwindow.moment().subtract(10, 'days').calendar();\n```\n\n*output*\n```js\n// `moment` was renamed to `a`\n// this will not run\nwindow.a().b(10, 'days').calendar();\n```\n\nThe way you do it is via _externs_. See [Externs](#externs) section for more information.\n\n## Referencing compiled code\n\nIf you are about to build a library that exports to global scope, you must tell the compiler about variables that should be exported safely.\n\n*input*\n```js\n// `MY_APP` is declared in global scope\nwindow.MY_APP = {};\n```\n\n*output*\n```js\n// `MY_APP` was renamed to `a`\n// it's no longer possible to reference `MY_APP`\nwindow.a = {};\n```\n\nThis should be done by exporting symbols into global scope. See [Exporting to global scope](#exporting-to-global-scope) section for more information.\n\n## Referencing to object properties using both dot and bracket notations\n\nClosure Compiler never rewrites strings. You should use only one way of declaring and accessing a property:\n- declare with a symbol, access with dot notation\n- declare with a string, access with a string\n\n*input*\n```js\n// `msg` property is declared and accessed in different ways\nobj = { msg: 'Hey!' };\nconsole.log(obj['msg']);\n```\n\n*output*\n```js\n// `msg` symbol is renamed to `a`, but `'msg'` text is not\nobj = { a: 'Hey!' };\nconsole.log(obj.msg);\n```\n\n# Compiler optimizations 🎛\n\nClosure 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.\n\n*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.*\n\n## Dead code elimination and Tree-shaking\n\n“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.\n\n*input*\n```js\n/* log.js module */\nexport const logWithMsg = (msg, arg) =\u003e console.log(msg, arg);\nexport const log = (arg) =\u003e console.log(arg);\n\n/* math.js module */\nexport const min = (a, b) =\u003e Math.min(a, b);\nexport const max = (a, b) =\u003e Math.max(a, b);\nexport const exp = (x) =\u003e x * x;\nexport const sum = (xs) =\u003e xs.reduce((a, b) =\u003e a + b, 0);\n\n/* entry.js entry point */\nimport * as math from './math';\nimport * as logger from './log';\n\nconst nums = [0, 1, 2, 3, 4, 5];\nconst msg = 'Result:';\n\nif (false) {\n  logger.log('nothing');\n} else {\n  logger.logWithMsg(msg, math.sum(nums));\n}\n```\n\n*output*\n```js\n// Even though the entire modules namespace was imported,\n// tree-shaking didn't include dependency code that is not used here.\n// Also a dead code within `if (false) { ... }` was removed.\nvar c = function(a) {\n  return a.reduce(function(a, b) {\n    return a + b;\n  }, 0);\n}([0,1,2,3,4,5]);\n\nconsole.log(\"Result:\",c);\n```\n\n## Unreachable and redundant code elimination\n\nThis 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`.\n\n## Cross-module code motion\n\nClosure 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.\n\n*input*\n```js\n/* math.js module */\nexport const sum = (xs) =\u003e xs.reduce((a, b) =\u003e a + b, 0);\nexport const mult = (xs) =\u003e xs.reduce((a, b) =\u003e a * b, 1);\n\n/* entry-1.js module */\nimport * as math from './math';\n\nconsole.log(math.sum(nums));\n\n/* entry-2.js module */\nimport * as math from './math';\n\nconsole.log(math.sum([4, 5, 6]) + math.mult([3, 5, 6]));\n```\n\n*output*\n```js\n/* common.js shared code */\nfunction c(a) {\n  return a.reduce(function(a, b) {\n    return a + b;\n  }, 0);\n};\n\n/* entry-1.bundle.js */\nconsole.log(c(nums)); // using shared code\n\n/* entry-2.bundle.js */\nconsole.log(\n  // using shared code\n  c([4,5,6]) +\n  // moved from `math.js` module\n  function(a) {\n    return a.reduce(function(a, b) {\n      return a * b;\n    }, 1);\n  }([3,5,6])\n);\n```\n\n## Constant folding\n\n\u003e 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.\n\n*input*\n```js\nconst years = 14;\nconst monthsInYear = 12;\nconst daysInMonth = 30;\n\nconsole.log(years * monthsInYear * daysInMonth);\n```\n\n*output*\n```js\nconsole.log(5040);\n// `years * monthsInYear * daysInMonth` computed at compile time\n// because they are known as constants\n```\n\n## Function call inlining\n\nTo 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.\n\n*input*\n```js\nconst person = {\n  fname: 'John',\n  lname: 'Doe',\n};\n\nfunction getFullName({ fname, lname }) {\n  return fname + ' ' + lname;\n}\n\nconsole.log(getFullName(person));\n```\n\n*output*\n```js\nvar a = { a: \"John\", b: \"Doe\" };\nconsole.log(a.a + \" \" + a.b);\n```\n\n## Property flattening (collapsing)\n\nCollapsing object properties into separate variables enables such optimizations as variable renaming, inlining and better dead code removal.\n\n*input*\n```js\nconst person = {\n  fname: 'John',\n  lname: 'Doe'\n};\n\nconsole.log(person.fname);\n```\n\n*output*\n```js\nvar person$fname = \"John\",\n    person$lname = \"Doe\"; // \u003c- is not used, can be removed\n\nconsole.log(person$fname);\n```\n\n## Variable and property renaming\n\nSmall 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']`).\n\n*input*\n```js\nconst user = window.session.user;\nconsole.log(user.apiToken, user.tokenExpireDate);\n```\n\n*output*\n```js\nvar a = window.b.f;\nconsole.log(a.a, a.c);\n```\n\n## Statement fusion (merging) \u0026 variable declarations grouping\n\nStatement fusion tries to merge multiple statements in a single one. And variable declarations grouping groups multiple variable declarations into a single one.\n\n*input*\n```js\nconst fname = 'John';\nconst lname = 'Doe';\n\nif (fname) {\n  console.log(fname);\n}\n```\n\n*output*\n```js\nvar fname = \"John\", lname = \"Doe\";\nfname \u0026\u0026 console.log(fname);\n```\n\n## Alternate syntax substitution\n\nSimplifies conditional expressions, replaces `if`s with ternary operator, object and array constructs with literals and simplifies `return`s.\n\n## RegExp optimization\n\nRemoves unnecessary flags and reorders them for better gzip.\n\n## Known methods folding\n\nThis precomputes known methods such as `join`, `indexOf`, `substring`, `substr`, `parseInt` and `parseFloat` when they are called with constants.\n\n*input*\n```js\n[0, 1, 2, 3, 4, 5].join('');\n```\n\n*output*\n```js\n\"012345\"\n```\n\n## Property assignment collection\n\nLooks for assignments to properties of object/array immediately following its creation using the abbreviated syntax and merges assigned values into object/array creation construct.\n\n*input*\n```js\nconst coll = [];\ncoll[0] = 0;\ncoll[2] = 5;\n\nconst obj = { x: 1 };\n\nobj.y = 2;\n```\n\n*output*\n```js\nvar coll = [0, , 5], obj = { x:1, y:2 };\n```\n\n## Anonymous functions naming\n\nGives anonymous function names. This makes it way easier to debug because debuggers and stack traces use the function names.\n\n*input*\n```js\nmath.simple.add = function(a, b) {\n  return a + b;\n};\n```\n\n*output*\n```js\nmath.simple.add = function $math$simple$add$(a, b) {\n  return a + b;\n};\n```\n\n# Compiler flags 🚩\n\nThere are much more compiler flags, see all of them in [google/closure-compiler-js](https://github.com/google/closure-compiler-js#flags) repo.\n\n| Flag                             | Default | Usage |\n|----------------------------------|---------|-------|\n| applyInputSourceMaps | `true` | Compose input source maps into output source map |\n| 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. |\n| compilationLevel | `SIMPLE` | Specifies the compilation level to use: `WHITESPACE_ONLY`, `SIMPLE`, `ADVANCED` |\n| env | `BROWSER` | Determines the set of builtin externs to load: `BROWSER`, `CUSTOM` |\n| languageIn | `ES6` | Sets what language spec that input sources conform to. |\n| languageOut | `ES5` | Sets what language spec the output should conform to. |\n| newTypeInf | `false` | Checks for type errors using the new type inference algorithm. |\n| outputWrapper | `null` | Interpolate output into this string, replacing the token `%output%` |\n| processCommonJsModules | `false` | Process CommonJS modules to a concatenable form, i.e., support `require` statements. |\n| rewritePolyfills | `false` | Rewrite ES6 library calls to use polyfills provided by the compiler's runtime. |\n| warningLevel | `DEFAULT` | Specifies the warning level to use: `QUIET`, `DEFAULT`, `VERBOSE` |\n| jsCode | `[]` | Specifies the source code to compile. |\n| externs | `[]` | Additional externs to use for this compile. |\n| createSourceMap | `false` | Generates a source map mapping the generated source file back to its original sources. |\n\n# Supported languages 🙊\n\n| Language | Option name          | Input | Output |\n|----------|----------------------|-------|--------|\n| ES3      | `ECMASCRIPT3`        | ✅    |   ✅   |\n| ES5      | `ECMASCRIPT5`        | ✅    |   ✅   |\n| ES5      | `ECMASCRIPT5_STRICT` | ✅    |   ✅   |\n| ES2015   | `ECMASCRIPT6`        | ✅    |        |\n| ES2015   | `ECMASCRIPT6_STRICT` | ✅    |        |\n| ES2015   | `ECMASCRIPT6_TYPED`  | ✅    |   ✅   |\n\n# JavaScript modules 🌯\n\n# Recipes 🍜\n\n## Externs\n\nExtern 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.\n\nOnce 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.\n\n*input*\n```js\n// `moment` is declared in global scope\nwindow.moment().subtract(10, 'days').calendar();\n```\n\n*extern*\n```js\nfunction moment() {}\n\nmoment.prototype = {\n  subtract: function() {},\n  calendar: function() {}\n};\n```\n\n*output*\n```js\n// `moment` and its prototype methods was not renamed\nwindow.moment().subtract(10, 'days').calendar();\n```\n\nExterns can be generated for most libraries, see [JavaScript Externs Generator](http://michaelmclellan.me/javascript-externs-generator/).\n\n## Exporting to global scope\n\nIf 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.\n\n*input*\n```js\nfunction logger(x) {\n  console.log('LOG:', x);\n}\n\nwindow['logger'] = logger;\n```\n\n*output*\n```js\n// `logger` function is exported properly into global scope\nwindow.logger = function(a) {\n  console.log('LOG:', a);\n};\n```\n\n## Code splitting\n\nCode 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.\n\n# Who is using it?\n\n- [ClojureScript](https://clojurescript.org/)\n- [Scala.js](https://www.scala-js.org/)\n- [Dart](https://www.dartlang.org/)\n- [GWT](http://www.gwtproject.org/)\n- [Tsickle — TypeScript to Closure Annotator](https://github.com/angular/tsickle)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Froman01la%2Fclosure-compiler-handbook","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Froman01la%2Fclosure-compiler-handbook","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Froman01la%2Fclosure-compiler-handbook/lists"}