Modular JavaScript with CommonJS Compiler

Preview:

DESCRIPTION

Introduction into a developing approach where you can keep your JavaScript modular without any performance loss

Citation preview

WITH

Dmitry Sheiko

Modular JavaScript

CommonJS Compiler

separates the functionality of a program into independent modules

MODULAR PROGRAMMING

encapsulates everything required to implement a single aspect of the desired

functionality

MODULE

Therefore, a complex problem can be broken into simpler tasks

The entire system becomes easier to

debugupdatemodify

What about JavaScript?

MODULE PATTERNvar bar = (function(){ // Functionality return exportObj; }()),

foo = (function( bar ){ // Functionality }( bar ));

And what the structure does it give for your codebase?

HOW ABOUT THIS?

AMD

• Designed to accommodate asynchronous loading• Lazy-load scripts • Can load more than just JavaScript files• Config settings to simplify path resolution and

dependency listing

AMD IMPROVES PERFORMANCE OF WEB APPLICATION by bypassing module loading along with the rest of the page content

AMD HARMS PERFORMANCE OF WEB APPLICATION by producing numerous HTTP requests

COMMONJS MODULES/1.1

• Designed for server-side JavaScript and for native desktop applications

• Simple and clean module definition syntax

CJS MODULES + COMMONJS COMPILER

• Designed for server-side JavaScript and for native desktop applications

• Simple and clean module definition syntax• Can load more than just JavaScript files• Config settings to simplify path resolution and

dependency listing

COMMONJS COMPILER is the keyhttp://dsheiko.github.io/cjsc

Let’s get started!

INSTALLING COMMONJS COMPILER$sudo npm i cjsc -g

EXAMPLE 1

`foo.js`:console.log( "foo.js: Hello World" );

`bar.js`:require( "./foo" );console.log( "bar.js: Hello World" );

EXAMPLE 1

Compiling `bar.js`:$cjsc bar.js build.js

Output of `build.js`:foo.js: Hello Worldbar.js: Hello World

WHAT HAVE WE JUST DONE?

We loaded one module in another. Both are executed in the compiled code

EXAMPLE 2

`foo.js`:var privateState = “lorem“;module.exports = { name: "foo.js" };

`bar.js`:console.log( require( "./foo" ) );console.log(“privateState:" + typeof privateState );

EXAMPLE 2

Output of `build.js`:{ name: "foo.js" }privateState: undefined

WHAT HAVE WE JUST DONE?

We accessed an exported object and made certain that private state isn't available outside the module.

EXAMPLE 3

`foo.js`:console.log( "foo.js: constructing" );module.exports = { name: "foo.js" };

`bar.js`:console.log( require( "./foo" ) );console.log( require( "./foo" ) );

EXAMPLE 3

Output of `build.js`:foo.js: constructing{ name: "foo.js" }{ name: "foo.js" }

WHAT HAVE WE JUST DONE?

We checked that loading a module URL multiple times results in a single cached instance.

EXAMPLE 4

`foo.tpl`:Lorem ipsum dolor sit amet, Lorem ipsum dolor sit amet

`bar.js`:var tpl = require( "./foo.tpl" );console.log( "foo:" + tpl );

EXAMPLE 4

Output of `build.js`:foo: Lorem ipsum dolor sit amet, Lorem ipsum dolor sit amet

WHAT HAVE WE JUST DONE?

We found out that while resolving module dependencies CommonJS Compiler exports any content of non-JavaScript or JSON syntax as a string.

EXAMPLE 5`foo.tpl`:{{title}} spends {{calc}}

`bar.js`:var mustache = require( "./mustache" ), tpl = require( "./foo.tpl" ), view = { title: "Joe", calc: function () { return 2 + 4;}};console.log( mustache.render( tpl, view ) );

EXAMPLE 5

Output of `build.js`:

Joe spends 6

WHAT HAVE WE JUST DONE?

We leveraged loading of plain text resource to obtain a template for further use with a template engine (mustache.js).

DEBUGGING COMPILED CODEGenerating source map:$cjsc bar.js build.js --source-map=build.js.map

JavaScript console refers to original sources:

RUN-TIME CONFIGURATIONJSON configuration syntax:{ "<dependency-name>": { "path": "<dependency-path>", "globalProperty": "<global-property>", exports: [ "<variable>", "<variable>" ], require: [ "<dependency-name>", "<dependency-name>" ] }}

RUN-TIME CONFIGURATION EXAMPLE{ "jQuery": { "globalProperty": "jQuery" }, "plugin": { "path": "./config/vendors/jquery.plugin.js", "require": "jQuery", "exports": "jQuery" }}

ENABLING CONFIGURATION

$cjsc foo.js build.js --config=config.json

BUILD AUTOMATION WITH GRUNTGruntfile.js:grunt.loadNpmTasks( "grunt-contrib-cjsc" );grunt.initConfig({

cjsc: { debug: { options: { sourceMap: "./wwwroot/build/js/*.map", config: { "backbone": { "path": "./wwwroot/vendors/backbone/backbone" }}}, files: { "./wwwroot/build/js/app.js": "./wwwroot/js/app.js" }},

BUILD AUTOMATION WITH GRUNTGruntfile.js: build: { options: { minify: true, banner: "/* License */", config: { "backbone": { "path": "path": "./wwwroot/vendors/backbone/backbone" }}}, files: { "./wwwroot/build/js/app.js": "./wwwroot/js/app.js" }}}

BUILD AUTOMATION WITH GRUNT

It gives us two options: cjsc:debug and cjsc:build. The first one we run during development; it provides source maps for debugging and doesn't compress output. The second option we use when preparing production build.

THANK YOU!

COMMONJS COMPILERhttp://dsheiko.github.io/cjsc COMMONJS COMPILER GRUNT TASKhttps://github.com/dsheiko/grunt-contrib-cjsc

DMITRY SHEIKO

@sheikohttps://github.com/dsheiko

dsheiko.com

Recommended