-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.html
630 lines (534 loc) · 18.7 KB
/
index.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
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
<html>
<head>
<title>Bolt JavaScript Framework</title>
<link rel="stylesheet" href="style.css" type="text/css"/>
</head>
<body>
<h1><a href="index.html">bolt</a></h1>
<div id="content">
<h2>Getting Started</h2>
<p>
Bolt is a module-based JavaScript framework, inspired by, but at this point (intentionally)
not fully compatible with the <a href="https://github.com/amdjs/amdjs-api/wiki/AMD">AMD specification</a>.
Bolt consists of a runtime framework, compiler and testing tool for JavaScript modules.
</p>
<p>
There are a few things that need to be understood to take full advantage of bolt
modules:
<ul>
<li>Getting Bolt</li>
<li>Modules</li>
<li>Project Structure</li>
<li>Configuration</li>
<li>Runtime</li>
<li>Compilation</li>
<li>Testing</li>
</ul>
</p>
<h2>Getting Bolt</h2>
<h4>
From `npm`:
</h4>
<pre>
npm install -g boltjs
</pre>
<p>
You can test the bolt command by using <code>bolt --version</code>
</p>
<h4>
From distribution:
</h4>
<p>
Grab the latest release tar from <a href="http://dist.boltjs.io/1.4.1.1/bolt-1.4.1.1.tar.gz">http://dist.boltjs.io/1.4.1.1/bolt-1.4.1.1.tar.gz</a>. And install node.js v0.8+ from
<a href="http://nodejs.org/#download">http://nodejs.org/</a> or your package manager.
</p>
<p>
Unpack the tar, and put bolt on the path. For example:
</p>
<pre>
cd install-dir
curl http://dist.boltjs.io/1.4.1.1/bolt-1.4.1.1.tar.gz | tar xfz -
sudo ln -s `pwd`/bolt-*/bin/bolt /usr/local/bin/bolt
</pre>
<p>
You can test the bolt command by using <code>bolt --version</code>
</p>
<h4>
Access directly:
</h4>
<ul>
<li>Runtime: <a href="http://dist.boltjs.io/1.4.1.1/bolt.js">http://dist.boltjs.io/1.4.1.1/bolt.js</a></li>
<li>Karma test integration: <a href="http://dist.boltjs.io/1.4.1.1/bolt-karma.js">http://dist.boltjs.io/1.4.1.1/bolt-karma.js</a></li>
</ul>
<h2>Modules</h2>
<h3>Concepts</h3>
<p>
The central component of a bolt project is the module.
</p>
<p>
A module is essentially a named, self-contained unit of JavaScript
code, with a specified API, that may or may not depend on other
modules in order to accomplish its purpose.
</p>
<p>
Modules are created by calling the <code>define</code> function.
Define has the following signature:
</p>
<code>define(name, dependencies, definitionFunction);</code>
<p>For example, a typical bolt module definition in a project might look like:</p>
<pre>
define(
'example.bolt.Module', // Module name (including namespace)
[
'example.bolt.AnotherModule', // Dependencies on other modules
'example.bolt.DifferentModule'
],
function (AnotherModule, DifferentModule) { // Definition function - passed dependencies in order
// Private state
var hello = function () {
alert('Hello, world!');
};
// Public API (exposed to other modules)
return {
hello: hello
};
}
);
</pre>
<p>
By convention, this module would live in the file
<code>example/bolt/Module.js</code>, somewhere in the source directory
of a project.
</p>
<h4>Naming</h4>
<p>
The first parameter to <code>define</code> is the namespaced module name
of the newly defined module.
</p>
<p>
Bolt module names are capitalised, and follow a namespacing convention
of lower-case, dot-separated segments, for example:
</p>
<code>example.bolt.Module</code>
<p>
In this case, the <code>Module</code> module is in the
<code>example.bolt</code> namespace.
</p>
<p>
Modules are named primarily so they can be depended upon by other modules,
but also so that they can be conveniently grouped for loading from different
sources, as we will see later in the section on Configuration.
</p>
<h4>Dependencies</h4>
<p>
Dependencies are specified as an array of strings of module names that a
given module needs to use in order to carry out its tasks. For example:
</p>
<pre>
[
'example.bolt.AnotherModule',
'example.bolt.DifferentModule'
]
</pre>
<p>
The dependency array is the second parameter to <code>define</code>, and
may be an empty array if a module doesn't have any dependencies.
</p>
<p>
In bolt, circular module dependencies are not allowed, for example if module
<code>example.bolt.A</code> depends on <code>example.bolt.B</code>, which
then depends on <code>example.bolt.A</code> again.
</p>
<p>
The bolt runtime will throw an exception if this situation is encountered
whilst initialising a project. Note that circular dependency chains can be
quite long and non-obvious in some cases, however bolt will list what the
circular dependency is when it complains.
</p>
<h4>Definition Function</h4>
<p>
The definition function is responsible for initialising the module, setting
up any static resources it might have, and for returning a value that will
be made available to other modules that depend on in it.
</p>
<p>
The definition function is the third and final parameter to
<code>define</code>.
</p>
<p>
The function must return a value, but it need not be an object - although
typically it is, containing a set of methods that represent the module's
public API. For example:
</p>
<pre>
function (...) {
// ...
return {
api1: api1,
api2: api2
};
}
</pre>
<p>
Another common value that is returned by the definition function is another
function. This is often the case when the module is used to manufacture
instances - the returned function is treated like a constructor by modules
that depend upon it.
</p>
<p>
The definition function is passed the values exported by modules specified in the
list of dependencies, in the order that they appear in the list. For example,
given the following dependencies:
</p>
<pre>
[
'example.bolt.AnotherModule',
'example.bolt.DifferentModule'
]
</pre>
<p>
the definition function would appear as follows:
</p>
<pre>
function (AnotherModule, DifferentModule) {
// ...
}
</pre>
<p>
By convention, the names given to the arguments of the definition function
are the same as the dependency module names (minus the namespace), however
these argument names are arbitrary and scoped to the definition function,
so they can be easily changed to something else to e.g. resolve name clashes
between modules in different namespaces with the same name.
</p>
<!-- TODO -->
<!-- <h3>Requiring Modules</h3>
<h3>Main Modules</h3>
<h3>Demanding Modules</h3>
-->
<h2>Project Structure</h2>
<p>
Bolt does not depend on any specific project structure, but does have a few defaults.
All defaults can be easily overridden on the command line. The following outlines
a basic project structure that works well for bolt based projects.
</p>
<pre>
config
|-- bolt
| |-- bootstrap-demo.js
| |-- bootstrap-prod.js
| |-- demo.js
| `-- prod.js
|
demo
|-- html
| ` demo.html
|-- js
| `-- example
| `--bolt
| `--demo
| `-- Demo.js
|
src
|-- js
| `-- example
| `-- bolt
| |-- Module.js
| |-- AnotherModule.js
| `-- DifferentModule.js
test
`-- js
|-- ModuleTest.js
|-- AnotherModuleTest.js
`-- DifferentModuleTest.js
</pre>
<p>
The <code>config/bolt/prod.js</code> (default by convention but can be specified on command line), file is the production configuration.
</p>
<pre>
configure({
sources: [
source('bolt', 'example.bolt', '../../src/js', mapper.hierarchical),
]
});
</pre>
<p>
The <code>config/bolt/demo.js</code> file is the demo configuration. In
this case it just delegates to the production configuration, but in a
more complex scenario would include its own sources.
</p>
<pre>
configure({
configs: [
'prod.js'
]
});
</pre>
<p>
The <code>bootstrap-*.js</code> files are generated by the <code>bolt init</code>
command. These files are referenced by your html to initialise bolt. Bolt's
runtime API can then be used to load your modules.
</p>
<p>
The demo help shows what the client code would contain to reference bolt
code.
</p>
<pre>
<html>
<head>
<script type="text/javascript" src="../../config/bolt/bootstrap-demo.js"></script>
<script type="text/javascript">
ephox.bolt.module.api.main('example.bolt.Module');
</script>
</head>
<body>
</body>
</html>
</pre>
<h2>Configuration</h2>
<p>
Bolt relies on a configuration file that defines what types of
files can be loaded, where they are loaded from and potentially
other configurations where this information can be found. The
configuration is used for both runtime loading of modules and
the compilation of modules.
</p>
<h3>Concepts</h4>
<dl>
<dt>configs</dt>
<dd>
configs are other javascript files that are used to
configure bolt, a configuration file consists of a
single <code>configure</code> call that takes an object with
three optional keys, <code>configs</code>,
<code>types</code> and <code>sources</code>.
</dd>
<dt>types</dt>
<dd>
component types that are understood by bolt - these component
types are able to be loaded and compiled by bolt.
</dd>
<dt>sources</dt>
<dd>
sources specify where to load resources from. Each source
consists of a type and then a set of configuration parameters that
indicate what modules can be loaded from this source and
where to load them from.
</dd>
</dl>
<h3>Api</h3>
<dl>
<dt><code>configure({ configs: [ path ], types: [ type ], sources: [ source ] });</code></dt>
<dd>
<p>
A single configure call should be the only thing made in a
configuration file.
</p>
<p>
<code>configs</code> are an array of strings which specify
the path to another configuration file. Configurations are
read pre-order, so sources and types specified take
precedence over those read from the imported
configs. Relative paths are defined relative to the file
they are declared in.
</p>
<p>
<code>types</code> are an array of objects created by calls
to the type function specified below.
</p>
<p>
<code>sources</code> are an array of objects created by
calls to the source function specified below.
</p>
</dd>
<dt><code>type(type, package);</code></dt>
<dd>
<p>
The type registers with bolt a module type to be
loaded. The <code>bolt</code> type is always implicitly
loaded but a common example is the <code>js</code> type,
which registers a custom type for loading raw javascript
files as bolt modules.
</p>
<pre>type('js', 'ephox.modulator.js')</pre>
<p>
The implementation package specifies the base package for a
type. It is expected to contain two
modules <code><package>.Modulator</code>, which is used
for runtime loading of the custom module type;
and <code><package>.Compiler</code>, which is used for
compilation of the custom module type.
</p>
</dd>
<dt>source(type, arguments ...)</dt>
<dd>
<p>
The source function takes the type as a string as its first
argument and then a variable number of arguments that are
passed to the source types implementation. The exact
argument formulation is dependent on the type argument.
</p>
<p>
For the base bolt type, this is of the form:
</p>
<p><code>source('bolt', namespace, path, mapper)</code></p>
<p>
The <code>namespace</code> argument specifies the namespace
prefix that is being configured by this source, i.e. only
modules matching this prefix will match this source.
</p>
<p>
The <code>path</code> specifies the path (excluding the
mapped module name) to where the modules should be loaded
from. Relative paths are defined relative to the file they
are declared in.
</p>
<p>
The <code>mapper</code> specifies a function that takes a
module name and converts it to a file path (exclude the
'.js') extension. This is normally in the form of one of the
convenience mappers described below.
</p>
</dd>
<dt>mapper.hierarchical</dt>
<dd>
<p>
A convenience function that specifies a function that takes
a module name and converts it to a directory structure. For
example, the module <code>example.bolt.Module</code> would
be come the path <code>example/bolt/Module</code>. This is
how modules are commonly layed out in source control.
</p>
</dd>
<dt>mapper.flat</dt>
<dd>
<p>
A convenience function that specifies a function that takes
a module name and converts it to a file name. This is
effectively an identity function. For example, the
module <code>example.bolt.Module</code> would be come the
path <code>example.bolt.Module</code>. The bolt compiler's
-m flag outputs modules in this structure.
</p>
</dd>
<dt>mapper.constant(path)</dt>
<dd>
<p>
A convenience function that is used to construct a function
that always returns a constant path. For example, a call
to <code>mapper.constant('example/bolt')</code>, would
convert any module name to the
path <code>example/bolt</code>. This is useful for
referencing a compiled file where a number of modules are
contained in a single file.
</p>
</dd>
</dl>
<h2>Runtime</h2>
<p>
In development mode the system is designed to be run behind a
web server that is serving up the source tree of your
project. For pure javascript projects this is normally achieved
by just serving up the source with apache or nginx. For more
complex projects it would involve configuring whatever
application server or framework is involved to serve up the
module and config source files.
</p>
<p>
Bolt generates a bootstrap file that will read a configuration
and then dynamically load modules as required. This allows for
a quick save-refresh development cycle without the need for
compilation. Assuming the basic project structure outlined
above, a call to bolt will generate the bootstrap files for
your configuration:
</p>
<pre>bolt init</pre>
<p>
Note that this process only needs to happen once.
Configuration is read dynamically so the bootstrap does
not need to be rebuilt for each change. The default
configuration can be overridden with the -c or --config flag.
</p>
<p>
Any html that needs access to javascript modules references
the bootstrap file:
</p>
<pre>
<script type="text/javascript" src="../../config/bolt/bootstrap-demo.js"></script>
</pre>
<p>and can then call the bolt runtime api to
load modules. In most cases it is sufficient to directly invoke
a main module:
</p>
<pre>
<script type="text/javascript">
ephox.bolt.module.api.main('example.bolt.Module');
</script>
</pre>
<h2>Compilation</h2>
<p>
For production, bolt will compile all modules into a single file and generate
a bootstrap with an inline configuration to minimise server requests.
</p>
<p>
There are a number of ways that you may want to arrange your javascript depending
on if you are generating a library, building a single-page application or a multi-page
application. The best way to demonstrate this is with a series of examples. All examples
use the directory gen as their output location.
</p>
<p>
Produce a bolt build for a multi-page application. A compiled file will be
generated for each Main module in this example.
</p>
<pre>bolt build -o gen -e src/js/**/*Main.js</pre>
<p>
Produce a bolt build for a library. A self contained script registering
all modules in their namespace will be produced. This compiles in a minimal
kernel so that your library does not have a dependency on bolt.
</p>
<pre>bolt build -o gen -i -g src/js/**/api/*.js</pre>
<p>
Produce a bolt build for a library to be consumed by other bolt projects, in
this build we only want modules to be converted to a convenient form, no compiled
output is produced.
</p>
<pre>bolt build -o gen -m src/js</pre>
<p>
These options can be used together for more complex scenarios. See <code>bolt help build</code>
for more detail.
</p>
<p>
Note that the examples assume use of a shell with "**" glob support. This means either zsh or
bash 4.x with `shopt -s globstar` set. If you are a mac user with a
default bash 3.x, bolt strongly recommends you upgrade to a nicer shell, however you can
use something like $(find src/js -name \*.js) to simulate glob support.
</p>
<h2>Testing</h2>
<p>
Bolt comes with testing support. Tests are defined by a <code>test</code> function
similar in style to a <code>define</code> call. An example test:
</p>
<pre>
test(
'This is the test name',
[
'example.bolt.AnotherModule'
],
function (AnotherModule) {
var actual = AnotherModule.five();
assert.equal(5, actual);
}
);
</pre>
<p>
This is using the assert module available on node, see <a href="http://nodejs.org/docs/latest/api/assert.html">http://nodejs.org/docs/latest/api/assert.html</a> for more detail.
</p>
<p>
To run tests you specify a config that knows how to load any
modules required by the tests. For the example project structure
the production configuration is sufficient. To run the tests:
</p>
<pre>bolt test config/bolt/prod.js test/js/*.js</pre>
</div>
</body>
</html>