Introduction to the Component JavaScript Package Manager

By Toby Ho

Component is a front-end JavaScript package manager developed by the prolific Tj Holowaychuk. It embodies the philosophy of small modules and is designed to manage assets as well as JavaScript. Currently, there exist over 1600 “components”. Although there are more popular JS package managers than Component, I chose to cover it because I love an underdog.

Installing

Before getting started, you’ll need to install Node, which is a prerequisite of Component. Installing Node is as simple as clicking on “Download” on the Node website, and then running the installer. To verify you have successfully installed Node, run node from the command line and see that the executable exists.

Next, install Component using npm (sudo may be required on some platforms)

npm install component -g

Component is installed! If you type component you should see its usage info

Usage: component [options]

Options:

-h, --help     output usage information
-V, --version  output the version number

Commands:

install [name ...]      install one or more components
create [dir]            create a component skeleton
search [query]          search with the given query
convert <file ...>      convert html files to js modules
info <name> [prop]      output json component information
changes <name>          output changelog contents
wiki                    open the components list wiki page
build                   build the component
ls                      list installed components

Component has several commands. Let’s first take a look at install, and build.

Create a Project

To create an application which uses components, all that’s required is that the root directory of the project contains a valid component.json file. So let’s set these up

mkdir hello_component
cd hello_component

Next, create a file component.json with the following content

{
  "name": "hello_component"
}

Congratulations! Now, we can start installing components.

Installing a Component

For demostration purposes, we’ll install the dialog component:

component install component/dialog

component/dialog is simply an alias to the Github url: https://github.com/component/dialog. All components are identified by their Github URL. Once you’ve installed dialog, you’ll notice that a components directory was created, and that it contains a component-dialog subdirectory plus a bunch of others

$ ls components
component-classes          component-indexof
component-css              component-matches-selector
component-delegate         component-overlay
component-dialog           component-query
component-dom              component-sort
component-domify           component-type
component-emitter          component-value
component-event

All the other components that were installed were installed because they are either a direct dependency or a transitive dependency of component/dialog.

Also note that your component.json has been modified – a “dependencies” field has been added containing component/dialog

"dependencies": {
  "component/dialog": "*"
}

Having the dependencies listed in component.json allows you to easily get back all the components you need even if you’ve deleted the components directory. In this situation, you can restore the dependencies listed via the command: component install.

Next, to test out the dialog, we need to build it.

Build It

In order to consume any components, you will need build them – which combines all of the components you’ve currently installed into a .js file and a .css file. Why CSS? Because components can contain CSS – for example, dialog does.

component build

Now you should see a build directory which contains a build.js as well as a build.css.

Test It

The only other thing we need to do now is to create a test page that links these files:

<!doctype html>
<html>
<head>
  <title>Hello Dialog</title>
  <link href="build/build.css" rel="stylesheet">
  <script src="build/build.js"></script>
</head>
<body>
  <h1>Hello Dialog</h1>
</body>
</html>

Sweet! Open it up in your browser, but nothing happens. Oops, we still need to write some JavaScript. First let’s bring in the dialog component using the require function:

var Dialog = require('dialog');

Then make an openDialog function which calls the dialog component API:

function openDialog(){
  var dialog = new Dialog('Hello World', 'Welcome human!')
    .closable() // this adds an `x` button on the top right
    .modal()    // makes it a modal dialog

  dialog.show()
}

To activate this function, put a button on a page, and just for now, use an onclick attribute

<button id="button" onclick="openDialog()">Open</button>

Refresh the page, click the button you should see a modal dialog!

component-dialog

Full Source

Do Some DOM

Using the onclick attribute is ok for a quick example, but would be unadvised for a real app -so let’s rewrite this in a cleaner way. jQuery time, right? Not so fast! In the land of Component, instead of jQuery, we can use the much more light-weight dom component

component install component/dom

Check your component.json and make sure it contains “component/dom” as a dependency. There’s currently a bug in Component that causes a dependency not to get added if it already exists in the components directory. If it’s not there, just add it manually – so we should have:

