Create a fully working Closure Library project in seconds.
The generator is using yeoman and relies on Grunt to operate. If you don't have them, install:
npm install -g yo grunt-cli
The generator itself can be globally installed and reused anywhere:
npm install -g generator-closure
Run it:
yo closure
After the generator is finished, you need to add the Closure Library in the app/closure-library
path:
git clone https://github.com/google/closure-library app/closure-library
Finally, install all the dependencies:
npm install && bower install
There is a Library version of the generator:
yo closure:lib
The Library version is for closure libraries that have no web output. The location of your project's base changes to lib/
instead of the default one app/js/
.
- A fully working installation of closure compiler.
- A battle-tested folder scaffolding for your closure application.
- A skeleton sample application.
- A third-party dependencies loader.
- A set of helper and boilerplate code to speed up your time to productive code.
- A Full Behavioral and Unit testing suite using Mocha with Chai.js and Sinon.js.
- 52 BDD and TDD tests both for your development and compiled code.
- Full open source boilerplace (README, LICENSE, .editorconfig, etc).
- Vanilla and a special edition Closure Compiler that strips off all
logger
calls from your production code. (The special edition is used). - Sourcemap file for your compiled code.
- A set of Grunt Tasks that will:
- Manage your dependencies.
- Compile your code.
- Run a static webserver with livereload.
- Test your code on the CLI & the browser.
grunt server
Start a static servergrunt
orgrunt deps
Calculate Dependenciesgrunt build
Compile your codegrunt test
Run tests on the command linegrunt server:test
Run tests on the browser
The grunt server
task will do quite a few things for you.
- A static server will listen on port 9000 (or anything you'd like, with:
--port=8080
). - A live reload server will be launched.
- All your codebase will be wathed for changes and trigger livereload events
- Finally, your browser will open on the project page
The grunt deps
task will calculate the dependencies of your project and output to the deps file: app/js/deps-app.js
.
It will also run the dependencies task for the behavioral and unit tests updating the files: test/bdd/deps-test-bdd.js
and test/unit/deps-test-tdd.js
. Find more about testing bellow.
The build task employs a long flow so it can enable you to bundle third-party dependencies on your production file. Here is the overview of what happens:
- Temporary folder
temp
is cleared. - All the defined third-party dependencies are minified using uglify. The output can be found in
temp/vendor.js
. - Closure Compiler will compile your closure codebase using ADVANCED_OPTIMIZATIONS. The output can be found at:
temp/compiled.js
- Produce the final file by concatenating the vendor and compiled files to:
app/jsc/app.js
The build operation is easily configured down to the most edge case. Everything you need is in the Gruntfile which is at the root of your project: Gruntfile.js
.
At the top of the file you will find a few build related variables:
// The folder that contains all the externs files.
var EXTERNS_PATH = 'build/externs/';
// define the main namespace of your app
var ENTRY_POINT = 'app';
Read about Configuring Third-Party dependencies for your build.
Define the folder that will be scanned for externs files. The Closure Generator comes packed with these externs for you:
- jQuery 1.9
- Angular
- Facebook Javascript SDK
- When.js 1.8
The entry point is the top-most namespace level of your application. In the included sample application that namespace is app
.
Locate the directive closureBuilder
in the Gruntfile. The full documentation for all the options and directives can be found in the Grunt Closure Tools plugin that is being used to compile your code.
One thing to take note of is the line where the compiled is defined:
compilerFile: compiler.getPathSS(),
The compiler
variable is the Superstartup Closure Compiler npm package that includes two versions of the Closure Compiler. The original closure compiler and a modified one. In this line, the modified compiler is used so all logger
debug calls are stripped from the production built.
The test tasks for the CLI and the browser. Read more on the Testing section.
The scaffold of the closure application gives you a kickstart on writing your own app. A lot of different practices and techniques are incorporated in the scaffolding. They are based on distilled experiences and problems faced over years of developing closure applications. Feel free to rip everything off and start from scratch or checkout what's included...
The root folder of the Closure Application is in: app/js/
. Only two files two files should exist in the root folder:
main.js
This is the main bootstrap file. No code should exist in this file, only require statements. Sequence matters.deps-app.js
The dependencies file. This file is auto-generated by thegrunt deps
task.
The other folders and their meaning:
The core folder is where the core of your application resides. The standard core/core.js
file defines the core class and initializes your application.
The exports.js
file is where you define what parts of your application will get exposed after compilation.
The response.core.js
is an optional library that will help your library provide uniform, standardized and properly exposed responses. E.g. event objects, callback parameters, etc.
Put helpers here. A set of some utility functions is included in the ssd.helpers
namespace. Read the helpers/helpers.js
file, they are well documented.
Stand alone closure libraries for your project. The third-party loader is in this folder: libs/vendor.loader.js
. Read more about it in the Third-party dependencies section.
The file module.js
is an empty class that all other applications extend, it can be accessed is the app.Module
namespace. The app.Module
class extends goog.events.EventTarget
which extends goog.Disposable
. This provides with all your classes event and disposing capabilities.
A typical way to extend the app.Module
base class:
/**
* @fileoverview Performs some function.
*/
goog.provide('app.SomeClass');
goog.require('app.Module');
/**
* @constructor
* @extends {app.Module}
*/
app.SomeClass = function() {
goog.base(this);
/** .. */
};
goog.inherits(app.SomeClass, app.Module);
The network folder contains a persistent storage layer abstraction. The top-most class is the app.sync
which only has one function: app.sync.send()
. app.sync
is a this wrapper for app.ajax
which provides some abstraction over Closure's XhrIo
library.
The result is that when your app interfaces with app.sync
it has the option to work with a promise or callback. Both of which return a standardized response object that is defined in the response.sync.js
file. Should that be the case at a later point, you can easily intercept calls in the sync class and use sockets over xhr or local storage or...
While this is possibly quite a stretch for your use-case, it is generaly advisable to retain such a level of abstraction to the persistent storage layer. That includes the network layer (xhr or socket calls).
The structs folder should contain all your data abstractions. These are the building blocks of your models.
All third-party libraries should be in here. Read more about Third-Party Dependencies.
Create new folders as you see fit. In the generator the folder app/
is included which contains a skeleton app.
Closure Library has a hard time working with third-party libraries that are not closure compatible. Hopefully, with the use of externs files, this dependency loader and the community's help we can soften these hurdles.
This is more of a technique, rather than a stand alone library. The library itself is only usefull for developing. For building your application the ball is on Grunt's hands.
IMPORTANT: All third-party dependencies must be in the
app/js/vendor
folder.
You need to edit the third-party library file which is located at: app/js/libs/vendor.loader.js
.
/**
* EDIT THIS ARRAY.
*
* @type {Array} define the 3rd party deps.
*/
ssd.vendor.files = [
'when.js',
'jQuery-1.9.1.js'
];
Add or remove strings in the array as you see fit.
To define what third-party files will get bundled with your production file you need to edit the Gruntfile. At the top of the Gruntfile the vendorFiles
Array is defined:
// define the path to the app
var APP_PATH = 'app/js';
// the file globbing pattern for vendor file uglification.
var vendorFiles = [
// all files JS in vendor folder
APP_PATH + '/vendor/*.js',
// and jQuery, we'll use a CDN for it.
'!' + APP_PATH + '/vendor/jQuery*'
];
This configuration will include every javascript file in the app/js/vendor/
directory, except any jQuery file. We don't want to include jQuery in the production file as it is faster to include from a public CDN.
The test suite uses Mocha with Chai.js and Sinon.js. Two seperate types are included, Behavioral and Unit tests.
BDD tests are supposed to test against the development and compiled code. They ensure your API is properly exposed and all functionality and behavior happens as expected.
24 tests are included that can run against your development or compiled code. Launch them on your browser with grunt:
grunt server:test
Unit tests are designed to test your codebase only in development state. They will fail if run against your compiled code.
This provides you with the ability to unit test down to the most granular level your code. 4 unit tests are included to get you started. You can view them in the browser after you click on the Unit Tests
link at the top of your browser:
grunt server:test
grunt test
'nough said.
You may noticed that to switch from BDD to Unit tests or to Compiled codebase on the browser, a GET param is added on the url. E.g. to view the unit tests the url is http://localhost:4242/test/?unit=1
.
If you want to drill down on a specific test that GET param ?unit=1
will be lost. For example, if you click on the isjQ()
test you will be redirected to this url and see nothing:
http://localhost:4242/test/?grep=ssd.helpers%20isjQ
The reason this is blank is because the unit
GET param is not there. You need to add it manually:
http://localhost:4242/test/?grep=ssd.helpers%20isjQ&unit=1
Sorry about that, please share your thoughts.
Closure is so vast and we need to have a common place to document all the techniques and best practises used today.
The ssd
namespace that's included in some libraries stands for SuperStartup Development. It is the development namespace used by the Superstartup library.
- v0.1.15, 10 Jan 2014
- v0.1.13, 06 Jan 2014
- Force create
temp/
folder. - Updated
grunt-closure-tools
package to~0.9.0
, latest.
- Force create
- v0.1.12, 05 Dec 2013
- Updated all dependencies to latest.
- v0.1.9, 14 Oct 2013
- Allow overriding hostname and port of grunt server.
- Fix generator
green
bug. - Enables defining closure-library location using the
CLOSURE_PATH
env var #3
- v0.1.8, 8 Jun 2013
- Fix event handling so it works with recent closure changes.
- v0.1.7, 3 Jun 2013
- Bug fix for library generation
- v0.1.6, 1 May 2013
- Several bugfixes, all found thanks to @JayGray.
- v0.1.5, 07 May 2013
- Renamed
component.json
tobower.json
- Linted Gruntfile
- Minor color tweaks
- Renamed
- v0.1.4, 14 Apr 2013
- Added Closure Linter task, thanks @pr4v33n
- v0.1.3, 14 Apr 2013
- Minor bugs
- v0.1.2, 21 Mar 2013
- Added Library generator
- Added Bower support
- Instruction changes
- v0.1.1, 20 Mar 2013
- Added Source Map option
- Minor typo fixes
- v0.1.0, Mid Mar 2013
- Big Bang
Copyright (c) 2013 Thanasis Polychronakis Licensed under the MIT.