Up and Running with JSPM

JSPM is a relatively new package manager, and it brands itself as

Frictionless browser package management

I have to agree. It stands out from the other package managers for a few reasons.

  1. It lets you manage your dependencies across registries.

  2. A flat, versioned dependency tree.

  3. Loads all module formats.

  4. It has plugins for build steps and optimized, self executing bundles.

Getting started with JSPM is pretty familiar if you've been working with npm. Start up a new npm project by running npm init in whatever directory you want. Then, install JSPM both locally and globally.

npm install -g jspm

cd project_folder (if you're not already there)

npm install jspm -D

Now to get started, we can run jspm init.

At this point, JSPM will ask you a series of questions about where you want things to be and how you want to transpile your code. For our purposes, we can take the default option for every question except one.

Enter client baseURL (public folder URL) [/]:

I'm going to keep my index.html and compiled JS in a folder called public. You can put those things wherever, this is where you can set that.

Here's some more info about the options we just went through.

baseURL: This should be set to the public folder where your server will serve from, relative to the package.json file. Defaults to the package.json folder itself.

jspm packages folder: The folder where jspm will install external dependencies.

Config file path: The jspm config file for your application. Should be within the baseURL and checked in to version control.

Client baseURL: The URL from the browser where the public folder is hosted.

Transpiler: Change this option at any time with jspm dl-loader babel. Custom transpilation options can also be set through babelOptions or traceurOptions in the jspm config file.

You can find this and more docs for JSPM here.

Alright so from here we can start setting up our project.

We need and index.html file in our public folder and a src folder with a main.js file.

├─── package.json
├─── config.js
├─┬ jspm_packages/
├─┬ node_modules/
├─┬ public/
 │ ├── index.html
 └─┬ src/
   └── main.js

Let's keep our HTML simple for this example, here it is.

public/index.html

<!doctype html>  
<html>  
  <head>
  </head>
  <body>
    <div id="mount"></div>
    <script src="./main.js"></script>
  </body>
</html>  

We point at one file that will be the starting place for our app. Let create the file that will be bundled into this one now.

src/main.js

const mainDiv = document.createElement('div').appendChild(document.createTextNode('Good to Go!'))

function startApp(mainElement) {  
  mainElement.appendChild(mainDiv)
}

startApp(document.getElementById('mount'))  

Here we have a really fancy app, we make an element and put some text in it, then finally pass it through a function that will append it to the mount div in index.html.

That's all the code. Now to bundle this, run

jspm bundle-sfx src/main.js public/main.js

This creates a self executing module so that we don't explicitly have to include System.js in our index file.
You can make a quick npm script for it since you will likely be doing this often. I made these two scripts.

"start": "node server.js"

"build": "jspm bundle-sfx src/main public/main.js"

First we can run npm run build and then we can serve our app with npm run start. We do need a server to do this, Here's a quick Hapi.js server. If you want to use this, just install hapi and inert with npm.

npm install --save hapi inert

server.js

const Path = require('path')  
const Hapi = require('hapi')  
const Inert = require('inert')

const server = new Hapi.Server({  
    connections: {
        routes: {
            files: {
                relativeTo: Path.join(__dirname, 'public')
            }
        }
    }
})
server.connection({ port: 3000 })

server.register(Inert, () => {})

server.route({  
    method: 'GET',
    path: '/{param*}',
    handler: {
        directory: {
            path: '.',
            redirectToSlash: true,
            index: true
        }
    }
})

server.start((err) => {

    if (err) {
        throw err
    }

    console.log('Server running at:', server.info.uri)
})

This just serves index.html for the main route and serves static files from public. So now we're set, build your code, then run your app and you should be good to go!