"dependencies": {
    "component/dialog": "*",
    "component/dom": "*"
}

Now rebuild the components.

component build

Once rebuilt, we can do this

var dom = require('dom');
...
dom('#button').on('click', openDialog);

Same result, but cleaner code! Very jQuery-like, no?

Full Source

Finding Components

How do you know what components exist? You can peruse the components wiki page – which in fact is the official registry for components. Alternatively you can also use the component search command, for example:

component search dom

…to search for all dom-related components.

Screencast

The following video covers the previous examples.

Making Your Own Component?

Why would one want to make a component? There are mainly two reasons:

  1. Code organization – breaking up your application into small logical pieces allows other team members and future you navigate the code base more easily.
  2. Code sharing – if you find that an existing component in your application is applicable in another application you are building, it reduces the build cost of the new application. Furthermore, open sourcing the component opens up the possibility of code reuse with anyone in the world.

With that, let’s make a local component (for the purpose of code organization) and then we’ll make the component public – to share it with the world.

Setting Up

To set up the project, create a new directory and within it create a component.json file with these contents

{
  "name": "My App",
  "local": [],
  "paths": ["mycomponents"]
}

The paths property tells Component where to search for local components. We’ve defined mycomponents as the subdirectory where they will be located. Let’s create this directory:

mkdir mycomponents

The local property is an explicit list of the local components which will be included in the build when we rebuild the components via component build. It’s empty now because we don’t have any yet, so let’s make one.

Making A Local Component

Earlier we created a “hello world button” – which when clicked, opens up a dialog box that says “Hello, world!”. Now we plan to extract the button into a library so that we can require it, initialize it and attach it to the DOM, like this:

var HelloButton = require('hello_button');
var aButton = HelloButton();
aButton.appendTo(document.body);

To create a skeleton for the component, use the component create command with the -l flag – for local.

component create mycomponents/hello_button -l

This will prompt you for a name, description and a whether it contains JS, CSS, and HTML – say yes to all three.

$ component create mycomponents/hello_button -l
name: hello_button
description: A hello world button.
does this component have js? ye 
does this component have css? y
does this component have html? y

  create : mycomponents/hello_button
  create : mycomponents/hello_button/index.js
  create : mycomponents/hello_button/template.html
  create : mycomponents/hello_button/hello_button.css
  create : mycomponents/hello_button/component.json

Note that some files have been created for you, including a JS file, a CSS file and an HTML file. It also created mycomponents/hello_button/component.json. Open it up and we see this

{
  "name": "hello_button",
  "description": "A hello world button.",
  "dependencies": {},
  "development": {},
  "main": "index.js",
  "scripts": [
    "index.js"
  ],
  "templates": [
    "template.html"
  ],
  "styles": [
    "hello_button.css"
  ]
}

The scripts, templates and styles properties contain the paths to each file of interest – this is important. A component must explicitly list each JavaScript file, template file, and stylesheet file that it needs.

We will put the button’s markup in template.html.

<button class="hello_button">Click me!</button>

In index.js we will “require” this template file:

var markup = require('./template.html');

What? You can require an HTML file? Why yes. Yes you can. During the build step, Component converts HTML files listed as templates to JavaScript modules which return a string containing the markup in the file. The idea is that you can use any templating engine you want to – simply add a build step to compile the template – but component has built-in support for the simplest templating engine of all: plain HTML. Also note that we are using a relative path to require the template – this is necessary when requiring another file within the same component.

To create the button, we use the dom component:

var dom = require('dom');
...
var button = dom(markup);

We now implement the component by extracting code from the previous example into index.js, and exporting a function which creates and returns the button – in the CommonJS module system, this is done by assigning a value to module.exports.

var template = require('./template.html');
var Dialog = require('dialog');
var dom = require('dom');

module.exports = function(){
  var button = dom(template)
    .on('click', openDialog);
  return button;
}

function openDialog(){
  var dialog = new Dialog('Hello World', 'Welcome human!')
    .closable()
    .modal();
  dialog.show();
}

Next create a new test page:

