- Install Prerequisites
- Setup a new project
- Import your first module
- Import styles
- [Setup hot module swapping]
- Create an ES6 exporting module and modlet
- Create a test with dependency injection
- Import a global script in a CJS modlet
- Build a production app
- Build a progressive loading production app
- Export modules to other formats
- Install NodeJS 6.
> mkdir myhub
> cd myhub
> npm init
Create myhub.html with:
<!DOCTYPE html>
<html lang="en">
<head></head>
<body>
Hello World!
</body>
</html>
Install and run local fileserver:
> npm install http-server -g
> http-server
Open http://127.0.0.1:8080/myhub.html.
> npm install steal --save
> npm install steal-tools --save-dev
> npm install jquery --save
Create myhub.js with the following:
import $ from "jquery";
$("body").html("<h1>Goodbye script tags!</h1>");
Update myhub.html with:
<!DOCTYPE html>
<html lang="en">
<head></head>
<body>
Hello World!
<script src="./node_modules/steal/steal.js"></script>
</body>
</html>
Update package.json to:
{
"name": "myhub",
"version": "1.0.0",
"description": "",
"main": "myhub.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"jquery": "^3.0.0",
"steal": "^0.16.21"
},
"devDependencies": {
"steal-tools": "^0.16.5"
}
}
Reload myhub.html to see your changes.
Create myhub.less with:
body h1 {
color: #2193C4;
}
Import it with the following updated myhub.js:
import $ from "jquery";
import "./myhub.less";
$("body").html("<h1>Goodbye script tags!</h1>");
Review module identifiers and module names.
Install bootstrap with:
> npm install bootstrap --save
Update the myhub.html to use bootstrap with:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<script src="./node_modules/steal/steal.js"></script>
</body>
</html>
Import it and use it with the following updated myhub.js:
import $ from "jquery";
import "./myhub.less";
import "bootstrap/dist/css/bootstrap.css";
$("body").append(
"<div class='container'>"+
"<h1>Goodbye script tags!</h1>"+
"</div>");
Create repos/repos.html with:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<div id="repos"/>
<script src="../node_modules/steal/steal.js" main="@empty">
import repos from "myhub/repos/repos";
repos("#repos");
</script>
</body>
</html>
Create repos/repos.js with:
import $ from "jquery";
import "bootstrap/dist/css/bootstrap.css";
export default function(selector){
$(selector).html("Loading...")
$.ajax({
url: "https://api.github.com/users/justinbmeyer/repos",
jsonp: "callback",
dataType: "jsonp",
success: function( response ) {
var defs = response.data.map(function(repo){
return `<dt><a href="${repo.url}">${repo.name}</a></dt><dd>${repo.description}</dt>`
});
$(selector).html("<dl class='dl-horizontal'>"+defs.join("")+"</dl>");
}
});
}
Create repos/repos-test.html with:
<title>myhub/repos/repos</title>
<script src="../node_modules/steal/steal.js"
main="myhub/repos/repos-test"></script>
<div id="qunit-fixture"></div>
Install steal-qunit
with:
> npm install steal-qunit --save-dev
Create repos/repos-test.js with:
import QUnit from "steal-qunit";
import repos from "./repos";
QUnit.module("myhub/repos/");
QUnit.test("basics", function(){
stop();
var fixtureEl = document.getElementById("qunit-fixture");
repos(fixtureEl);
QUnit.equal(
fixtureEl.innerHTML,
"Loading...", "starts with loading");
var interval = setInterval(function(){
var dl = fixtureEl.getElementsByTagName("dl");
if(dl.length === 1) {
QUnit.ok(true, "inserted a dl");
QUnit.start();
clearInterval(interval);
}
},100);
});
Update myhub.js to:
import $ from "jquery";
import "./myhub.less";
import "bootstrap/dist/css/bootstrap.css";
import repos from "./repos/repos";
$("body").append(
"<div class='container'>"+
"<h1>Goodbye script tags!</h1>"+
"<div id='repos'/>"+
"</div>");
repos('#repos');
Update repos/repos-test.js with:
import QUnit from "steal-qunit";
import repos from "./repos";
import clone from 'steal-clone';
import $ from 'jquery';
QUnit.module("myhub/repos/");
QUnit.test("basics", function(){
QUnit.stop();
var fixtureEl = document.getElementById("qunit-fixture");
repos(fixtureEl);
QUnit.equal(
fixtureEl.innerHTML,
"Loading...", "starts with loading");
var interval = setInterval(function(){
var dl = fixtureEl.getElementsByTagName("dl");
if(dl.length === 1) {
QUnit.ok(true, "inserted a dl");
QUnit.start();
clearInterval(interval);
}
},100);
});
QUnit.asyncTest("basics with dependency injection", function(){
var jQuery = function(selector){
return $(selector)
};
jQuery.ajax = function(options){
setTimeout(function(){
options.success({
data: [{
url: "http://stealjs.com",
name: "StealJS",
description: "Futuristic Module Loader"
}]
});
QUnit.equal(
$("#qunit-fixture").html(),
'<dl class="dl-horizontal">'+
'<dt><a href="http://stealjs.com">StealJS</a></dt><dd>Futuristic Module Loader</dd>'+
'</dl>',
"updated with request");
QUnit.start();
},1);
};
clone({
"jquery": {"default": jQuery}
}).import("myhub/repos/repos").then(function(module){
var repos = module["default"];
var fixtureEl = document.getElementById("qunit-fixture");
repos(fixtureEl);
});
});
Run:
> npm install justifiedGallery --save
Create puppies/puppies.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<div class='container'>
<div id="puppies"/>
</div>
<script src="../node_modules/steal/steal.js" main="@empty">
var puppies = require("myhub/puppies/puppies");
puppies("#puppies");
</script>
</body>
</html>
Create puppies/puppies.js:
require("justifiedGallery");
module.exports = function(selector) {
};
Change package.json to:
{
"name": "myhub",
"version": "1.0.0",
"description": "",
"main": "myhub.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"bootstrap": "^3.3.6",
"jquery": "^3.0.0",
"justifiedGallery": "^3.6.2",
"steal": "^0.16.21"
},
"devDependencies": {
"steal-qunit": "^0.1.1",
"steal-tools": "^0.16.5"
},
"system": {
"map": {
"justifiedGallery": "justifiedGallery/src/js/justifiedGallery"
},
"meta": {
"justifiedGallery/src/js/justifiedGallery": {
"format": "global",
"deps": ["jquery","justifiedGallery/src/less/justifiedGallery.less"]
}
}
}
}
Change puppies/puppies.js to:
require("justifiedGallery");
var $ = require("jquery");
module.exports = function(selector) {
$(selector).html("Loading...");
$.ajax({
url: 'https://api.flickr.com/services/feeds/photos_public.gne',
dataType: 'jsonp',
jsonpCallback: "jsonFlickrFeed",
data: {
"tags": "puppy",
"format": "json"
},
success: function(response) {
var html = response.items.map(function(item, index) {
return '<a href="'+item.link+'">'+
'<img alt="'+item.title+'" src="'+item.media.m+'"/>'+
'</a>'
}).join("");
$(selector).html(html).justifiedGallery();
}
});
};
Update myhub.js to:
import $ from "jquery";
import "./myhub.less";
import "bootstrap/dist/css/bootstrap.css";
import repos from "./repos/repos";
import puppies from "./puppies/puppies";
$("body").append(`
<div class='container'>
<h1>Goodbye script tags!</h1>
<a href="#repos">Repos</a> <a href="#puppies">Puppies</a>
<div id='main'/>
</div>`);
var modules = {
repos: repos,
puppies: puppies,
"": function(selector){
$(selector).html("Welcome home");
}
}
var updatePage = function(){
var hash = window.location.hash.substr(1);
modules[hash]("#main");
};
$(window).on("hashchange", updatePage);
updatePage();
Run:
> ./node_modules/.bin/steal-tools
Create index.html with:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<script src="./node_modules/steal/steal.production.js"
main="myhub/myhub"></script>
</body>
</html>
Update index.html to:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="./dist/bundles/myhub/myhub.css" rel="stylesheet">
</head>
<body>
<script>
steal = {
instantiated: {
"bundles/myhub/myhub.css!$css" : null
}
}
</script>
<script src="./node_modules/steal/steal.production.js"
main="myhub/myhub"></script>
</body>
</html>
Run:
> ./node_modules/.bin/steal-tools build --bundleSteal
Update index.html to:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="./dist/bundles/myhub/myhub.css" rel="stylesheet">
</head>
<body>
<script>
steal = {
instantiated: {
"bundles/myhub/myhub.css!$css" : null
}
}
</script>
<script src="./dist/bundles/myhub/myhub.js"></script>
</body>
</html>
Update myhub.js to:
import $ from "jquery";
import "./myhub.less";
import "bootstrap/dist/css/bootstrap.css";
$("body").append(`
<div class='container'>
<h1>Goodbye script tags!</h1>
<a href="#repos">Repos</a> <a href="#puppies">Puppies</a>
<div id='main'/>
</div>`);
var updatePage = function(){
var hash = window.location.hash.substr(1);
if(!hash) {
$("#main").html("Welcome home");
} else {
System.import("myhub/"+hash+"/"+hash).then(function(moduleOrPlugin){
var plugin = typeof moduleOrPlugin === "function" ?
moduleOrPlugin : moduleOrPlugin["default"];
plugin("#main");
});
}
};
$(window).on("hashchange", updatePage);
updatePage();
Update package.json to:
{
"name": "myhub",
"version": "1.0.0",
"description": "",
"main": "myhub.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"bootstrap": "^3.3.6",
"jquery": "^3.0.0",
"jqueryui": "^1.11.1",
"justifiedGallery": "^3.6.2",
"steal": "^0.16.21",
"steal-tools": "^0.16.4"
},
"devDependencies": {
"steal-qunit": "^0.1.1"
},
"system": {
"map": {
"justifiedGallery": "justifiedGallery/src/js/justifiedGallery"
},
"meta": {
"justifiedGallery/src/js/justifiedGallery": {
"format": "global",
"deps": ["jquery","justifiedGallery/src/less/justifiedGallery.less"]
}
},
"bundle": [
"myhub/puppies/puppies",
"myhub/repos/repos"
]
}
}
Run:
> ./node_modules/.bin/steal-tools build --bundleSteal
Create build.js:
var stealTools = require("steal-tools");
stealTools.build({
config: __dirname+"/package.json!npm"
}, {
bundleSteal: true
});
Run the build script with:
> node build.js
Create export.js with:
var stealTools = require("steal-tools");
stealTools.export({
system: {
main: "myhub/repos/repos",
config: __dirname+"/package.json!npm"
},
options: {
verbose: true
},
outputs: {
"+amd": {},
"+global-js": {
exports: {
"myhub/repos/repos":"repos",
"jquery": "jQuery"
},
dest: __dirname+"/dist/global/repos.js"
}
}
});
Run:
> node export.js
Create repos/repos-standalone.html with:
<div id='git-repos'/>
<script src="//code.jquery.com/jquery-3.0.0.js"></script>
<script src="../dist/global/repos.js"></script>
<script>
repos("#git-repos");
</script>
We're not implementing any cache-busting here and one of Chrome or http-server seems to be caching aggressively. I'm having to "Empty Cache and Hard Reload" after adding Bootstrap to see the changes. This could put less experienced new users off if they can't figure out why nothing is changing after changes are made.