javascript modules
About Me
Barak Igal
Front End Developer
Wix TPA Team
I love javascript
Why?
it's all about Freedom
we have a problem

script MANAGEMENT
...<script src="jquery.js" type="text/javascript"></script><script src="jquery.plugin.js" type="text/javascript"></script><script src="view.js" type="text/javascript"></script><script src="widget.js" type="text/javascript"></script><script src="i18n.js" type="text/javascript"></script><script src="app.js" type="text/javascript"></script><script src="strings.js" type="text/javascript"></script>...
Can you spot the bug?
PROS
- No setup upfront.
- Server guys don't know javascipt.
cons
- Insert script tags manually.
- Keep the scripts in order.
- Global scope pollution.
- Blocking/Synchronize.
the script tag guides
-
Don't write your javascript in one big file. Separate it to smaller files.
- When you have lots of small pieces you need to start working with dependencies and the worst of all - dependency management.
- Manual dependency management using script tags, might fit for a small project, but.... there are no small projects.
- Build system alone still doesn't solve the problem, one still needs to keep the scripts in order.
dependency mess
NAMESPACES
definition
//define namesapcesvar App = {}; App.Views = {}; App.Views.Home = {}; App.Views.Home.Config = {}; //get some property of deep namespace var myColor = App.Views.Home.Config.backgroundColor;
get unknown namespace
if(App && App.HasThisProp && App.HasThisProp.AndThisProp && App.HasThisProp.AndThisProp.SomeWantedNamespace && App...........)Solution?
var closer = App.HasThisProp.AndThisProp.SomeWantedNamespace;var myVar = closer.myVar;var myOtherVar = closer.myOtherVar;
Composition over inheritance chain
javascript inheritance problems
- Many ways to do it wrong.
- Developers try to enforce traditional inheritance on javascript prototypal inheritance.
- Implement the super method in javascript is hard.
-
Deep prototype chains leads to slow lookups.
so what is the answer?
Modules
Modules are easy to compose mix and handle.
What are JavaScript modules?
what are modules?
MODULE definition
Module is a piece of software that contains everything that is necessary to accomplish a particular task.
A module is a part of a program. Programs are composed of one or more independently developed modules that are not combined until the program is linked. A single module can contain one or several routines.
modularity

