CanJS - Steal

canjs

http://canjs.com/guides/Using.html
http://blog.bitovi.com/using-canjs-2-2-with-stealjs/ - done reading
http://stealjs.com/
http://blog.bitovi.com/training-series-stealjs-overview/
http://blog.bitovi.com/get-started-with-stealjs/
https://github.com/matthewp/steal-sweet

How can we use Steal with CanJS?

npm install can steal --save

jQuery will be installed and loaded automatically since it is a peer dependency of CanJS. Then create an index.html like this:

<!DOCTYPE html>
<html>
  <head>
    <title>CanJS + Steal + NPM demo</title>
  </head>
  <body>
    <script type="text/javascript" src="node_modules/steal/steal.js"></script>
  </body>
</html>

Steal will now automatically load its configuration from the package.json we initialized. Because it supports different module formats we can choose to use ES6 modules (and any other ES6 features provided by the Traceur or Babel transpilers), CommonJS or AMD. In ES6 an app.js that loads jQuery and Stache and renders a simple template when the document is ready can look like this:

import $ from 'jquery';
import stache from 'can/view/stache/stache';

const template = stache('Hello {{message}}!');

$(() => {
  $('body').append(template({ message: 'David' }));
});

The same file in CommonJS would look like:

var $ = require('jquery');
var stache = require('can/view/stache/stache');

var template = stache('Hello {{message}}!');

$(function() {
  $('body').append(template({ message: 'David' }));
});

And using AMD like this:

define(['jquery', 'can/view/stache/stache'], function($, stache) {
  var template = stache('Hello {{message}}!');

  $(function() {
    $('body').append(template({ message: 'David' }));
  });
});

If you now open index.html you will see that all dependencies are being loaded and the view is rendered. The zero configuration approach already works with many client-side JavaScript libraries that are available on NPM like jQuery, Lodash, MomentJS or ChartJS. Additional configuration, like mappings and shims to libraries that do not support a module loader can be put into a system property in the package.json.

For example, if you downloaded the Tooltipster jQuery plugin and put it into a lib/tooltipster folder in your project, the configuration to make it available as the tooltipster module and load its CSS file automatically would look like this:

{
  "name": "steal-can",
  "version": "0.0.1",
  "description": "A StealJS + CanJS example",
  "main": "app",
  "author": "Bitovi",
  "license": "MIT",
  "dependencies": {
    "can": "^2.2.5",
    "jquery": "^2.1.3",
    "steal": "^0.9.3"
  },
  "system": {
    "paths": {
      "tooltipster": "lib/tooltipster/js/jquery.tooltipster.js"
    },
    "meta": {
      "tooltipster": {
        "deps": ["lib/tooltipster/css/tooltipster.css!"]
      }
    }
  }
}

Next, create a main.stache template for your app:

<!-- main.stache -->
<h1>{{message}}</h1>

Next, create a main module for your application. Import CanJS's core, jQuery, and your template to say "Hello World":

// main.js
import can from "can";
import $ from "jquery";
import template from "./main.stache!";
var data = new can.Map({message: "Hello World"});
$("body").append(template(data));

Finally, create a page that loads steal.js and specifies "main" as the main module:

<html>
    <body>
        <script src="./node_modules/steal/steal.js" data-main="main"></script>
    </body>
</html>

It's better if you import just what you need. Instead of loading all of CanJS's core, we can load just "can/map/map" like:

// main.js
import Map from "can/map/map";
import $ from "jquery";
import template from "./main.stache!";
var data = new Map({message: "Hello World"});
$("body").append(template(data));

StealJS supports "modlet" module names that end with "/". This means that the above could also be written like:

// main.js
import Map from "can/map/";
import $ from "jquery";
import template from "./main.stache!";
var data = new Map({message: "Hello World"});
$("body").append(template(data));

Besides ES6 modules, StealJS supports AMD, and CommonJS. You could also write main.js like:

// main.js
var Map = require("can/map/");
var $ = require("jquery");
var template = require("./main.stache!");
var data = new Map({message: "Hello World"});
$("body").append(template(data));

Then we can load and initialize the plugin in app.js:

import $ from 'jquery';
import 'tooltipster';
import stache from 'can/view/stache/stache';

const template = stache('<div title="Hello {{message}}!">Hover me for a tooltip</div>');

$(() => {
  $('body').append(template({ message: 'David' }));
  $('div').tooltipster();
});

How can we create the production build?

To build the project for production we will use the steal-tools NPM package that we can install as a development dependency:

npm install steal-tools --save-dev

Running steal-tools without any parameters will build using our package.json as the configuration. Lets add a build NPM script that simply runs the steal-tools binary we just installed:

{
  "name": "steal-can",
  "version": "0.0.1",
  "description": "A StealJS + CanJS example",
  "main": "app",
  "scripts": {
    "build": "steal-tools"
  },
  "author": "Bitovi",
  "license": "MIT",
  "dependencies": {
    "can": "^2.2.5",
    "jquery": "^2.1.3",
    "steal": "^0.9.3"
  },
  "devDependencies": {
    "steal-tools": "^0.9.4"
  },
  "system": {
    "paths": {
      "tooltipster": "lib/tooltipster/js/jquery.tooltipster.js"
    },
    "meta": {
      "tooltipster": {
        "deps": ["lib/tooltipster/css/tooltipster.css!"]
      }
    }
  }
}

The production build can now be kicked off with:

npm run build

The build files will end up in dist/bundles/app.css and dist/bundles/app.js. To load those files instead of the individual modules we need to add a main="app" and env="production" to the Steal script tag in index.html:

<!DOCTYPE html>
<html>
  <head>
    <title>CanJS + Steal + NPM demo</title>
  </head>
  <body>
    <script type="text/javascript" src="node_modules/steal/steal.js" env="production" main="app"></script>
  </body>
</html>

Now the application is ready to ship.

When using StealJS with the generated application you can simply run

./js app/scripts/build.js

in your JavaScriptMVC folder. This will create app/production.js and app/production.css which will be loaded when referencing steal.production.js in app/index.html (instead of steal.js itself).

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License