Skip to content
Matthew Phillips edited this page Sep 25, 2015 · 43 revisions

Setup

Install donejs

npm install donejs -g

Create a new project

donejs init donejs-chat

Then go into the application folder

cd donejs-chat

Start the donejs server

donejs develop

Add bootstrap and checkout live-reload

Install bootstrap

npm install bootstrap --save

Add it to your page

Change index.stache to:

<html>
  <head>
    <title>{{title}}</title>
    {{asset "css"}}
  </head>
  <body>
    <can-import from="bootstrap/less/bootstrap.less!" />
    <can-import from="donejs-chat/styles.less!" />
    <can-import from="donejs-chat/app" as="viewModel" />

    {{asset "inline-cache"}}

    {{#switch @env.NODE_ENV}}
      {{#case "production"}}
        <script src="http://donejs-chat.divshot.io/node_modules/steal/steal.production.js"  main="donejs-chat/index.stache!done-autorender"></script>
      {{/case}}
      {{#default}}
        <script src="/node_modules/steal/steal.js"></script>
      {{/default}}
    {{/switch}}
  </body>
</html>

Add some HTML that uses it

<div class="container">
  <div class="row">
    <div class="col-sm-8 col-sm-offset-2">
      <h1>Hello world</h1>
    </div>
  </div>
</div>

Show live-reload awesomeness

Make some changes and see stuff updates. Talk about how live-reload even works on the server!!!

Setup Basic Routing

Generate Home Component

donejs generate component home.component chat-home

Generate chat-messages component

donejs generate component messages chat-messages

Set up navigation between components.

  1. Add link to chat-home
<can-component tag="chat-home">
  <style type="less">
    display: block;

    h1.page-header { margin-top: 0; }
  </style>
  <template>
    <can-import from="can/view/href/" />
    <h1 class="page-header text-center">
        <img src="http://donejs.com/static/img/donejs-logo-white.svg" alt="DoneJS logo" />
        <br>Chat
    </h1>

    <a can-href="{ page='chat' }" class="btn btn-primary btn-block btn-lg">Start chat</a>
  </template>
</can-component>
  1. Add link on chat page (messages/messages.stache)
<can-import from="can/view/href/" />
<h5><a can-href="{ page='home' }">Home</a></h5>
<p>{{message}}</p>
  1. Add route in app.js
route('/:page', { page: 'home' });
  1. Load dynamically in index.stache
<div class="container">
  <div class="row">
    <div class="col-sm-8 col-sm-offset-2">
    {{#eq page 'chat'}}
      <can-import from="donejs-chat/messages/">
        {{#if isPending}}
          Loading...
        {{else}}
          <chat-messages/>
        {{/if}}
      </can-import>
    {{else}}
      <can-import from="donejs-chat/home.component!">
        {{#if isPending}}
          Loading...
        {{else}}
          <chat-home/>
        {{/if}}
      </can-import>
    {{/eq}}
    </div>
  </div>
</div>

Complete the messages page

Generate Message model

donejs generate supermodel message

Set URL to http://donejs-chat.herokuapp.com/api/messages.

Use Message model

In src/messages/messages.stache:

<message-model get-list="{}">
  <h5><a can-href="{ page='home' }">Home</a></h5>
  <div class="list-group">
    {{#each ./value}}
      <a class="list-group-item">
        <h4 class="list-group-item-heading">{{name}}</h4>
        <p class="list-group-item-text">{{message}}</p>
      </a>
    {{/each}}
    {{^if ./value.length}}
    <a class="list-group-item">
      <h4 class="list-group-item-heading">No messages</h4>
    </a>
    {{/if}}
  </div>
</message-model>

alternate:

<can-import from="donejs-chat/models/message" />
<h5><a can-href="{ page='home' }">Home</a></h5>
<message-model get-list="{}" class="list-group">
  {{#each ./value}}
    <a class="list-group-item">
      <h4 class="list-group-item-heading">{{name}}</h4>
      <p class="list-group-item-text">{{message}}</p>
    </a>
  {{else}}
    <a class="list-group-item">
      <h4 class="list-group-item-heading">No messages</h4>
    </a>
  {{/each}}
</message-model>

Create messages

  1. add html, and (enter) event handler
<div class="row">
  <div class="col-sm-3">
    <input type="text" class="form-control" id="name" placeholder="Your name" can-value="{name}">
  </div>
  <div class="col-sm-9">
    <input type="text" class="form-control" id="message" placeholder="Your message" can-value="{message}" (enter)="{send}">
  </div>
</div>
  1. import Message model in messages.js
<can-import from="donejs-chat/models/message" />
  1. Add send method in src/messages/messages.js
import Component from 'can/component/';
import Map from 'can/map/';
import 'can/map/define/';
import './messages.less!';
import template from './messages.stache!';
import Message from '../models/message';

export const ViewModel = Map.extend({
  send() {
    new Message({
      name: this.attr('name'),
      message: this.attr('message')
    }).save().then(msg => this.attr('message', ''));
  }
});

export default Component.extend({
  tag: 'chat-messages',
  viewModel: ViewModel,
  template
});
  1. Talk about set logic

Make it work real-time

> npm install steal-socket.io --save

Add to src/models/message.js

import io from 'steal-socket.io';

const socket = io('http://donejs-chat.herokuapp.com');

socket.on('messages created', order => messageConnection.createInstance(order));
socket.on('messages updated', order => messageConnection.updateInstance(order));
socket.on('messages removed', order => messageConnection.destroyInstance(order));

Make homepage

Add tabs

npm install bit-tabs --save

Import:

<can-import from="bit-tabs/unstyled" />

Add to page:

<bit-tabs tabs-class="nav nav-tabs">
  <bit-panel title="CanJS">
    CanJS provides the MV*
  </bit-panel>
  <bit-panel title="StealJS">
    StealJS provides the infrastructure.
  </bit-panel>
</bit-tabs>

Add some styles:

bit-panel {
    display: block;
    padding: 10px;
}

Talk about cool stuff

  1. Server Side Rendering
  2. Fall through caching
  3. Inline caching
  4. Request combining

Show off build locally.

Run build

node build

Set to production.

Close the old server and run

NODE_ENV=production donejs start

Show bundles loading progressively

Show off div-shot

  1. Create Divshot application, install the CLI tool and log in
> npm install -g divshot-cli
> divshot login
  1. Paste config in
"donejs": {
  "deploy": {
    "root": "dist",
    "services": {
      "production": {
        "type": "divshot",
        "config": {
          "name": "donejs-chat",
          "headers": {
            "/**": {
              "Access-Control-Allow-Origin": "*"
            }
          }
        }
      }
    }
  }
},
...
"system": {
  ...
  "envs": {
    "server-production": {
      "baseURL": "https://donejs-chat.divshot.io/"
    }
  }
}
  1. Run node build again.
  2. Run donejs deploy
  3. Add http://donejs-chat.divshot.io to <script src and to envs.server-production.baseURL
  4. Show off

Desktop and mobile apps

First create an app.html file that looks like:

<html>
<head><title>DoneJS chat</title></head>
<body>
<script load-bundles env="cordova-production" src="node_modules/steal/steal.production.js" main="donejs-chat/index.stache!done-autorender"></script>
</body>
</html>

Cordova

Make sure all platform SDKs like XCode (for iOS) and the Android SDK are installed.

Update build.js to:

var stealTools = require("steal-tools");

var buildPromise = stealTools.build({
  config: __dirname + "/package.json!npm"
}, {
  bundleAssets: true
});

var cordovaOptions = {
  buildDir: "./build/cordova",
  id: "com.donejs.chat",
  name: "DoneJS chat",
  platforms: ["ios"],
  plugins: ["cordova-plugin-transport-security"],
  index: __dirname + "/app.html",
  glob: [
    "node_modules/steal/steal.production.js"
  ]
};

var stealCordova = require("steal-cordova")(cordovaOptions);

// Check if the cordova option is passed.
var buildCordova = process.argv.indexOf("cordova") > 0;

if(buildCordova) {
  buildPromise.then(stealCordova.build).then(stealCordova.ios.emulate);
}

Then run

npm install ios-sim -g

node build cordova

NW.js

Update your package.json:

"main": "app.html",
...
"window": {
  "width": 1060,
  "height": 625,
  "toolbar": false
}

Add to build.js:

var nwOptions = {
  buildDir: "./build",
  platforms: ["osx"],
  files: [
    "package.json",
    "app.html",
    "node_modules/steal/steal.production.js"
  ],
  version: "0.12.3"
};

var stealNw = require("steal-nw");

// Check if the cordova option is passed.
var buildNW = process.argv.indexOf("nw") > 0;

if(buildNW) {
  buildPromise = buildPromise.then(function(buildResult){
    stealNw(nwOptions, buildResult);
  });
}

Add to app.js

import platform from "steal-platform"
if(platform.isCordova || platform.isNW) {
 route.defaultBinding = "hashchange";
}

Then run

node build nw

cd build/donejs-chat/osx64

open donejs-chat.app