WHY MODULES?
-
Separation of concerns.
-
Encapsulation.
-
Maintainability.
-
Testability.
-
Code reusability.
-
Easy to distribute.
- Easy to understand.
why javascript modules?
- No global scope pollution.
- Async loading.
- Differed loading (just in time).
- Private variables.
- Faster scope lookups.
- Easier script management.
the old days
Module pattern
var counter = (function(){var count = 0; //privatereturn {get: function(){return count;},add: function(){return count++;},reset: function(){count = 0;}};}());
REVEALING module pattern
var counter = (function(){ var count = 0;function get(){ return count; }function add(){ return count++; }function reset(){ count = 0; }function add2(){return add(), add();}return { get: get,add: add,add2: add2,reset: reset };}());
pros
- Better than nothing.
- Create a separate scope.
- Can create private variables.
- Create separation of concerns.
cons
- Uses global scope for the return value.
- Still needs Handle dependencies manually.
- Each module instance duplicate all the methods
AMD
ASYNCHRONOUS MODULE DEFINITION
not a javascript framework!
Not related to the AMD the company
definition
The Asynchronous Module Definition API specifies a mechanism for defining modules such that the module and its dependencies can be asynchronously loaded.
This is particularly well suited for the browser environment where synchronous loading of modules incurs performance, usability, debugging, and cross-domain access problems.
AMD module API
define(id?, dependencies?, factory*);*Not really a factory
DEFINE A MODULE
define('counterModule', function(){
var count = 0;
return {
add: function(){
return count++;
},
reset: function(){
count = 0;
},
get: function(){
return count;
}
}
});
module id is usually left empty
define('counterModule', function(){
var count = 0;
return {
add: function(){
return count++;
},
reset: function(){
count = 0;
},
get: function(){
return count;
}
}
});
module id is usually left empty
using other modules
define('viewModule', ['counterModule'], function(counter){var views = {};return { register: function(viewName, viewData){ counter.add();views[viewName] = viewData;},count: function(){return counter.get();}.... }; });
returning a constructor
define('counterModule', function(){var staticCount = 0;return function Counter() {var count = 0;return { add: function(){staticCount++;return count++; }, reset: function(){staticCount -= count;count = 0; }, get: function(){ return count; },getGlobalCount: function(){return staticCount;} };}});
using a constructor in a module
define('otherModule', ['counterModule'], function(Counter){ var views = {}; var counter = new Counter();return {... register: function(viewName, viewData){ counter.add(); views[viewName] = viewData; }, count: function(){ return counter.get(); } ... }; });
commonjs modules
Still not
a FRAMEWORK
no BROWSER in mind
-
modules are not supported in browser because of the synchronous nature.*
- There is not wrapper.
- Designed to use in javascript servers.
- No wrapper.
Already in use in :
Node js
Titanium
And more
*there are ways to do it in the browser.
common js Api
require('module.name');exports.someApi = {};module;
define a module
exports.add = function(a, b){return a + b;}exports.subtract = function(a, b){ return a - b; }
using other modules
var Math = require('Math');Math.add(1, 2); // 3Math.subtract(1, 2); // -1
exporting a constructor
exports.myClass = function(){ this.startTime = Date.now(); }exports.myClass.prototype.elapsedTime = function(){ return Date.now() - this.startTime; }
CHANGING the exported module
var someObject = {someProperty: {}};var someVar = someObject.someProperty;someVar = function(){};console.log(someObject.someProperty); // {}
Assign to the module.exports
module.exports = function(){
this.startTime = Date.now();
}
module.exports.prototype.elapsedTime = function(){
return Date.now() - this.startTime;
}More formats
the Hybrid format
define(function(require, module, exports){var otherModule = require('otherModule');exports = {add:function(x, y){return x + y;}}});
Umd
Universal module definition.
(function (root, factory) {if (typeof define === 'function' && define.amd) { // AMD define('myModule', ['pkg/A', 'pkg/B'], function (A, B) { return factory(A, B); });} else if (typeof exports === 'object') { // Node.js module.exports = factory(require('pkg/A'), require('pkg/B'));} else { // Browser globals root.myModule = factory(root.A, root.B); }}(this, function (B, B) { var myModule = {}; return myModule; }));
lmd
Lazy Module Declaration
module loaders
loaders
requirejs

about
RequireJS is a JavaScript file and module loader. It is optimized for in-browser use, but it can be used in other JavaScript environments
this is
the framework

makes your html sexy
<!doctype html>
<html>
<head>
<title>Sexy HTML</title>
<link rel="stylesheet" href="css/sexy.css"/>
</head>
<body>
<script data-main="main" src="require.js"></script>
</body>
</html>app bootstrap
main.js
require(['app'], function (app) {app.start();}, function (err) {require(['logger'], function (logger) {logger.error('App Failed To Load Restarting!');location.reload();});});
two globals story
the REQUIRE function
-
Used to load top level resources.
- Used to load scripts dynamically.
the define function
- Used to define modules.
see the DIFFERENCe
// define a module that load content dynamically define(['require', 'login', 'text!template'], function (require, login, template) { login.open(template);login.onOK = function () {//load some scripts lazilyrequire(['app'], function (app) {login.resolve('success');app.start();});}//handle failed login here...return login.promise();} )
amd! PLUGINS
css, html, json, i18n, text, templates, images, files, coffeescript, typescript, ES6, and many more
require paths
requirejs.config({enforceDefine : true,baseUrl:'js/myApp' paths : {handlebars:'lib/handlebars',someModule:'modules/someModule',jquery : ['http://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min','lib/jquery']} });
shims
Configure the dependencies, exports, and custom initialization for older "browser globals" scripts that do not use define()
requirejs.config({ shim: {'app.drawCirclePlugin': ['app']'drawSVGPlugin': {deps: ['app'],exports: 'drawSVG'} } });
require config map
requirejs.config({ map: { 'some/newmodule': {'dependency': 'dependency.version.2'},'some/oldmodule': {'dependency': 'dependency.version.1'} } });
Two require contexts
var require1 = requirejs.config({context: "version1",baseUrl: "app/lib/version/1"});var require2 = requirejs.config({context: "version2",baseUrl: "app/lib/version/2"});
Build PROCESS for modules
wtf MY BUILD IS
F5 OR CTRL+F5
what are we building for?
- Minify resources (javascript,html,css,images).
- Concat files (gzip is happier).
- Drink coffee.
- Analyze code coverage.
- Run our awesome test suite.
- Find errors that we do not find.
- Run fancy command line tools.
r.js
Builds your AMD moules.
Runs on java, node, browser
r.js -o path/to/build.js
- Resolve Dependencies.
- Combines related scripts together into build layers and minifies them.
- Optimizes CSS by inlining CSS files referenced by @import and removing comments.
what it CAN'T do?
Yes
define(['a', 'b'], function (a, b) {});
require(['a', 'b']);
No
var mods = someCondition ? ['a', 'b'] : ['c', 'd'];require(mods);
build Config
({
baseUrl: ".",
name: "main",
out: "main-built.js",
paths: {
jquery: "empty:"
}
})harmony modules
new keywords
MODULE
define a module
import
import modules using destructuring
export
export variables from a module
es6 module
module 'math' {
export function sum(x, y) {
return x + y;
}
export var pi = 3.141593;
}Importing
import { sum, pi } from "math";sum(pi,pi);
more ways to IMPORT
import $ from "jquery";import { encrypt, decrypt } from "crypto";import { encrypt as enc } from "crypto";
loading harmony
System.baseURL = '/lib';//load modulesSystem.import(['js/test1', 'js/test2'], function(test1, test2) { console.log('test1.js loaded', test1); console.log('test2.js loaded', test2); }, function(err) { console.log('loading error'); });//load a script from urlSystem.load('js/libs/jquery-1.7.1.js', function() { var $ = System.global.jQuery; console.log('jQuery loaded', $); $('body').css({'background':'blue'}); });
use them today
Loader
Transpailer
Grunt plugin
Typescript
demo/QUESTIONS?
Javascript Modules
By jsmaker
Javascript Modules
- 2,656
