Skip to content

Instantly share code, notes, and snippets.

@bmomberger-bitovi
Forked from justinbmeyer/stealjs.md
Last active June 24, 2016 17:23
Show Gist options
  • Save bmomberger-bitovi/73f5317201c29cfca8c187d85e18121f to your computer and use it in GitHub Desktop.
Save bmomberger-bitovi/73f5317201c29cfca8c187d85e18121f to your computer and use it in GitHub Desktop.
StealJS Training

Example App

Install Prerequisites

Window Setup

  1. Install NodeJS 6.
  2. Install chocolatey, python, windows sdk, and visual studio as described here.

Linux / Mac Setup

  1. Install NodeJS 6.

Setup a new project

Create a new project folder

> mkdir myhub
> cd myhub
> npm init

npm init will prompt you to set a few options about the project. Press Enter at each one to accept the default.

Create and host dummy page

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.

Install steal, steal-tools, and jquery

> npm install steal --save
> npm install steal-tools --save
> npm install jquery --save

Import your first module

Create the module

Create myhub.js with the following:

import $ from "jquery";

$("body").html("<h1>Goodbye script tags!</h1>");

Point your page at steal.js

Update myhub.html by adding a script tag below the "Hello World":

<!DOCTYPE html>
<html lang="en">
  <head></head>
  <body>
    Hello World!
    <script src="./node_modules/steal/steal.js"></script>
  </body>
</html>

Point package.json to the right main.

Update package.json to change the main script to myhub.js:

{
  "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",
    "steal-tools": "^0.16.4"
  }
}

Reload myhub.html to see your changes.

Import styles

Create and import a less file

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 and import bootstrap

Install bootstrap with:

> npm install bootstrap --save

Update the myhub.html to use bootstrap by adding these meta tags into the document head:

<!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 an ES6 exporting module and modlet

Create the demo page

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 the module

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 the test page

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>

Create the test

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);
});

Use the module

Import the repos script into myhub.js, and make a call to the imported function:

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');

Create test with dependency injection

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);
    });
});

Import a global script in a CJS modlet

Install the global script

Run:

> npm install justifiedGallery --save

Create the modlet

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) {
    
};

Configure justifiedGallery to load

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",
    "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"]
         }
     }
  }
}

Use justifiedGallery

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();
		}
	});
};

Build a production app

Update app to change pages

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();

Build the app and switch to production

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>

Preload css

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>

Bundle steal.js

Run:

> ./node_modules/.bin/steal-tools build --bundleSteal

Update index.html to add steal configuration and references to the built bundles:

<!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>

Build a progressive loading production app

Make the app progressively load

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 bundles to build

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

Make a build script

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

Export modules to other formats

Create an export script

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

Test the standalone module

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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment