-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathguide.html
193 lines (187 loc) · 15.9 KB
/
guide.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
<!DOCTYPE html><html><head><title>normalize.io - an ES6 module, Web Component, and SPDY/HTTP2 Push frontend development worfklow</title><meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no, minimal-ui"><link rel="stylesheet" href="index.css"><link rel="stylesheet" href="https://yandex.st/highlightjs/8.0/styles/github.min.css"></head><body><div id="top-bar"><div class="container"><a id="top-bar-logo" href="./">nlz.io</a><a href="https://github.com/normalize/discussions" class="top-bar-link">discuss</a><a href="faq.html" class="top-bar-link">faq</a><a href="guide.html" class="top-bar-link">guide</a><a href="api.html" class="top-bar-link">api</a></div></div><header><div class="container"><h1>Guide</h1></div></header><main><div id="toc" class="Dropdown right down"><a href="#" class="Dropdown-toggle">#</a><div class="Dropdown-menu"></div></div><section><div class="container"><h2 id="best-practices">General Best Practices</h2><h3 id="don-t-comment-out-dependencies">Don't comment out dependencies</h3>
<p>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:</p>
<pre><code class="lang-js">// <span class="hljs-keyword">import</span> <span class="hljs-string">'x'</span>
// require(<span class="hljs-string">'x'</span>)
/* <span class="hljs-keyword">import</span> <span class="hljs-string">'x'</span> */
</code></pre>
<pre><code class="lang-css">/* <span class="hljs-variable">@import</span> <span class="hljs-string">'test.css'</span>; *<span class="hljs-regexp">/</span>
</code></pre>
<p>The reason it's difficult to strip out comments
is because Normalize supports dependencies of the form:</p>
<pre><code class="lang-js"><span class="hljs-keyword">import</span> <span class="hljs-string">'https://github/component/emitter/*/index.js'</span>;
</code></pre>
<p>And the <code>/*/</code> in the URL confuses a lot of parsers and
makes stripping comments difficult.</p>
<p>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.</p>
</div></section><section><div class="container"><h2 id="authoring-javascript">Authoring JavaScript</h2><h3 id="best-practices">Best Practices</h3>
<h4 id="use-index-js-for-browsers-node-js-for-node-js">Use index.js for browsers, node.js for node.js</h4>
<p>Give browsers filename priority. Specify <code>.main = 'node.js'</code> and <code>.browser = 'index.js'</code> in your <code>package.json</code>s.</p>
<h4 id="don-t-inline-dependencies-with-their-own-dependencies">Don't inline dependencies with their own dependencies</h4>
<p>Specifically, don't do this:</p>
<pre><code class="lang-js"><span class="hljs-reserved">import</span> css from <span class="hljs-string">'style.css'</span>;
<span class="hljs-reserved">var</span> style = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">'style'</span>);
style.innerHTML = css;
<span class="hljs-built_in">document</span>.head.appendChild(style);
</code></pre>
<p>Where <code>style.css</code> is:</p>
<pre><code class="lang-css"><span class="hljs-at_rule">@<span class="hljs-keyword">import</span> <span class="hljs-string">'another-style.css'</span></span>;
</code></pre>
<p>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!</p>
</div></section><section><div class="container"><h2 id="authoring-css">Authoring CSS</h2><h3 id="best-practices">Best Practices</h3>
<h4 id="don-t-do-crazy-imports">Don't do crazy @imports</h4>
<p>Stick with simple <code>@import</code> statements.
<code>@import</code> statements using <code>url()</code>s and media queries are not supported.
Instead of using <code>@import</code>s with media queries,
just use each as separate entry points and use <code><link></code> tags with media queries.</p>
<h4 id="-import-liberally">@import liberally</h4>
<p><code>@import</code>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 <code>@import</code>ed within a CSS file will be included before the the rest of the CSS file's rules.</p>
<h4 id="prepend-relative-urls-with-if-it-contains-a-">Prepend relative URLs with ./ if it contains a <code>@</code></h4>
<p>For example, if you have:</p>
<pre><code class="lang-css"><span class="hljs-attribute">background-image</span>: <span class="hljs-string">url('images/[email protected]')</span>
</code></pre>
<p>Normalize might think that this is a remote dependency.
To avoid this confusion, just prepend it with a <code>./</code>:</p>
<pre><code class="lang-css"><span class="hljs-attribute">background-image</span>: <span class="hljs-string">url('./images/[email protected]')</span>
</code></pre>
</div></section><section><div class="container"><h2 id="authoring-html">Authoring Web Components</h2><h3 id="only-use-web-components-in-a-spdy-environment">Only use web components in a SPDY environment</h3>
<p>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).</p>
</div></section><section><div class="container"><h2 id="bundling">Bundling</h2><p>As shown via <code>nlz build(1)</code>,
you can build multiple entry points, whether <code>.js</code> or <code>.css</code>,
all at the same time.</p>
<pre><code class="lang-bash">nlz build index<span class="hljs-preprocessor">.js</span> something<span class="hljs-preprocessor">.js</span> else<span class="hljs-preprocessor">.js</span>
</code></pre>
<p>However, you probably want a couple of partial bundles,
one for the initial page load and the others for specific pages.</p>
<pre><code class="lang-html"><span class="hljs-tag"><<span class="hljs-title">script</span> <span class="hljs-attribute">src</span>=<span class="hljs-value">"boot.js"</span>></span><span class="javascript"></span><span class="hljs-tag"></<span class="hljs-title">script</span>></span>
<span class="hljs-tag"><<span class="hljs-title">script</span> <span class="hljs-attribute">src</span>=<span class="hljs-value">"homepage.js"</span>></span><span class="javascript"></span><span class="hljs-tag"></<span class="hljs-title">script</span>></span>
</code></pre>
<p>To do is very simple: have <code>boot.js</code> and <code>homepage.js</code> as entry points
and have <code>homepage.js</code> depend on <code>boot.js</code> directly:</p>
<pre><code class="lang-js"><span class="hljs-comment">// homepage.js:</span>
<span class="hljs-keyword">import</span> <span class="hljs-string">'boot'</span>
</code></pre>
<p>Then create a build with both entry points:</p>
<pre><code class="lang-bash">nlz build boot<span class="hljs-preprocessor">.js</span> homepage<span class="hljs-preprocessor">.js</span>
</code></pre>
<p>Now you will have to entry points, <code>boot.js</code> and <code>homepage.js</code>.
<code>boot.js</code> will be required to use <code>homepage.js</code>,
and none of <code>boot.js</code>'s dependencies will be included in <code>homepage.js</code>.</p>
<p>If you want to create a single <code>homepage.js</code> bundle,
just build it independently:</p>
<pre><code class="lang-bash">nlz build homepage<span class="hljs-preprocessor">.js</span>
</code></pre>
<p>Now <code>homepage.js</code> will include all of <code>boot.js</code>.</p>
<p>This will work with JS as well as CSS.</p>
<blockquote>
<p>Notes:</p>
<ul>
<li>Common bundles are not supported.</li>
<li>All entry points must be defined with their all their dependencies defined prior.</li>
</ul>
</blockquote>
</div></section><section><div class="container"><h2 id="authoring-tests">Authoring Tests</h2><p>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.</p>
<h3 id="tests-will-simply-be-another-entry-point">Tests will simply be another entry point</h3>
<p>Currently, tests are run through CLI utilities such as <code>mocha</code> with many options passed:</p>
<pre><code class="lang-bash"><span class="hljs-comment">mocha</span> <span class="hljs-literal">-</span><span class="hljs-literal">-</span><span class="hljs-comment">reporter</span> <span class="hljs-comment">spec</span> <span class="hljs-literal">-</span><span class="hljs-literal">-</span><span class="hljs-comment">require</span> <span class="hljs-comment">should</span> <span class="hljs-literal">-</span><span class="hljs-literal">-</span><span class="hljs-comment">bail</span> <span class="hljs-literal">-</span><span class="hljs-literal">-</span><span class="hljs-comment">timeout</span> <span class="hljs-comment">10s</span> <span class="hljs-comment">test/*</span><span class="hljs-string">.</span><span class="hljs-comment">js</span>
</code></pre>
<p>Instead, Normalized components should have pure JS entry points for tests:</p>
<pre><code class="lang-js">// get mocha and should globally
import <span class="hljs-string">'https://nlz.io/github/visionmedia/mocha/1/index.js'</span>
import <span class="hljs-string">'https://nlz.io/github/visionmedia/should.js/3/index.js'</span>
// set the test options
mocha.setup(<span class="hljs-string">'bdd'</span>)
mocha.bail()
mocha.reporter(<span class="hljs-string">'spec'</span>)
mocha.timeout(<span class="hljs-string">'10s'</span>)
// include tests within this file
import Component from <span class="hljs-string">'index'</span>
describe(<span class="hljs-string">'My Component'</span>, <span class="hljs-keyword">function</span> () {
// <span class="hljs-keyword">...</span> tests
})
// or simply import other tests
import <span class="hljs-string">'test/this'</span>
import <span class="hljs-string">'test/that'</span>
</code></pre>
<p>Locally, in node.js environments, running <code>node test.js</code> should be sufficient.
However, some build process might be necessary, so for the near future, it'll look like:</p>
<pre><code class="lang-bash">nlz build test<span class="hljs-preprocessor">.js</span>
node build/test<span class="hljs-preprocessor">.js</span>
</code></pre>
<h3 id="running-tests-in-browsers">Running tests in browsers</h3>
<p>The above test is only applicable to pure JS modules.
Ideally, we should be able to run tests in browsers,
but browsers require <code>.html</code> documents.
With <code>test.js</code> created above,
users should simply create <code>test.html</code> that references <code>test.js</code>:</p>
<pre><code class="lang-html"><span class="hljs-doctype"><!DOCTYPE html></span>
<span class="hljs-tag"><<span class="hljs-title">html</span>></span>
<span class="hljs-tag"><<span class="hljs-title">head</span>></span>
<span class="hljs-tag"><<span class="hljs-title">title</span>></span>My Component<span class="hljs-tag"></<span class="hljs-title">title</span>></span>
<span class="hljs-tag"><<span class="hljs-title">link</span> <span class="hljs-attribute">rel</span>=<span class="hljs-value">"stylesheet"</span> <span class="hljs-attribute">href</span>=<span class="hljs-value">"https://nlz.io/github/visionmedia/mocha/1/index.css"</span>></span>
<span class="hljs-tag"></<span class="hljs-title">head</span>></span>
<span class="hljs-tag"><<span class="hljs-title">body</span>></span>
<span class="hljs-tag"><<span class="hljs-title">p</span>></span>These are the tests!<span class="hljs-tag"></<span class="hljs-title">p</span>></span>
<span class="hljs-tag"><<span class="hljs-title">div</span> <span class="hljs-attribute">id</span>=<span class="hljs-value">"mocha"</span>></span><span class="hljs-tag"></<span class="hljs-title">div</span>></span>
<span class="hljs-tag"><<span class="hljs-title">script</span> <span class="hljs-attribute">src</span>=<span class="hljs-value">"test.js"</span>></span><span class="javascript"></span><span class="hljs-tag"></<span class="hljs-title">script</span>></span>
<span class="hljs-tag"></<span class="hljs-title">body</span>></span>
<span class="hljs-tag"></<span class="hljs-title">html</span>></span>
</code></pre>
<p>Thus, simply <code>open test.html</code> <strong>should</strong> 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:</p>
<pre><code class="lang-bash">nlz build test<span class="hljs-preprocessor">.html</span>
open build/test<span class="hljs-preprocessor">.html</span>
</code></pre>
</div></section><section><div class="container"><h2 id="troubleshooting">Troubleshooting</h2><h3 id="normalization-logs">Normalization Logs</h3>
<p>The normalization proxy will add logs to two places: <code>normalize-debug.log</code> and each file themselves.</p>
<h4 id="normalize-debug-log">normalize-debug.log</h4>
<p>Each normalized repository will have a <code>normalize-debug.log</code>:</p>
<pre><code><span class="hljs-constant">GET</span> <span class="hljs-symbol">https:</span>/<span class="hljs-regexp">/nlz.io/github</span><span class="hljs-regexp">/components/jquery</span><span class="hljs-regexp">/2.1.0/normalize</span>-debug.log
</code></pre><p>This file will contain logs that pertain to the entire repository as a whole.</p>
<h4 id="per-file-logs">Per-file logs</h4>
<p>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.</p>
<h3 id="debug">Debug</h3>
<p>Whether you're using <code>nlz(1)</code> or run your own proxy,
you can set the <code>DEBUG</code> environmental variable to view the logs.
See <a href="https://github.com/visionmedia/debug">visionmedia/debug</a> for more usage info.
In particular,
you want to do one of the following:</p>
<pre><code class="lang-bash">DEBUG=<span class="hljs-built_in">normalize</span>*
DEBUG=<span class="hljs-built_in">normalize</span>-proxy*
</code></pre>
<h3 id="common-errors">Common Errors</h3>
<h4 id="emfile-errors">EMFILE Errors</h4>
<p>Normalize does <strong>not</strong> 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.</p>
<p>Concurrency control is complex and unnecessary for build systems that don't require concurrency.
If you're hitting <code>EMFILE</code> errors,
then all you have to do is set your <code>ulimit</code> higher:</p>
<pre><code class="lang-bash">ulimit <span class="hljs-attribute">-n</span> <span class="hljs-number">10000</span>
</code></pre>
<p>There's no reason you should have low limits in development.</p>
</div></section></main><footer><div class="container"><div id="footer-badges"><script data-gittip-username="jonathanong" src="https://gttp.co/v1.js" async></script></div><ul id="footer-links"><li>Jonathan Ong © 2014</li><li><a href="http://jongleberry.com">jongleberry.com</a></li><li><a href="https://github.com/jonathanong">@jonathanong</a></li><li><a href="https://twitter.com/jongleberry">@jongleberry</a></li><li><a href="mailto:[email protected]">[email protected]</a></li></ul></div></footer><script>(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-7367759-13', 'normalize.github.io');
ga('send', 'pageview');
</script><script src="http://yandex.st/highlightjs/8.0/highlight.min.js"></script><script src="index.js"></script></body></html>