How to use Ractive.js components with JSPM as ES6 module.

February 15, 2016

After reading this article you will be able to easily:

  • Install JSPM
  • Add Ractive module
  • Use ES6 modules
  • Build minified code for better performance

To demonstrate ES6 modules I will use component I wrote about in previous post.

Want to try this app? Check this github repo.




Step by step instruction

Installing JSPM

To install JSPM simply use this command: npm install -g jspm Next, to initialize new configuration for JSPM, use this command: jspm init While JSPM configures your app, you will be asked a several questions, you can use defaults.

Package.json file does not exist, create it? [yes]:
Would you like jspm to prefix the jspm package.json properties under jspm? [yes]:
Enter server baseURL (public folder path) [./]:
Enter jspm packages folder [./jspm_packages]:
Enter config file path [./config.js]:
Configuration file config.js doesn't exist, create it? [yes]:
Enter client baseURL (public folder URL) [/]:
Do you wish to use a transpiler? [yes]:
Which ES6 transpiler would you like to use, Babel, TypeScript or Traceur? [babel]:

After app initialization, let’s create our app dictionary: mkdir app In this dictionary you will place all files from your app. Next, you have to edit config.js and add "blacklist": [] line to Babel configuration. Your file now should look like code below

babelOptions: {
    "optional": [
      "runtime",
      "optimisation.modules.system"
    ],
    "blacklist": []
  },

Next thing you have to do is create new index.html file in root directory.

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>JSPM</title>
	<script src="jspm_packages/system.js"></script>
	<script src="config.js"></script>
	<script>
		System.import('app/main');
	</script>
</head>
<body>

</body>
</html>

This is a default index file that imports all necessary files. Now, you have to install packages that we will need in our project, these packages will allow us to import CSS and HTML files. Then you will install Ractive.js package.

jspm install text
jspm install css
jspm install ractive

Creating Ractive.js component

As a reminder, we will use code from my previous blog post. You can find it on https://jsfiddle.net/goleksy/yarhgnz8/

Next, let’s add our files to app directory. Create these directories:

mkdir app/css/
mkdir app/components/contactForm/

In app/css you will store your CSS files. In app/components will be your Ractive.js components. Now, in app/components/contactForm create files named contactForm.html and contactForm.js. Insert below code to contactForm.html. It would be a template for component.

