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.json
s.
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 @import
s with media queries,
just use each as separate entry points and use <link>
tags with media queries.
@import liberally
@import
ing 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 @import
ed 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.