javascript modules done right

Post on 11-May-2015

6.669 Views

Category:

Technology

2 Downloads

Preview:

Click to see full reader

DESCRIPTION

JavaScript Modules Done RightClient & server-side code organization

TRANSCRIPT

JavaScript ModulesDone right

Client & server-side code organization

meetjs · November 2011 · Warsaw, Poland

Mariusz Nowakmariusz@medikoo.com

@medikoo

github.com/medikoo

JavaScript Programmer at Roche Ltd.

Browser

In the beginning there was Browser.How we managed large code bases (?)

Browser

In the beginning there was Browser.How we managed large code bases (?)

• Files concatenation

Browser

Written usually this style:

MAIN.module = (function() { var privateVar = '..';

var privateMethod = function (args) { // ... };

return { publicProperty: '..', publicMethod: function () { // ... } };

}());

Browser

In the beginning there was Browser.How we managed large code bases (?)

• Files concatenation

Browser

In the beginning there was Browser.How we managed large code bases (?)

• Files concatenation• Module pattern

Server

Beginning of 2009

• Growing number of interpreters: Rhino, Spidermonkey, V8, JSCore

• No cross-interpreter standards

• There are programmers who want to write server-side JavaScript but want to have their code runnable on any engine

Server

Beginning of 2009

• Growing number of interpreters: Rhino, Spidermonkey, V8, JSCore

• No cross-interpreter standards

• There are programmers who want to write server-side JavaScript but want to have their code runnable on any engine

• There’s a need for standard library API that would allow JavaScript ecosystem grow (as it happened for Ruby, Python or Java)

Server

Beginning of 2009

• Growing number of interpreters: Rhino, Spidermonkey, V8, JSCore

• No cross-interpreter standards

• There are programmers who want to write server-side JavaScript but want to have their code runnable on any engine

• There’s a need for standard library API that would allow JavaScript ecosystem grow (as it happened for Ruby, Python or Java)

• ServerJS initiative is announced, renamed later into CommonJS -> http://www.blueskyonmars.com/2009/01/29/what-server-side-javascript-needs/

Server

CommonJS presents Modules specification -> http://www.commonjs.org/specs/modules/1.0/

Server

CommonJS presents Modules specification -> http://www.commonjs.org/specs/modules/1.0/

add.js

exports.add = function() { var sum = 0, i = 0, args = arguments, l = args.length; while (i < l) sum += args[i++]; return sum;};

increment.js

var add = require('add').add;exports.increment = function(val) { return add(val, 1);};

program.js

var inc = require('increment').increment;var a = 1;inc(a); // 2

Server

In about same time Ryan Dahl creates Node.js, which implements CommonJS Modules

add.js

exports.add = function() { var sum = 0, i = 0, args = arguments, l = args.length; while (i < l) sum += args[i++]; return sum;};

increment.js

var add = require('add').add;exports.increment = function(val) { return add(val, 1);};

program.js

var inc = require('increment').increment;var a = 1;inc(a); // 2

Server

In about same time Ryan Dahl creates Node.js, which implements CommonJS Modules... with some improvements

add.js

module.exports = function() { var sum = 0, i = 0, args = arguments, l = args.length; while (i < l) sum += args[i++]; return sum;};

increment.js

var add = require('./add');module.exports = function(val) { return add(val, 1);};

program.js

var inc = require('./increment');var a = 1;inc(a); // 2

Server

How module works:

// increment.js var add = require('./add'); module.exports = function (val) { return add(val, 1); };

Server

How module works:

var exports, module;function (exports, require, module) {

// increment.js var add = require('./add'); module.exports = function (val) { return add(val, 1); };

}.call(exports = {}, exports, function (path) { // import external module}, module = { exports: exports });

MODULE = module.exports;

Server

Let’s get back to module pattern.

Server

Let’s get back to module pattern.

module.js

MAIN.module = (function() { var privateVar = '..'; var privateMethod = function (args) { // ... }; return { publicProperty: '..', publicMethod: function () { // ... } };}());

Server

Module pattern as CommonJS module:

module.js

var privateVar = '..';var privateMethod = function (args) { // ...};

exports.publicProperty: '..',exports.publicMethod: function () { // ...};

program.jsvar foobar = require(‘./module’);

Server

Module pattern as CommonJS module:

module.js

var privateVar = '..';var privateMethod = function (args) { // ...};

exports.publicProperty: '..',exports.publicMethod: function () { // ...};

program.jsvar foobar = require(‘./module’); ↑ we decide locally under which name we’ll access imported module

Server

CommonJS Modules is indeed great specification.What are the benefits ?

Server

CommonJS Modules is indeed great specification.What are the benefits ?

First of all, cleanliness and encapsulation on highest available (for JavaScript) level

Server

CommonJS Modules is indeed great specification.What are the benefits ?

First of all, cleanliness and encapsulation on highest available (for JavaScript) level

• There’s no need to write obsolete function wrappers to work in private scope

Server

CommonJS Modules is indeed great specification.What are the benefits ?

First of all, cleanliness and encapsulation on highest available (for JavaScript) level

• There’s no need to write obsolete function wrappers to work in private scope

• We don’t have to deal with long namespaces, each required module is assigned to local variable

Server

CommonJS Modules is indeed great specification.What are the benefits ?

First of all, cleanliness and encapsulation on highest available (for JavaScript) level

• There’s no need to write obsolete function wrappers to work in private scope

• We don’t have to deal with long namespaces, each required module is assigned to local variable

• We can build large complex application without a need to touch global namespace

Server & Browser

How to run it in the Browser ?

Server & Browser

How to run it in the Browser ?

When I started working with CommonJS and Node.js (beginning 2011) I thought there’s solid solution already available

Server & Browser

How to run it in the Browser ?

When I started working with CommonJS and Node.js (beginning 2011) I thought there’s solid solution already available

I’ve found about 8-10 solutions that aimed at something similar, however none of them were really working right

Server & Browser

Main issue was that each of them, was trying to be something more than Node.js modules parser, and “more” seemed to have more attention than dependency parser I was after.

Server & Browser

Main issue was that each of them, was trying to be something more than Node.js modules parser, and “more” seemed to have more attention than dependency parser I was after.

Parsers were incomplete and buggy

Server & Browser

Anyway, time goes by, there are few solutions that deserve focus

Server & Browser

Anyway, time goes by, there are few solutions that deserve focus

Browserify -> https://github.com/substack/node-browserify

Server & Browser

Anyway, time goes by, there are few solutions that deserve focus

Browserify -> https://github.com/substack/node-browserify

Very interesting tool, if we’re after reusing native Node.js modules on client-side. Browserify struggles to make it possible, I guess it was main intention behind the project.

Server & Browser

Anyway, time goes by, there are few solutions that deserve focus

Browserify -> https://github.com/substack/node-browserify

Very interesting tool, if we’re after reusing native Node.js modules on client-side. Browserify struggles to make it possible, I guess it was main intention behind the project.

You need to add extra 320 lines of code for client-side to make it work, that’s not impressive, this code could be much smaller.

Server & Browser

Anyway, time goes by, there are few solutions that deserve focus

Browserify -> https://github.com/substack/node-browserify

Very interesting tool, if we’re after reusing native Node.js modules on client-side. Browserify struggles to make it possible, I guess it was main intention behind the project.

You need to add extra 320 lines of code for client-side to make it work, that’s not impressive, this code could be much smaller.

It doesn’t work well with some paths, modules from external packages were not found when I played with that (not sure if it’s bug or limitation)

Server & Browser

AMD -> Asynchronous Module Definition

Server & Browser

AMD ?

Server & Browser

AMD ?

It was made for browsers - Node.js won’t run AMD module properly

Server & Browser

AMD ?

It was made for browsers - Node.js won’t run AMD module properly

Server & Browser

AMD ?

It was made for browsers - Node.js won’t run AMD module properly

AMD has not much to do with CommonJS Modules, you need to write modules differently

Server & Browser

AMD ?

It was made for browsers - Node.js won’t run AMD module properly

AMD has not much to do with CommonJS Modules, you need to write modules differently

• All dependencies needs to be declared at begin of module

Server & Browser

AMD ?

It was made for browsers - Node.js won’t run AMD module properly

AMD has not much to do with CommonJS Modules, you need to write modules differently

• All dependencies needs to be declared at begin of module

In CommonJS we can reach for external modules in any place at any time, and it’s same for native modules that JavaScript will have in a future.

Server & Browser

AMD ?

It was made for browsers - Node.js won’t run AMD module properly

AMD has not much to do with CommonJS Modules, you need to write modules differently

• All dependencies needs to be declared at begin of module

In CommonJS we can reach for external modules in any place at any time, and it’s same for native modules that JavaScript will have in a future.

• Again, we need to use function wrappers. Each module needs to be declared with function call

Server & Browser

Why is that ?

Server & Browser

Why is that ?

AMD tries to be solution for two problems:

• Code modularization and organization• Dynamic dependency handling, so we load only that code that is actually used

Server & Browser

Why is that ?

AMD tries to be solution for two problems:

• Code modularization and organization• Dynamic dependency handling, so we load only that code that is actually used

Sounds promising, but is it worth it ?

Server & Browser

How AMD modules look like ?

Server & Browser

How AMD modules look like ?add.jsdefine(function () { return function() { var sum = 0, i = 0, args = arguments, l = args.length; while (i < l) sum += args[i++]; return sum; };});

increment.jsdefine(['add'], function (add) { return function(val) { return add(val, 1); };});

program.jsdefine(['increment'], function (inc) { var a = 1; inc(a); // 2});

Server & Browser

Most popular implementation -> http://requirejs.org/requires us to load library made of 2000 lines of code.

Server & Browser

Most popular implementation -> http://requirejs.org/requires us to load library made of 2000 lines of code.

... it’s needed just to run code of our application.

Server & Browser

Most popular implementation -> http://requirejs.org/requires us to load library made of 2000 lines of code.

... it’s needed just to run code of our application.

... and still we cannot use our modules on server-side (Node.js) without extra compilation step.

Server & Browser

Ok, but what about dynamic dependency resolution, isn’t it main purpose of AMD ?

Server & Browser

Ok, but what about dynamic dependency resolution, isn’t it main purpose of AMD ?

In my opinion dynamic dependency resolution should be considered on application functionality level not on modules level

Server & Browser

Summary:

Server & Browser

Summary:

We miss light and clean CommonJS (precisely Node.js) Modules implementation, that would allow us to use them on client side

Server & Browser

Summary:

We miss light and clean CommonJS (precisely Node.js) Modules implementation, that would allow us to use them on client side

Implementation that wouldn’t try to be solution for other problems in first place.

Server & Browser

Summary:

We miss light and clean CommonJS (precisely Node.js) Modules implementation, that would allow us to use them on client side

Implementation that wouldn’t try to be solution for other problems in first place.

Code for handling modules on client side should be minimal, unnoticeable in size when compared to application code

Server & Browser

Finally new project was born:

Server & Browser

Finally new project was born:

modules-webmake ->https://github.com/medikoo/modules-webmake

npm install -g webmake

Modules Webmake

modules-webmake scans modules, builds dependency tree and produces output that it executable in the browser

Modules Webmake

modules-webmake scans modules, builds dependency tree and produces output that it executable in the browser

Current implementation is very basic, we might say, we just started

Modules Webmake

modules-webmake scans modules, builds dependency tree and produces output that it executable in the browser

Current implementation is very basic, we might say, we just started

It doesn’t limit us though from building complex applications made from hundreds of modules that originated from dozens of packages

Modules Webmake

modules-webmake scans modules, builds dependency tree and produces output that it executable in the browser

Current implementation is very basic, we might say, we just started

It doesn’t limit us though from building complex applications made from hundreds of modules that originated from dozens of packages

With modules-webmake you can build complex applications, right now

Modules WebmakeHow generated file looks like ?

Modules WebmakeHow generated file looks like ?(function (modules) { // 53 lines of import/export logic})({ "root": { "add.js": function (exports, module, require) { module.exports = function () { var sum = 0, i = 0, args = arguments, l = args.length; while (i < l) sum += args[i++]; return sum; }; }, "increment.js": function (exports, module, require) { var add = require('./add'); module.exports = function (val) { return add(val, 1); }; }, "program.js": function (exports, module, require) { var inc = require('./increment'); var a = 1; inc(a); // 2 } }})("root/program");

Modules WebmakeHow generated file looks like ?(function (modules) { // 53 lines of import/export logic})({ "root": { "add.js": function (exports, module, require) { module.exports = function () { var sum = 0, i = 0, args = arguments, l = args.length; while (i < l) sum += args[i++]; return sum; }; }, "increment.js": function (exports, module, require) { var add = require('./add'); module.exports = function (val) { return add(val, 1); }; }, "program.js": function (exports, module, require) { var inc = require('./increment'); var a = 1; inc(a); // 2 } }})("root/program"); <- Execution of module that initiates application

Modules Webmake• modules-webmake can be used both from shell and programmatically - we can bind it to http server in Node.js and generate files on demand

Modules Webmake• modules-webmake can be used both from shell and programmatically - we can bind it to http server in Node.js and generate files on demand

• Dependencies are parsed statically, it introduces some limitations, for specific cases we may force inclusion of chosen modules with ‘include’ option.

Modules Webmake• modules-webmake can be used both from shell and programmatically - we can bind it to http server in Node.js and generate files on demand

• Dependencies are parsed statically, it introduces some limitations, for specific cases we may force inclusion of chosen modules with ‘include’ option.

• modules-webmake reads local dependencies and those from external packages, one limitation is that it doesn’t recognize two different versions of same package (it will be addressed)

Modules Webmake• modules-webmake can be used both from shell and programmatically - we can bind it to http server in Node.js and generate files on demand

• Dependencies are parsed statically, it introduces some limitations, for specific cases we may force inclusion of chosen modules with ‘include’ option.

• modules-webmake reads local dependencies and those from external packages, one limitation is that it doesn’t recognize two different versions of same package (it will be addressed)

• Up to date documentation can be found at github project page:https://github.com/medikoo/modules-webmake

Modules WebmakeLast week I finished work on application that was built with help ofmodules-webmake.

• It’s HTML5 application, targetted only for modern browsers (newest FF, Chrome and Safari (both OSX & iOS))

• To support Offline mode we needed to put whole application logic to client side, including templates and simple database engine.

• Node.js on server-side, takes care about clients synchronization and saving data to physical database (mongodb)

• Minimalistic client-server communication based on sockets (Socket.IO)

Modules WebmakeFinal JavaScript file for client consists of 273 modules from 19 packages.

176 of mentioned modules works also on server side.It means that about 60% of client-side code is also running on server-side.

Concatenated file is 11 thousand lines longand weights about 370kB before minification and zipping.

It looks quite promising, if we take into account, that it consists of templates for whole application and all other modules that application is made of, including simple database engine.

After application load, all client-server communication is minimal as all pages as generated by client.

Modules WebmakeUpcoming improvements:

Modules WebmakeUpcoming improvements:

• Not only parser, but full modules engine. What for? It will allow to run and test modules with it’s dependencies in differently setup environments, like pure V8 + Modules, or emulation of browser environment.

Modules WebmakeUpcoming improvements:

• Not only parser, but full modules engine. What for? It will allow to run and test modules with it’s dependencies in differently setup environments, like pure V8 + Modules, or emulation of browser environment.

• Work in a background, it will allow much more optimized and faster file generation (watching file system for changes, immediate serving of generated files when integrated with node.js http server)

Modules WebmakeUpcoming improvements:

• Not only parser, but full modules engine. What for? It will allow to run and test modules with it’s dependencies in differently setup environments, like pure V8 + Modules, or emulation of browser environment.

• Work in a background, it will allow much more optimized and faster file generation (watching file system for changes, immediate serving of generated files when integrated with node.js http server)

• Optional minification, compilation

Modules WebmakeUpcoming improvements:

• Not only parser, but full modules engine. What for? It will allow to run and test modules with it’s dependencies in differently setup environments, like pure V8 + Modules, or emulation of browser environment.

• Work in a background, it will allow much more optimized and faster file generation (watching file system for changes, immediate serving of generated files when integrated with node.js http server)

• Optional minification, compilation

• Discovering modules that were required but not used

Modules WebmakeUpcoming improvements:

• Not only parser, but full modules engine. What for? It will allow to run and test modules with it’s dependencies in differently setup environments, like pure V8 + Modules, or emulation of browser environment.

• Work in a background, it will allow much more optimized and faster file generation (watching file system for changes, immediate serving of generated files when integrated with node.js http server)

• Optional minification, compilation

• Discovering modules that were required but not used

• Splitting into few files (for faster client-side load)

Modules WebmakeUpcoming improvements:

• Not only parser, but full modules engine. What for? It will allow to run and test modules with it’s dependencies in differently setup environments, like pure V8 + Modules, or emulation of browser environment.

• Work in a background, it will allow much more optimized and faster file generation (watching file system for changes, immediate serving of generated files when integrated with node.js http server)

• Optional minification, compilation

• Discovering modules that were required but not used

• Splitting into few files (for faster client-side load)

• Modules should not be duplicated in different files, introduction of intelligent more than one file generation

Modules WebmakeUpcoming improvements:

• Not only parser, but full modules engine. What for? It will allow to run and test modules with it’s dependencies in differently setup environments, like pure V8 + Modules, or emulation of browser environment.

• Work in a background, it will allow much more optimized and faster file generation (watching file system for changes, immediate serving of generated files when integrated with node.js http server)

• Optional minification, compilation

• Discovering modules that were required but not used

• Splitting into few files (for faster client-side load)

• Modules should not be duplicated in different files, introduction of intelligent more than one file generation

• Small code fixes for buggy engines e.g. quoting reserved keywords used as property names

Future: Harmony

We will have modules natively in JavaScript

http://wiki.ecmascript.org/doku.php?id=harmony:modules_examples

Future: Harmony

We will have modules natively in JavaScript

http://wiki.ecmascript.org/doku.php?id=harmony:modules_examples

Base concept of Harmony Modules is same as in CommonJS Modules.

Future: Harmony

We will have modules natively in JavaScript

http://wiki.ecmascript.org/doku.php?id=harmony:modules_examples

Base concept of Harmony Modules is same as in CommonJS Modules.

Differences lies in dedicated syntax, and powerful optional features like dynamic loading, possibility to load external modules via url etc.

Harmony Modules

Harmony ModulesWhat we currently write for Node.js:add.js

module.exports = function() { var sum = 0, i = 0, args = arguments, l = args.length; while (i < l) sum += args[i++]; return sum;};

increment.js

var add = require('./add');module.exports = function(val) { return add(val, 1);};

program.js

var inc = require('./increment');var a = 1;inc(a); // 2

Harmony ModulesWill be written that way with Harmony:add.js

export function add () { var sum = 0, i = 0, args = arguments, l = args.length; while (i < l) sum += args[i++]; return sum;};

increment.js

import add from './add';export function increment (val) { return add(val, 1);};

program.js

import { increment: inc } from './increment';var a = 1;inc(a); // 2

Harmony ModulesModules Webmake for EcmaScript 3/5:(function (modules) { // 53 lines of import/export logic})({ "root": { "add.js": function (exports, module, require) { module.exports = function () { var sum = 0, i = 0, args = arguments, l = args.length; while (i < l) sum += args[i++]; return sum; }; }, "increment.js": function (exports, module, require) { var add = require('./add'); module.exports = function (val) { return add(val, 1); }; }, "program.js": function (exports, module, require) { var inc = require('./increment'); var a = 1; inc(a); // 2 } }})("root/program");

Harmony ModulesModules Webmake for Harmony:

module add { export function add () { var sum = 0, i = 0, args = arguments, l = args.length; while (i < l) sum += args[i++]; return sum; }; }; module increment { import add from add; export function increment (val) { return add(val, 1); }; }; module program { import { increment: inc } from increment; var a = 1; inc(a); // 2 };

import * from program;

Server & Browser

If you use CommonJS/Node.js Modules today, it won’t be problematic for you to switch to Harmony in few years time

Server & Browser

If you use CommonJS/Node.js Modules today, it won’t be problematic for you to switch to Harmony in few years time

Today:

CommonJS/Node.js Modules & modules-webmake

Server & Browser

If you use CommonJS/Node.js Modules today, it won’t be problematic for you to switch to Harmony in few years time

Today:

CommonJS/Node.js Modules & modules-webmake

Tomorrow:

Harmony Modules

Server & Browser

If you use CommonJS/Node.js Modules today, it won’t be problematic for you to switch to Harmony in few years time

Today:

CommonJS/Node.js Modules & modules-webmake

Tomorrow:

Harmony Modules (& modules-webmake ?)

Questions ?

top related