epubjs
Version:
Render ePub documents in the browser, across many devices
124 lines (121 loc) • 14.3 kB
HTML
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Chapter 8. Extending Node</title><link rel="stylesheet" href="core.css" type="text/css"/><meta name="generator" content="DocBook XSL Stylesheets V1.74.0"/></head><body><div class="chapter" title="Chapter 8. Extending Node"><div class="titlepage"><div><div><h1 class="title"><a id="chapter_9"/>Chapter 8. Extending Node</h1></div></div></div><div class="sect1" title="Modules"><div class="titlepage"><div><div><h1 class="title"><a id="I_sect15_d1e13553"/>Modules</h1></div></div></div><p>The module system in <a id="no8.1" class="indexterm"/>Node makes it easy to create extensions to the platform. It
is simple to learn and enables us to easily share reusable library code.
The Node module system is based on the commonJS module<a id="I_indexterm5_d1e13564" class="indexterm"/> specification. We’ve already used lots of modules in the
previous chapters, but here we’ll study how to create our own modules.
<a class="xref" href="ch08.html#example8-1" title="Example 8-1. A simple module">Example 8-1</a> shows one simple implementation.</p><div class="example"><a id="example8-1"/><p class="title">Example 8-1. A simple module</p><div class="example-contents"><pre class="programlisting">exports.myMethod = function() { console.log('Method output') };
exports.property = "blue";</pre></div></div><p>As you can see, writing a module is as simple as attaching
properties to the <code class="literal">exports</code> global
variable. Any script that is included with <code class="literal">require()</code> will return its <code class="literal">exports</code> object. This means that everything
returned from <code class="literal">require()</code> is in a
closure, so you can use private variables in a module that are not exposed
to the main scope of the program.</p><p>Node developers have created a few conventions around modules.
First, it’s typical to create factory methods for a class. Although you
might also expose the class itself, factory methods give us a clean way to
instantiate objects. For I/O-related classes, one of the arguments is
normally a callback for either the I/O being done or one of its most
common aspects. For example, <code class="literal">http.Server</code> has a factory method called <code class="literal">http.createServer()</code> that takes a callback
function for the <code class="literal">request</code> event, the
most commonly used <code class="literal">http.Server</code>
event.</p></div><div class="sect1" title="Package Manager"><div class="titlepage"><div><div><h1 class="title"><a id="I_sect15_d1e13603"/>Package Manager</h1></div></div></div><p>Being able to make <a id="I_indexterm5_d1e13608" class="indexterm"/>modules is great, but ultimately having a good way to
distribute them and share them with the rest of your team or the community
is essential. The package manager for Node, <code class="literal">npm</code>,
provides a way of distributing code, either locally or via a global
repository of Node modules. <code class="literal">npm</code> helps you manage code
dependencies, installation, and other things associated with distributing
code. Best of all, <code class="literal">npm</code> is all JavaScript and Node. So
if you are already using Node, you are ready to use
<code class="literal">npm</code>, too. <code class="literal">npm</code> provides both the
installation tools for developers and the distribution tools for package
maintainers.</p><p>Most developers will start by using <code class="literal">npm</code> to
install packages using the simple <code class="literal">npm
install</code> command. You can install packages you have locally, but
you’ll probably want to use <code class="literal">npm</code> to install remote
packages from the <code class="literal">npm</code> registry. The registry stores
packages that other Node developers make available to you to use. There
are many packages in the registry: everything from database drivers to
flow control libraries to math libraries. Most things you’ll install with
<code class="literal">npm</code> are 100% JavaScript, but a few of them require
compilation. Luckily, <code class="literal">npm</code> will do that for you. You can
see what’s in the registry at <a class="ulink" href="http://search.npmjs.org">http://search.npmjs.org</a>.</p><div class="sect2" title="Searching Packages"><div class="titlepage"><div><div><h2 class="title"><a id="id847787"/>Searching Packages</h2></div></div></div><p>The <code class="literal">search</code> command <a id="I_indexterm5_d1e13661" class="indexterm"/><a id="I_indexterm5_d1e13666" class="indexterm"/>lists all packages in the global <code class="literal">npm</code>
registry and filters for a package name:</p><a id="I_programlisting5_d1e13675"/><pre class="programlisting">npm search <em class="replaceable"><code>packagename</code></em></pre><p>If you don’t supply a package name, all of the available packages
will be displayed.</p><p>If the package list is out of date (because you added or removed a
package, or you know the package you want should be available but it
isn’t), you can instruct <code class="literal">npm</code> to clean the cache using
the following command:</p><a id="I_programlisting5_d1e13686"/><pre class="programlisting">npm cache clean</pre><p>The next time you ask <code class="literal">npm</code> for a list of
packages, the command will take longer because it will need to rebuild
its cache.</p></div><div class="sect2" title="Creating Packages"><div class="titlepage"><div><div><h2 class="title"><a id="id847859"/>Creating Packages</h2></div></div></div><p>Although most of the packages you get using <a id="I_indexterm5_d1e13698" class="indexterm"/><a id="I_indexterm5_d1e13703" class="indexterm"/>the <code class="literal">npm install</code> command are available
to anyone who uses Node, writing a package does not require publishing
it to the world. Consolidating your own code into module packages makes
it easy to reuse your work across multiple projects, share it with other
developers, or make it available to staging or production servers
running your application.</p><p>Packages do not have to be limited to modules or extensions; in
many cases, packages contain full applications intended for deployment.
Package files make deployment easy by declaring dependencies,
eliminating the library-labyrinth guesswork that was traditionally
required when moving from development to production environments.</p><p>Creating a package doesn’t require much more work than creating a
<em class="filename">package.json</em> file with some basic
definitions about your module—its name and version number being the most
critical components. To quickly generate a valid package file, run the
command<a id="I_indexterm5_d1e13721" class="indexterm"/> <code class="literal">npm init</code> from your module’s directory.
You will be prompted to enter descriptive information about your module.
Then the command will emit a <em class="filename">packages.json</em> file into the
directory. If a package file already exists, its attributes will be used
as the default values and you will be given a chance to overwrite them
with new information.</p><p>To use your package, install it using <code class="literal">npm
install</code> <em class="replaceable"><code>/path/to/yourpackage</code></em>. The
path may be a directory on your filesystem or an external URL (such as
GitHub).</p></div><div class="sect2" title="Publishing Packages"><div class="titlepage"><div><div><h2 class="title"><a id="id847964"/>Publishing Packages</h2></div></div></div><p>If your module is useful to a <a id="I_indexterm5_d1e13754" class="indexterm"/><a id="I_indexterm5_d1e13759" class="indexterm"/><a id="I_indexterm5_d1e13764" class="indexterm"/>broader audience and ready for prime time, you can release
it to the world using <code class="literal">npm</code>’s
<code class="literal">publish</code> command. To publish the contents of your
package:</p><div class="orderedlist"><ol class="orderedlist"><li class="listitem"><p>Create a user with <a id="I_indexterm5_d1e13780" class="indexterm"/>the <code class="literal">adduser</code> command:</p><a id="I_programlisting5_d1e13789"/><pre class="programlisting">npm adduser</pre><p>Follow the instructions that appear. You will be prompted for
a username, password, and email address.</p></li><li class="listitem"><p>Publish your package with the <code class="literal">publish</code>
command:</p><a id="I_programlisting5_d1e13799"/><pre class="programlisting">npm publish</pre></li></ol></div><p>That’s all there is to the process. At present, no registration or
validation is needed.</p><div class="warning" title="Warning"><h3 class="title">Warning</h3><p>This raises an interesting point about <code class="literal">npm</code>:
because anyone can publish a package without any prefiltering or
oversight, the quality of the libraries you install using
<code class="literal">npm</code> is uncertain. So “buyer beware.”</p></div><p>If you decide later to unpublish your package, you may do so with
<a id="I_indexterm5_d1e13814" class="indexterm"/>the <code class="literal">npm unpublish</code> command. Note that
you will need to clear your package list cache.</p></div><div class="sect2" title="Linking"><div class="titlepage"><div><div><h2 class="title"><a id="id848094"/>Linking</h2></div></div></div><p>Although <code class="literal">npm</code> excels at <a id="I_indexterm5_d1e13831" class="indexterm"/><a id="I_indexterm5_d1e13836" class="indexterm"/>publishing and deploying, it was designed primarily as a
tool for managing dependencies during development. The <code class="literal">npm
link</code> command creates a symbolic link between your project and
its dependencies, so any changes in the dependencies are available to
you as you work on your project.</p><p>There are two major reasons you would want to do this:</p><div class="itemizedlist"><ul class="itemizedlist"><li class="listitem"><p>You want to use <code class="literal">requires()</code>
to access one of your projects from another one of your
projects.</p></li><li class="listitem"><p>You want to use the same package in multiple projects, without
needing to maintain its version in each of your projects.</p></li></ul></div><p>Typing <code class="literal">npm link</code> with no arguments creates a
symbolic link for the current project inside the global packages path,
making it available to <code class="literal">npm</code> in all other projects on
your system. To use this feature, you need to have a <em class="filename">packages.json</em> file, described earlier. Using
<code class="literal">npm init</code> is the fastest way to generate a barebones
version of this file.</p><p>Typing <code class="literal">npm link
<em class="replaceable"><code>packagename</code></em></code> creates a symbolic link
from the project’s working directory to the global modules path for that
package. For example, typing <code class="literal">npm link express</code> will
install the Express framework in the global packages directory and
include it in your project. Whenever Express is updated, your project
will automatically use the latest version from the global packages
directory. If you have linked Express in more than one project, all of
those projects will be synchronized to the most recent version, freeing
you from having to update every one of them whenever Express is
updated.</p></div></div><div class="sect1" title="Add-ons"><div class="titlepage"><div><div><h1 class="title"><a id="I_sect15_d1e13881"/>Add-ons</h1></div></div></div><p>Whereas modules <a id="I_indexterm5_d1e13886" class="indexterm"/>are the JavaScript extensions for Node,
<em class="firstterm">add-ons</em> are the C/C++ extensions. Add-ons
frequently wrap existing system libraries and expose their functionality
to Node. They can, of course, create new functionality too, although most
people choose to do that in JavaScript for obvious reasons. Add-ons are
dynamically linked shared objects.</p><p>To create an add-on, you’ll need at least two sets of files: the
add-on code and the build files. Node uses the <code class="literal">waf</code> build system written in Python. Let’s start
with a “Hello World” example. <a class="xref" href="ch08.html#example8-2" title="Example 8-2. A simple add-on for Node">Example 8-2</a> is equivalent
to <code class="literal">exports.hello = "world";</code> in
JavaScript.</p><div class="example"><a id="example8-2"/><p class="title">Example 8-2. A simple add-on for Node</p><div class="example-contents"><pre class="programlisting">#include <v8.h>
using namespace v8;
extern "C" void init (Handle<Object> target) {
HandleScope scope;
target->Set(String::New("hello"), String::New("world"));
}</pre></div></div><p>The first thing this code needs to do is include the <code class="literal">v8</code> header file because Node is built on top of
V8. This provides a lot of standard objects that we will use. Next, we
declare the namespace. Then we create the <em class="firstterm">wrapper</em>,
which is required by all add-ons. The wrapper functions like the <code class="literal">exports</code> global variable for JavaScript modules.
We’ll hang everything we expose from the add-on off a <a id="I_indexterm5_d1e13919" class="indexterm"/>function with the signature <code class="literal">extern
'C' void init (Handle<Object> target)</code>.</p></div></div></body></html>