discussfaqguideapi

Guide

General Best Practices

Don't comment out dependencies

Currently, for speed, Normalize uses regular expressions to find all the dependencies of a CSS or JS file. The problem with this is that it will still catch any dependencies within comments, which can't easily be removed with regexps. For example, these dependencies will all be captured:

// import 'x'
// require('x')
/* import 'x' */
/* @import 'test.css'; */

The reason it's difficult to strip out comments is because Normalize supports dependencies of the form:

import 'https://github/component/emitter/*/index.js';

And the /*/ in the URL confuses a lot of parsers and makes stripping comments difficult.

The solution is to actually parse the AST for dependencies, which may be added in the future as long as performance is not too degraded.

Authoring JavaScript

Best Practices

Use index.js for browsers, node.js for node.js

Give browsers filename priority. Specify .main = 'node.js' and .browser = 'index.js' in your package.jsons.

Don't inline dependencies with their own dependencies

Specifically, don't do this:

import css from 'style.css';

var style = document.createElement('style');
style.innerHTML = css;
document.head.appendChild(style);

Where style.css is:

@import 'another-style.css';

This is relevant with all dependency types, including HTML and CSS. Normalize currently does not handle rewriting these URLs, mostly because it doesn't know how to change the dependency after it's already been converted to JS. If you have suggestions on how to solve this, please let us know!

Authoring CSS

Best Practices

Don't do crazy @imports

Stick with simple @import statements. @import statements using url()s and media queries are not supported. Instead of using @imports with media queries, just use each as separate entry points and use <link> tags with media queries.

@import liberally

@importing the same CSS file multiple does not include it multiple in the build, nor does it create multiple HTTP requests. What it does do, however, is guarantee ordering. All CSS files @imported within a CSS file will be included before the the rest of the CSS file's rules.

Prepend relative URLs with ./ if it contains a @

For example, if you have:

background-image: url('images/logo@2x.png')

Normalize might think that this is a remote dependency. To avoid this confusion, just prepend it with a ./:

background-image: url('./images/logo@2x.png')

Authoring Web Components

Only use web components in a SPDY environment

Normalize does not support creating bundles with web components. Doing so in an unopinionated manner is very difficult. Instead, you should only use web components with a SPDY push server (or allow your users to suffer the latency).

Bundling

As shown via nlz build(1), you can build multiple entry points, whether .js or .css, all at the same time.

nlz build index.js something.js else.js

However, you probably want a couple of partial bundles, one for the initial page load and the others for specific pages.

<script src="boot.js"></script>
<script src="homepage.js"></script>

To do is very simple: have boot.js and homepage.js as entry points and have homepage.js depend on boot.js directly:

// homepage.js:
import 'boot'

Then create a build with both entry points:

nlz build boot.js homepage.js

Now you will have to entry points, boot.js and homepage.js. boot.js will be required to use homepage.js, and none of boot.js's dependencies will be included in homepage.js.

If you want to create a single homepage.js bundle, just build it independently:

nlz build homepage.js

Now homepage.js will include all of boot.js.

This will work with JS as well as CSS.

Notes:

  • Common bundles are not supported.
  • All entry points must be defined with their all their dependencies defined prior.

Authoring Tests

One of the goals of Normalize is to make testing easier. Currently, a lot of CLI tools and integrations with various services are required to test web components well.

Tests will simply be another entry point

Currently, tests are run through CLI utilities such as mocha with many options passed:

mocha --reporter spec --require should --bail --timeout 10s test/*.js

Instead, Normalized components should have pure JS entry points for tests:

// get mocha and should globally
import 'https://nlz.io/github/visionmedia/mocha/1/index.js'
import 'https://nlz.io/github/visionmedia/should.js/3/index.js'

// set the test options
mocha.setup('bdd')
mocha.bail()
mocha.reporter('spec')
mocha.timeout('10s')

// include tests within this file
import Component from 'index'

describe('My Component', function () {
  // ... tests
})

// or simply import other tests
import 'test/this'
import 'test/that'

Locally, in node.js environments, running node test.js should be sufficient. However, some build process might be necessary, so for the near future, it'll look like:

nlz build test.js
node build/test.js

Running tests in browsers

The above test is only applicable to pure JS modules. Ideally, we should be able to run tests in browsers, but browsers require .html documents. With test.js created above, users should simply create test.html that references test.js:

<!DOCTYPE html>
<html>
  <head>
    <title>My Component</title>
    <link rel="stylesheet" href="https://nlz.io/github/visionmedia/mocha/1/index.css">
  </head>
  <body>
    <p>These are the tests!</p>
    <div id="mocha"></div>
    <script src="test.js"></script>
  </body>
</html>

Thus, simply open test.html should run the tests, eventually. Your test may include additional files such as custom CSS. For now, we're going to need a build process to run the tests locally:

nlz build test.html
open build/test.html

Troubleshooting

Normalization Logs

The normalization proxy will add logs to two places: normalize-debug.log and each file themselves.

normalize-debug.log

Each normalized repository will have a normalize-debug.log:

GET https://nlz.io/github/components/jquery/2.1.0/normalize-debug.log

This file will contain logs that pertain to the entire repository as a whole.

Per-file logs

Each file served from the proxy will include its own logs appended to the bottom of the file. You can view these comments to see what the proxy did to the file.

Debug

Whether you're using nlz(1) or run your own proxy, you can set the DEBUG environmental variable to view the logs. See visionmedia/debug for more usage info. In particular, you want to do one of the following:

DEBUG=normalize*
DEBUG=normalize-proxy*

Common Errors

EMFILE Errors

Normalize does not have any concurrency control. It executes everything as fast as possible in parallel. What this means is that you could have a lot of file descriptors open at the same time.

Concurrency control is complex and unnecessary for build systems that don't require concurrency. If you're hitting EMFILE errors, then all you have to do is set your ulimit higher:

ulimit -n 10000

There's no reason you should have low limits in development.