<div class='container'>
 <p class='head'>Do you want us to send our offer to you?</p>
 {{#if !isVisible}}
  <button class='btn btn-default btn-lg' on-click='showForm'>Yes I do</button>
 {{else}}
 <form>
  <div class="form-group">
   <label for="name" class='labels'>Your name</label><br>
   <input type="text" class="form-control {{class}}" id="userName" placeholder="John Smith" value='{{name}}'>
  </div>
  <div class="form-group">
   <label for="exampleInputEmail1">E-mail address</label><br>
   <input type="text" class="form-control {{class}}" id="userEmail" placeholder="[email protected]" value='{{email}}'>
  </div>
  <div class="form-group">
   <label for="phoneNumber">Phone number</label><br>
   <input type="tel" class="form-control" placeholder="0 800 911 1488" value='{{phoneNumber}}'>
  </div>
  <div class="checkbox">
   <label>
    <input type="checkbox" on-click='websiteExists'> Check if you have a website
   </label>
 </div>
 {{#if userHasWebsite}}
  <div class="form-group">
   <label for="websiteAddress">Website URL</label>
   <input type="text" class="form-control" id="websiteAddress" placeholder="http://example.com" value='{{url}}'>
  </div>
 {{/if}}
  <button class="btn btn-primary send" on-click='submitForm'>Send</button>
  <button class="btn btn-danger cancel" on-click='showForm'>Cancel</button>
 </form>
 {{#if success}}
  <div class='alert alert-success'>
   <p>Thank you for registration.<br> We will contact you very soon.
 </p>
 </div>
 {{/if}}
 {{#if registrationFailed}}
  <div class='alert alert-danger'>
  <p>Please fill all required fields.</p>
 </div>
 {{/if}}
 {{/if}}
</div>

Then, paste below code to app/components/contactForm.js:

import template from './contactForm.html!text';
import Ractive from 'ractive';

var ContactForm = Ractive.extend({
  template: template,
  oninit: function() {
    var self = this;
    self.set('isVisible', false);
    self.on({
      'showForm': function(event) {
        self.toggle('isVisible');
        self.set({
          name: '',
          email: '',
          phoneNumber: '',
          url: '',
          success: false,
          class: '',
          registrationFailed: false,
          userHasWebsite: false
        })
        event.original.preventDefault();
      },

      'submitForm': function(event) {
        var name = self.nodes.userName.value;
        var email = self.nodes.userEmail.value;
        if (name == '' || email == '') {
          self.set({
            registrationFailed: true,
            class: 'empty-form'
          });
        }
        else {
          self.set({
            success: true,
            registrationFailed: false,
            class: 'filled-form'
          });
          var user = {
            name: this.get('name'),
            email: this.get('email'),
            phoneNumber: this.get('phoneNumber'),
            url: this.get('url')
          };
          // you can add this user to database for example
          console.log(user);
        };
        event.original.preventDefault();
      },

      'websiteExists': function() {
        self.toggle('userHasWebsite');
        self.set('url', '');
      }
    });
  }
})

Ractive.components.contactform = ContactForm;

As you can see, there are a few changes between JSFiddle example and our final code. First, we imported template and Ractive module. That’s how you import modules in ES6 way. Simply type import FunctionName from 'moduleName'; and that’s it! Other disparity is last line in our code. Ractive.components.contactform = ContactForm;. We’ll use it to make our component globally available. Making anything globally available is generally not a good idea, but for demonstration purpose it’s good enough. Now, create file named styles.css in app/css directory. Insert there whole CSS code from JSFiddle example. You should also add a Bootstrap CSS file, since our contact form app is based on it.

Connecting all parts together

Next, create main.js and main.html files in app directory. main.js will contain all imports and necessary script of your app. File named main.html is our main file where we can place code needed to insert Ractive.js component and other elements of your site. Minimal version of this file should look like this:

<h1> Before Ractive.js component </h1>
<div id='form' class="row">
        <contactform />
</div>
<h1> After Ractive.js component </h1>

Line <contactform /> inserts our Contact Form component exactly in this place. Of course you can use it wherever you want to. Next, insert below code to app/main.js file.

import Ractive from 'ractive';
import template from './main.html!text';
import ContactForm from 'app/components/contactForm/contactForm';

import './css/bootstrap.min.css!';
import './css/styles.css!';

let ractive = new Ractive({
    el :'body',
    template : template
});

This file would import our HTML and CSS files, Ractive.js module and a component. Everything in ES6 manner. As you can see, importing modules in ES6 looks nice and elegant.

Building minified version

To create a minified version of our code for better performance of website, we have to install additional packages:

sudo npm install uglifyjs
jspm install npm:html-dist
jspm install npm:clean-css –dev

These packages will allow us to create one minified file from all our html, css and JS code. To use them, create a file named Makefile and place it in root directory. Then, insert this code:

build:
	- rm -r dist
	mkdir dist
	mkdir dist/app/
	jspm bundle-sfx app/main.js dist/app.js
	./node_modules/.bin/uglifyjs dist/app.js -o dist/app.min.js
	./node_modules/.bin/html-dist index.html --remove-all --minify --insert app.min.js -o dist/index.html

This will create a /dist directory where would be placed our minified code. You should use files generated to /dist on production.

Last thing you have to do to build your page is use command make build. When you type this command you should see the following information:

rm -r dist
mkdir dist
mkdir dist/app/
jspm bundle-sfx app/main.js dist/app.js
     Building the single-file sfx bundle for app/main.js...
ok   Built into dist/app.js with source maps, unminified.
./node_modules/.bin/uglifyjs dist/app.js -o dist/app.min.js
./node_modules/.bin/html-dist index.html --remove-all --minify --insert app.min.js -o dist/index.html

Now, to see if your website is working, simply run serve .. Your website is now available at http://localhost:3000 and minified version is available at http://localhost:3000/dist/

Resources:

Kuba Wyrobek Founder, Meteor Developer
Grzegorz Oleksy Junior Meteor Developer