npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

isomorphic-express-boilerplate

v1.2.3

Published

A boilerplate Node.js / Express app

Downloads

8

Readme

The Isomorphic Express Boilerplate

A node app that says, "Hello, world!"

This is an isomorphic Node application boilerplate using Express 4.x.

Learn JavaScript with Eric Elliott

The Isomorphic Express Boilerplate was written for the "Learn JavaScript with Eric Elliott" courses. A series of courses to teach people how to build great JavaScript apps for production. Don't just learn JavaScript. Learn how to build amazing things.

Isomorphic JavaScript

Isomorphic means that it's designed to run a lot of the same code on both the client and the server. Typically that includes a lot of rendering and domain logic. (Not to be confused with isomorphisms from category theory / functional programming. That's a totally different thing.)

There are many advantages to building apps this way, but the primary advantages are:

  • Cross-functional teams. Since everything is written in JavaScript, it's easier to build teams who know how to work on both the client and server sides of the app.
  • Write once, run everywhere. With the exception of a few library substitutions and browser polyfills, the code is shared, which means you have to write about half the code you'd write working on a non-isomorphic app.
  • More productive developers. Since the app is more consistent across the stack, there's no context switching when you need to maintain application behavior on both sides of the stack. Write the behavior once, and you're done. Context switching slows developers down significantly.

Tech stack

Take a look at the Roadmap for an idea of where this is going. Help is welcome and encouraged! =)

Current status

This is already very valuable as-is. Read on for details.

The isomorphic boilerplate use standard Node modules to author all of the code. All open-source modules are sourced from npm.

Why not use Bower and AMD? Lots of reasons:

  • npm has 5x more modules than Bower, 60% of which are browser compatible, and npm is growing faster than Bower. In fact, npm is the largest package repository available for any programming language.
  • Browserify lets you bundle Node style modules for the browser. It handles dependencies in a way that is compatible with the way that Node does.
  • Typical Node applications are not written using AMD modules or Bower, so sharing code becomes more complicated when you author with AMD.
  • Bower modules frequently assume they're running in a browser environment and do things that don't make any sense in the server environment.
  • Typical AMD apps default to asynchronously loading all the modules. That's bad for performance. See below.
  • 2010 called. They want you to know that AMD was always intended to be a temporary hack until something better came along. Something better has come along. Welcome to the Isomorphic future. ;)

The problem with AMDs async loading default

Asynchronously loading all your modules by default is really bad for application start up performance because all those requests create latency queues which can be really painful on mobile devices. HTTP2 / SPDY are changing that in modern browsers, but people often use their mobile devices for years without upgrading the browsers on them. I recommend bundling all your commonly used behavior (including templates and CSS) into a single, compressed JavaScript file in order to minimize request latency.

I know that AMD supports bundling with tools like r.js, but many apps start out without bundling and never bother to fix it later. I've personally been on three different app projects where bundling was postponed for a year or more, all the while making customers wait. I knew this was bad, and I tried to get it fixed, but on a large enterprise app project, getting something like that changed mid-project takes klout, political maneuvering, and buy-in from teams who may never have met you and could be wondering why you're creating work for them when they're already behind schedule.

In my experience, every team is always behind schedule if you ask them to do work they weren't planning well ahead of time. ;)

What's inside?

There are some concerns that legitimately belong only on the server, or only on the client, so there are client/ and server/ directories for code that is specific to one or the other. Shared code goes in lib/:

  • app/node_modules/lib - Shared code.
  • app/node_modules/client - For browser-only code.
  • app/node_modules/server - For server-only code.
.
├── LICENSE
├── README.md
├── app
│   ├── index.js
│   ├── node_modules
│   │   ├── client
│   │   │   └── index.js
│   │   ├── lib
│   │   │   └── app.js
│   │   ├── public
│   │   │   ├── index.html
│   │   │   └── js
│   │   │       └── vendor
│   │   │           └── html5shiv.js
│   │   └── server
│   │       └── index.js
│   └── test
│       ├── functional
│       │   ├── acceptance
│       │   │   └── index.js
│       │   ├── index.js
│       │   └── smoke
│       │       └── index.js
│       └── unit
│           ├── client
│           │   └── index.js
│           ├── index.js
│           └── server
│               └── index.js
├── config
│   └── BUILD
├── node_modules
└── package.json

Index

The index route / serves index.html from the public folder using express.static. The index file is a slightly modified version of the HTML5 Boilerplate trusted by Google, Microsoft, NASA, Nike, Barack Obama, etc... To customize it or create your own, visit Initializr.com.

Scripts

Some of these scripts may require a Unix/Linux environment. OS X and Linux come with appropriate terminals ready to roll. On Windows, you'll need git installed, which comes with Git Bash. That should work. If you have any trouble, please report the issue.

The package.json file comes with the following scripts that you may find useful:

  "scripts": {
    "start": "node index.js",
    "debug": "node --debug index.js",
    "inspect": "node-inspector",
    "test": "node test/unit/index.js | faucet",
    "lint": "jshint .",
    "build": "mkdir -p config && git rev-parse --short HEAD > config/BUILD",
    "watch:build": "watch --wait=5 'npm run lint && npm run build && npm run test' .",
    "dev": "npm run watch:build"
  }

To run a script, open the terminal, navigate to the boilerplate directory, and type:

npm run <name of script>

Start

Start the app.

npm run start

start and test support this shortcut, to save a few keystrokes:

npm start

Log messages will be written to the console (stdout) in JSON format for convenient queries using tools like Splunk. You should be able to pipe the output to a third party logging service for aggregation without including that log aggregation logic in the app itself.

Developer feedback console:

npm run dev

The dev console does the following:

  • Checks for syntax errors with jslint using idiomatic settings from .jshintrc
  • Runs a build script which (for now) simply writes the current git commit hash to a file called config/BUILD. In a later version, this will also bundle the browser JavaScript.
  • Runs the unit tests and reports any test failures.
  • Watches for file changes and re-runs the whole process.

Requiring modules

To require modules relative to the app root, just put them in app/node_modules and require them just like you would require a module installed by npm. For example, if you had a file called app/node_modules/lib/routes.js you can require it with:

var routes = require('lib/routes`);

The reason this works is because Node will traverse the parent directories until it finds the node_modules directory and use that as the base path for requires. See the full explanation on StackOverflow.

This boilerplate also has rootrequire, a very simple module that just exports a string containing your project's root path, so you can require files without a bunch of relative strings. You can use rootrequire if you need to get at files in the root directory, such as package.json.

Before:

var
  a = require('../../../lib/a'),
  b = require('../../../lib/b'),
  c = require('../../../lib/c');

After:

var
  root = require('rootrequire'),
  a = require(root + '/lib/a'),
  b = require(root + '/lib/b'),
  c = require(root + '/lib/c'),

Why?

  • You can move things around more easily.
  • Every file documents your app's directory structure for you. You'll know exactly where to look for things.
  • Dazzle your coworkers.

If you find yourself using the same file in a lot of modules, it's probably a better idea to split it out into its own module -- preferably open source. Then you can just install it like any other module so it can live in node_modules.

Recap

  • node_modules for modules installed by npm. That way you won't have to put up with a bunch of vendor noise in version control and pull requests. Just add node_modules to your .gitignore file (like it is in this repo).
  • app/node_modules for your application-level code that doesn't belong in npm. This should contain all your business logic and application secret-sauce. You DO want this in version control. See .gitignore to learn how to configure it.
  • rootrequire to get at stuff relative to the project root folder. You should only need to use this very rarely -- for example, to easily require package.json.