<!doctype html>
<html>
<head>
  <title>Hello Dialog</title>
  <link href="build/build.css" rel="stylesheet">
  <script src="build/build.js"></script>
</head>
<body>
  <h1>Hello Dialog</h1>
  <script>
  var HelloButton = require('hello_button');
  var aButton = HelloButton();
  aButton.appendTo(document.body);
  </script>
</body>
</html>

If you rebuild and load the page now, you’ll get errors. There are two issues. First we need to specify the parent project’s dependency on “hello_button”. Also since it no longer directly requires component/dom and component/dialog – those can be removed. Add “hello_button” to the main project’s “local” property, like so:

{
  "name": "hello_component",
  "paths": ["mycomponents"],
  "local": ["hello_button"],
  "dependencies": {}
}

Next, we establish hello_button’s dependency on component/dom and component/dialog: in mycomponents/hello_button/component.json make sure you have:

...
"dependencies": {
  "component/dom": "*",
  "component/dialog": "*"
},
...

Re-install and then rebuild everything in the parent project directory

component install
component build

Reload the page and everything should work just like the earlier example.

We have yet to make use of the CSS file in the hello_button component, so let’s do that. Let’s make this button fancy! In mycomponents/hello_button/styles.css put

button.hello_button{
  color: red;
  font-family: Impact;
  font-size: 2em;
  background-color: green;
  border: 5px solid red;
}

Rebuild

component build

Aaaand BAM! Colors.

component-button

Auto-Rebuilding

During the course of building this component, you might have had to type component build quite a few times. This gets tedious, doesn’t it? Tj recommends using a C program called watch, which simply reruns a supplied command every second. To install it:

git clone git@github.com:visionmedia/watch.git
cd watch
make install

This installs the watch command, and you can now do watch component build from the project directory in a separate terminal, and not have to manually rebuild.

Making It Public

If you had wanted to make a public component in the beginning, you would have used the component create command without the -l flag – which will scaffold out some extra things for you in the project. But since we already have a working local component, we’ll just convert it to a public component.

The main things you need for a public component which are not already present in a local component are:

  1. a “repo” property in component.json – the Github repo path of the component;
  2. a “version” property in component.json – a version number becomes important when code becomes public and others depend on it;
  3. a “license” property in component.json – the open source license that the component is released under;
  4. A README.md file;
  5. All dependencies of the component, which must also be public components.

We’ll move the component outside of the parent project:

mv mycomponents/hello_button ../hello_button
cd ../hello_button

Edit the component.json to add some fields to it (replace <github user> with your own Github username):

...
  "repo": "<github user>/hello_button",
  "version": "0.0.1",
  "license": "MIT",
...

Next add a README.md (follow this or use your imagination):

Hello Button
============

A hello world button.

## Install

    component install <github user>/hello_button

## Usage

``` js
var HelloButton = require('hello_button');
var button = HelloButton();
button.appendTo(document.body);
```

All dependencies of the button component are already public (component/dialog and component/dom), so we are good there. Now we are ready to publish! Create a new repo on Github and call it hello_button. Then back in the terminal:

git init
git add .
git commit -m "First commit"
git remote add origin git@github.com:<github user>/hello_button.git
git push -u origin master

Voila! You’ve created your first component. But let’s make sure it works okay by installing it within the parent project. Go back to the parent project, and remove “hello_button” from the “local” property of component.json. If you component build and reload the page, it should fail. Now, install your new public component

component install <github user>/hello_button
component build

Reload the page now, and it should work as before!

Adding It To The Registry

If this component were actually useful, the next step would be to add it to the Components Registry so that other people could find it. The registry is nothing but a wiki, so to add an entry amounts to clicking “Edit Page”, adding a link to your component’s project repo, and writing a brief description.

Screencast

If you wish, you can watch the demonstration building your own compoent in screencast form – get your popcorn!

This article was originally published at https://smalljs.org/package-managers/component-part-1/ and https://smalljs.org/package-managers/component-part-2/

Previous

8 Bootstrap Alternatives

CSS for Beginners with Dreamweaver

Next

Comments are closed.