@cilix/lightjs 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (5) hide show
  1. package/README.md +1010 -0
  2. package/cli.js +163 -0
  3. package/core.js +2730 -0
  4. package/index.js +364 -0
  5. package/package.json +26 -0
package/README.md ADDED
@@ -0,0 +1,1010 @@
1
+ # Light.js
2
+ ### A new kind of JavaScript framework
3
+
4
+ ## What is this?
5
+
6
+ Light.js is a JavaScript framework in the form of a compiler. Unlike other compiler-oriented JavaScript frameworks, however, Light is used like a proper compiler. It takes .light files, which look like this:
7
+
8
+ ```javascript
9
+ html [
10
+ head []
11
+ body [
12
+ h1 [ 'Welcome' ]
13
+ ]
14
+ ]
15
+ ```
16
+ And compiles them into a single HTML file like this:
17
+ ```html
18
+ <doctype html>
19
+ <html>
20
+ <head></head>
21
+ <body>
22
+ <h1>Hello</html>
23
+ </body>
24
+ </html>
25
+ ```
26
+ Using this command:
27
+ ```bash
28
+ light index.light -o index.html
29
+ ```
30
+ Or you can use the compiler programatically:
31
+ ```javascript
32
+ import { light } from 'lightjs';
33
+
34
+ const html = await light.compile({
35
+ input: 'index.light'
36
+ });
37
+ ```
38
+ Light.js has components. Here is a counter in Light:
39
+ ```javascript
40
+ tag Counter [
41
+ let count = 0
42
+
43
+ button on:click='count++' [ 'increment' ]
44
+ div [ 'current count: {{count}}' ]
45
+ ]
46
+
47
+ html [
48
+ head []
49
+ body [
50
+ Counter[]
51
+ ]
52
+ ]
53
+ ```
54
+ Light.js is **alpha** software. This documentation is a work in progress, but it is comprehensive, and can be given directly to LLMs.
55
+
56
+ ## Table of Contents
57
+
58
+ - [Quick Start](#quick-start)
59
+ - [Syntax](#syntax)
60
+ - [Document](#document)
61
+ - [Data](#data)
62
+ - [Control Flow](#control-flow)
63
+ - [Components](#components)
64
+ - [Javascript](#javascript)
65
+ - [Usage](#usage)
66
+
67
+ ## Quick Start
68
+
69
+ Create a project boilerplate using Light.js's built-in backend router:
70
+
71
+ ```bash
72
+ npx lightjs create my-app
73
+ ```
74
+
75
+ Light.js is extremely flexible and can be used with any backend. Use the following command to create the same boilerplate but using Express instead:
76
+
77
+ ```bash
78
+ npx lightjs create my-app --express
79
+ ```
80
+
81
+ And for the smallest possible boilerplate, use this command:
82
+
83
+ ```bash
84
+ npx lightjs create my-app --lean
85
+ ```
86
+
87
+ ## Syntax
88
+
89
+ Light.js syntax is extremely terse but it is **not** whitespace sensitive. It's a much less shift-y version of HTML. You simply drop the angle brackets, and put children between square brackets. Tags without children as well as void tags are ended with an empty set of square brackets.
90
+
91
+ ```javascript
92
+ form method='POST' action='/user' [
93
+ input name='first' []
94
+ input name='last' []
95
+ input type='submit' value='submit' []
96
+ ]
97
+ ```
98
+
99
+ Textnodes go inside strings.
100
+
101
+ ```javascript
102
+ a href='/' [ 'home' ]
103
+ ```
104
+
105
+ If a textnode is the only child, the brackets may be omitted.
106
+
107
+ ```javascript
108
+ a href='/' 'home'
109
+ ```
110
+
111
+ Remember, there is no whitespace sensitivity, so the following is equally valid.
112
+
113
+ ```javascript
114
+ a href='/'
115
+ 'home'
116
+ ```
117
+
118
+ Light.js supports class shorthand, as seen in other templating languages.
119
+
120
+ ```javascript
121
+ a.btn href='/' 'home'
122
+ ```
123
+
124
+ Of course, you can use the regular class attribute.
125
+
126
+ ```javascript
127
+ a class='btn' href='/' 'home'
128
+ ```
129
+
130
+ Light.js supports double-quoted string, single-quoted strings, and backtick strings. All strings may have interpolations.
131
+
132
+ ```javascript
133
+ html [
134
+ head []
135
+ body [
136
+ p `
137
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed nec fermentum arcu.
138
+ Aliquam vel ullamcorper ipsum. Nullam euismod nisl vel a tristique odio luctus.
139
+ Integer dapibus nec odio at lacinia. Pellentesque euismod id odio nec hendrerit.
140
+ `
141
+ ]
142
+ ]
143
+ ```
144
+
145
+ Backtick strings give you total whitespace control when using them with whitespace sensitive tags like code or pre:
146
+
147
+ ```javascript
148
+ html [
149
+ head []
150
+ body [
151
+ code `
152
+ const foo = require('foo')
153
+
154
+ foo()
155
+ `
156
+ ]
157
+ ]
158
+ ```
159
+
160
+ This prints the following block:
161
+
162
+ ```
163
+ const foo = require('foo')
164
+
165
+ foo()
166
+ ```
167
+
168
+ What's happening here is that the first line is being ignored because it contains only a newline. And the second backtick, the one on the bottom, is controlling how much whitespace is to the left of the code. Look at the next example where the bottom backtick is moved over two spaces:
169
+
170
+ ```javascript
171
+ html [
172
+ head []
173
+ body [
174
+ code `
175
+ const foo = require('foo')
176
+
177
+ foo()
178
+ `
179
+ ]
180
+ ]
181
+ ```
182
+
183
+ This produces the following block:
184
+
185
+ ```
186
+ const foo = require('foo')
187
+
188
+ foo()
189
+ ```
190
+
191
+ ## Document
192
+
193
+ A Light.js document is complete and doesn't require some sort HTML bootloader file. The following is a complete program.
194
+
195
+ ```javascript
196
+ html [
197
+ head []
198
+ body [
199
+ h1 "Hello from Light.js"
200
+ ]
201
+ ]
202
+ ```
203
+
204
+ ## Data
205
+
206
+ What follows is not Javascript. It is purely static Light.js data declaration. This is one of the key differences between Light.js and the rest. Light.js's opinion is that the document data, (what React calls "state"), belongs to the markup, and not the Javascript. Light.js sees Javascript as an extension that allows for interactivity.
207
+
208
+ ```javascript
209
+ let name = 'Matt'
210
+
211
+ html [
212
+ head []
213
+ body [
214
+ h1 "Hello, {{name}}"
215
+ ]
216
+ ]
217
+ ```
218
+
219
+ Light.js supports strings, numbers, arrays, objects, boolean, and null, just like JSON.
220
+
221
+ ```javascript
222
+ let colors = [
223
+ 'red',
224
+ 'blue',
225
+ 'green'
226
+ ]
227
+
228
+ let person = {
229
+ name: 'Matt',
230
+ age: 33
231
+ }
232
+
233
+ html [
234
+ head []
235
+ body [
236
+ h1 "Hello, {{person.name}}"
237
+ ]
238
+ ]
239
+ ```
240
+
241
+ Light.js supports the following operators:
242
+
243
+ ```
244
+ + - / * % ?:
245
+ ```
246
+
247
+ ```javascript
248
+ let count = 4 * (2 + 3)
249
+
250
+ let many = count > 10 ? true : false
251
+ ```
252
+
253
+ Arrays and objects can be accessed using expressions, as you might expect:
254
+
255
+ ```javascript
256
+ let person = {
257
+ name: 'Matt',
258
+ age: 33
259
+ }
260
+
261
+ let age = person.age
262
+ let name = person['nam' + 'e']
263
+ ```
264
+
265
+ Expressions can be interpolated into strings using double curly braces.
266
+
267
+ ```javascript
268
+ let count = 4 * (2 + 3)
269
+
270
+ html [
271
+ head []
272
+ body [
273
+ p '{{ count > 10 ? "many" : "not many" }}'
274
+ ]
275
+ ]
276
+ ```
277
+
278
+ Expressions can be passed into attributes using a single set of curly braces.
279
+
280
+ ```javascript
281
+ let link = '/'
282
+ let text = 'home'
283
+
284
+ html [
285
+ head []
286
+ body [
287
+ a href={link} '{{text}}'
288
+ ]
289
+ ]
290
+ ```
291
+
292
+ Once a Light.js variable is declared it cannot be reassigned, except using Javascript (more on that later). The following is not valid.
293
+
294
+ ```javascript
295
+ let name = 'Matt'
296
+
297
+ name = 'Bob' // this is illegal
298
+
299
+ html [
300
+ head []
301
+ body [
302
+ h1 'Hello {{name}}'
303
+ ]
304
+ ]
305
+ ```
306
+
307
+ For data transformations, Light.js has the pipe operator `|`:
308
+
309
+ ```javascript
310
+ let name = 'matt' | toupper
311
+
312
+ let nums = 1 | repeat 10 // creates an array of 10 1s
313
+
314
+ let length = nums | length // 10
315
+
316
+ html [
317
+ head []
318
+ body [
319
+ h1 'Hello {{name}}' // Hello MATT
320
+ ]
321
+ ]
322
+ ```
323
+
324
+ ### Built-in Pipes
325
+
326
+ **toupper** - Makes a string uppercase
327
+ ```javascript
328
+ let name = 'hello' | toupper
329
+ ```
330
+
331
+ **tolower** - Makes a string lowercase
332
+ ```javascript
333
+ let name = 'HELLO' | tolower
334
+ ```
335
+
336
+ **length** - Returns the length of the input
337
+ ```javascript
338
+ let len = x | length
339
+ ```
340
+
341
+ **repeat n** - Repeats the input N times. All data types are supported, and will be repeated. Even large complex objects.
342
+ ```javascript
343
+ let nums = 1 | repeat 10 // 10 1s
344
+ let x = {} | repeat 100 // 100 empty objects
345
+ ```
346
+
347
+ **map x** - Maps an array to an expression. The expression has 2 implicit arguments: `_a`, and `_b` which represent the value and the index respectively. This idea was borrowed from the Lobster programming language.
348
+ ```javascript
349
+ let people = [{
350
+ name: 'Frodo'
351
+ }, {
352
+ name: 'Sam'
353
+ }]
354
+ let names = people | map _a.name
355
+ // ['Frodo', 'Sam']
356
+ ```
357
+
358
+ Here is an example of map being used in conjunction with repeat:
359
+ ```javascript
360
+ let nums = 1 | repeat 5 | map _a + _b
361
+ // [1, 2, 3, 4, 5]
362
+ ```
363
+
364
+ The equivalent expression in javascript would look like this:
365
+ ```javascript
366
+ let nums = (new Array(5)).fill(1).map((_a, _b) => _a + _b);
367
+ ```
368
+
369
+ **filter x** - Filters an array against an expression that returns true or false. The expression has 2 implicit arguments: `_a`, and `_b` which represent the value and the index respectively.
370
+ ```javascript
371
+ let nums = 0 | repeat 10 | map _a + _b | filter _b % 2 == 0
372
+ // [0, 2, 4, 6, 8]
373
+ ```
374
+
375
+ **split x** - Splits a string at a given delimeter into an array
376
+ ```javascript
377
+ let greet = 'helloxworld' | split 'x'
378
+ // ['hello', 'world']
379
+ ```
380
+
381
+ **includes x** - Checks whether or not an item is included in an array
382
+ ```javascript
383
+ let has4 = [1, 2, 3, 4, 5] | includes 4
384
+ // true
385
+ ```
386
+
387
+ **indexof x** - Retrieves the index of an item in an array. Returns -1 if not found
388
+ ```javascript
389
+ let pos = [1, 2, 3, 4, 5] | indexof 4
390
+ // 3
391
+ ```
392
+
393
+ **reverse** - Reverses a string or array
394
+ ```javascript
395
+ let nums = [1, 2, 3] | reverse
396
+ // [3, 2, 1]
397
+ let hello = 'hello' | reverse
398
+ // olleh
399
+ ```
400
+
401
+ **tostring** - Converts any data type to a string, including arrays and objects
402
+ ```javascript
403
+ let person = { name: "matt" } | tostring
404
+ // '{"name":"matt"}'
405
+
406
+ let num = 10 | tostring
407
+ // '10'
408
+ ```
409
+
410
+ **todata** - Converts a string of data into useable data
411
+ ```javascript
412
+ let person = '{"name":"matt"}' | todata
413
+ let number = '10' | todata
414
+ let thetruth = 'true' | todata
415
+
416
+ html [
417
+ head[]
418
+ body[
419
+ h1 'Hello {{person.name}}'
420
+ ]
421
+ ]
422
+ ```
423
+
424
+ **replace x y** - Replaces the first instance of X in a string with Y
425
+ ```javascript
426
+ let str = 'hello world' | replace 'd' 'd!'
427
+ // 'hello world!'
428
+ ```
429
+
430
+ **join x** - Joins an array into a string using a delimeter
431
+ ```javascript
432
+ let x = ['hello', 'world'] | join ' '
433
+ // 'hello world'
434
+ ```
435
+
436
+ **keys** - Create an array from the keys of an object
437
+ ```javascript
438
+ let person = {
439
+ name: 'Frodo',
440
+ age: 80
441
+ }
442
+ let keys = person | keys
443
+ // ['name', 'age']
444
+ ```
445
+
446
+ **values** - Create an array from the values of an object
447
+ ```javascript
448
+ let person = {
449
+ name: 'Frodo',
450
+ age: 80
451
+ }
452
+ let vals = person | values
453
+ // ['Frodo', 80]
454
+ ```
455
+
456
+ **trim** - Trim the whitespace off the end of a string
457
+ ```javascript
458
+ let str = ' Hello world ' | trim
459
+ // 'Hello world'
460
+ ```
461
+
462
+ **slice x y** - Create a slice from an array or string
463
+ ```javascript
464
+ let str = 'Hello world' | slice 0 5
465
+ // 'Hello'
466
+ ```
467
+
468
+ **rand x** - Create a random floating point value between 0 and x
469
+ ```javascript
470
+ let val = 100 | rand
471
+ // 85.312
472
+ ```
473
+
474
+ ### Math Pipes
475
+
476
+ Light.js supports the following math pipes: `ceil`, `floor`, `sin`, `cos`, `tan`, `sqrt`
477
+
478
+ ```javascript
479
+ let v0 = 1 | sin
480
+ let v1 = 1 | cos
481
+ let v2 = 1 | tan
482
+
483
+ let v3 = 100 | sqrt
484
+ let v4 = 3.5 | ceil
485
+ let v5 = 4.5 | floor
486
+
487
+ let v6 = 100 | rand | floor
488
+ // In javascript, this would be equivalent to
489
+ // Math.floor(Math.random() * 100)
490
+ ```
491
+
492
+ ## Control Flow
493
+
494
+ In Light.js, there are 3 control flow keywords: `if`, `else`, `each`
495
+
496
+ If statements evaluate a single expression. Brackets are used for control flow just like tag children.
497
+
498
+ ```javascript
499
+ let num = 10
500
+
501
+ html [
502
+ head []
503
+ body [
504
+ if (num > 10) [
505
+ p 'Number is greater than 10'
506
+ ] else if (num > 5) [
507
+ p 'Number is greater than 5'
508
+ ] else [
509
+ p 'Number is less than or equal to 5'
510
+ ]
511
+ ]
512
+ ]
513
+ ```
514
+
515
+ Each statements iterate over arrays and objects.
516
+
517
+ ```javascript
518
+ let num = [1, 2, 3, 4, 5]
519
+
520
+ html [
521
+ head []
522
+ body [
523
+ // the i is optional, and is the index of the item
524
+ each (n, i in nums) [
525
+ p 'value: {{n}}'
526
+ p 'index: {{i}}'
527
+ ]
528
+ ]
529
+ ]
530
+ ```
531
+
532
+ With objects, the first and second variables of the each statement are the key and value respectively:
533
+
534
+ ```javascript
535
+ let person = {
536
+ name: 'Frodo',
537
+ age: 80,
538
+ location: 'Shire'
539
+ }
540
+
541
+ html [
542
+ head []
543
+ body [
544
+ each (k, v in person) [
545
+ p '{{k}}: {{v}}'
546
+ ]
547
+ ]
548
+ ]
549
+ ```
550
+
551
+ ## Components
552
+
553
+ You create components in Light.js with the `tag` keyword. Data that is local to a component must be declared within the component.
554
+
555
+ ```javascript
556
+ // a component with a single button
557
+ tag MyButton [
558
+ let text = 'click'
559
+ button.btn '{{text}}'
560
+ ]
561
+
562
+ html [
563
+ head[]
564
+ body[
565
+ // use like any tag
566
+ MyButton[]
567
+ ]
568
+ ]
569
+ ```
570
+
571
+ Components do not need to have a root element, and can simply be a list of elements:
572
+
573
+ ```javascript
574
+ tag MyButtonList [
575
+ let text = 'click'
576
+
577
+ button.btn '{{text}}'
578
+ button.btn '{{text}}'
579
+ button.btn '{{text}}'
580
+ ]
581
+
582
+ html [
583
+ head[]
584
+ body[
585
+ MyButtonList[]
586
+ ]
587
+ ]
588
+ ```
589
+
590
+ Components can be moved to separate files at your discretion. You are free to have single file components or multi-component files. Components in separate files can be imported using the `import` keyword and exported using the `export` keyword:
591
+
592
+ ```javascript
593
+ // buttons.lightjs
594
+ export tag BlueButton [
595
+ let text = 'click'
596
+ button.btn-blue '{{text}}'
597
+ ]
598
+
599
+ export tag GreenButton [
600
+ let text = 'click'
601
+ button.btn-green '{{text}}'
602
+ ]
603
+ ```
604
+
605
+ ```javascript
606
+ // index.lightjs
607
+ // all exports are visible to this file
608
+ import 'buttons.lightjs'
609
+
610
+ html [
611
+ head[]
612
+ body[
613
+ BlueButton[]
614
+ GreenButton[]
615
+ ]
616
+ ]
617
+ ```
618
+
619
+ While simple, this import strategy may cause a name collision. To handle this, an imported module may be namespaced using the 'as' keyword:
620
+
621
+ ```javascript
622
+ // index.lightjs
623
+ import 'buttons.lightjs' as btn
624
+
625
+ html [
626
+ head[]
627
+ body[
628
+ btn::BlueButton[]
629
+ btn::GreenButton[]
630
+ ]
631
+ ]
632
+ ```
633
+
634
+ Component props can be accessed using the `props` keyword. Props are passed to components as regular attributes:
635
+
636
+ ```javascript
637
+ tag MyButton [
638
+ button.btn '{{props.text}}'
639
+ ]
640
+
641
+ html [
642
+ head []
643
+ body [
644
+ MyButton text='click' []
645
+ ]
646
+ ]
647
+ ```
648
+
649
+ Components can have children, and are displayed using the `yield` keyword:
650
+
651
+ ```javascript
652
+ tag MySection [
653
+ div.section-div [
654
+ yield
655
+ ]
656
+ ]
657
+
658
+ html [
659
+ head []
660
+ body [
661
+ MySection [
662
+ p [
663
+ 'I am a child of .section-div'
664
+ ]
665
+ ]
666
+ ]
667
+ ]
668
+ ```
669
+
670
+ Using yield is how common page layouts are achieved in Light.js:
671
+
672
+ ```javascript
673
+ // layout.lightjs
674
+ export tag Layout [
675
+ html lang='en' [
676
+ head [
677
+ title '{{props.title}}'
678
+ ]
679
+ body [
680
+ yield
681
+ ]
682
+ ]
683
+ ]
684
+ ```
685
+
686
+ ```javascript
687
+ // index.lightjs
688
+ import 'layout.lightjs'
689
+
690
+ Layout title='My Blog' [
691
+ main [
692
+ h1 "Welcome!"
693
+ ]
694
+ ]
695
+ ```
696
+
697
+ ## Javascript
698
+
699
+ Light.js documents can be made interactive by adding Javascript. This requires no additional setup. All Javascript in Light.js goes between sets of dashes `---`, or in event listener strings. The `on:` directive is used to attach event listeners to elements.
700
+
701
+ ```javascript
702
+ tag Counter [
703
+ // remember, this is not Javascript
704
+ let count = 0
705
+
706
+ // this part is Javascript
707
+ // Javascript in Light.js has the power to update template data directly
708
+ ---
709
+ function increment() {
710
+ count++
711
+ }
712
+ ---
713
+
714
+ // any valid browser event can follow the on: directive
715
+ // the string following 'on:click' is also javascript
716
+ button on:click='increment()' 'click count: {{count}}'
717
+ ]
718
+
719
+ html [
720
+ head []
721
+ body [
722
+ Counter[]
723
+ ]
724
+ ]
725
+ ```
726
+
727
+ From within Javascript, there are 3 functions and 1 object to know about: `$on`, `$emit`, `$sync` and `$e`. And that's all. The Javascript experience in Light.js doesn't require complex concepts and implicit contexts to learn about. It is simply contextualized properly so that you have access to your Light.js data and the ability to update the document.
728
+
729
+ ### `$sync()`
730
+
731
+ This is the most important function call in your Javascript. This call updates the UI when your data changes. This call is analgous to setState in React, except that it's synchronous and takes no arguments. `$sync()` does NOT need to be called after event listeners, because it is called automatically.
732
+
733
+ ```javascript
734
+ // in this example, a counter is incremented every second
735
+ let count = 0
736
+ ---
737
+ setInterval(() => {
738
+ count++
739
+ // sync needs to be called because this was not triggered by an event listener
740
+ $sync()
741
+ }, 1000)
742
+ ---
743
+ html [
744
+ head []
745
+ body [
746
+ h1 "Count: {{count}}"
747
+ ]
748
+ ]
749
+ ```
750
+
751
+ `$sync()` does not need to be called in the following example because increment() was called in an event listener.
752
+
753
+ ```javascript
754
+ tag Counter [
755
+ let count = 0
756
+ ---
757
+ function increment() {
758
+ count++
759
+ }
760
+ ---
761
+ button on:click='increment()' 'click count: {{count}}'
762
+ ]
763
+
764
+ html [
765
+ head[]
766
+ body[
767
+ Counter[]
768
+ ]
769
+ ]
770
+ ```
771
+
772
+ ### `$e`
773
+
774
+ This represents the event object within an event listener. There is nothing else to know about it. It is only available from within the event listener string.
775
+
776
+ ```javascript
777
+ let name = 'Matt'
778
+
779
+ ---
780
+ function setInput(e) {
781
+ name = e.target.value
782
+ }
783
+ ---
784
+
785
+ html [
786
+ head []
787
+ body [
788
+ input on:input='setInput($e)' []
789
+ h1 'Hello {{name}}'
790
+ ]
791
+ ]
792
+ ```
793
+
794
+ ### `$on(event, callback)`
795
+
796
+ This function call allows you to listen for lifecycle events within components. The current list of events is: `mount`, `unmount`, `change`, `render`.
797
+
798
+ ```javascript
799
+ tag MyComponent [
800
+ ---
801
+ $on('mount', () => {
802
+ console.log('mounted')
803
+ })
804
+
805
+ $on('unmount', () => {
806
+ console.log('unmounted')
807
+ })
808
+
809
+ $on('change', (oldProps) => {
810
+ console.log('props are different than last time')
811
+ })
812
+
813
+ $on('prerender', () => {
814
+ console.log('right before rendering')
815
+ })
816
+
817
+ $on('render', () => {
818
+ console.log('finished rendering')
819
+ })
820
+ ---
821
+ ]
822
+
823
+ html [
824
+ head []
825
+ body [
826
+ MyComponent[]
827
+ ]
828
+ ]
829
+ ```
830
+
831
+ ### `$emit(event, data)`
832
+
833
+ This function call allows components to emit events that parent components can listen for.
834
+
835
+ ```javascript
836
+ tag Child [
837
+ ---
838
+ function myClick(e) {
839
+ // emit a synthetic click event, and pass the object along
840
+ $emit('myclick', e)
841
+ }
842
+ ---
843
+ button on:click='myClick($e)' 'click'
844
+ ]
845
+
846
+ tag Parent [
847
+ // You simply use the on: directive on a component to listen for synthetic events
848
+ Child on:myclick='alert($e)' []
849
+ ]
850
+
851
+ html [
852
+ head []
853
+ body [
854
+ Parent[]
855
+ ]
856
+ ]
857
+ ```
858
+
859
+ ## Usage
860
+
861
+ ### `lightjs.compile()`
862
+
863
+ Fundamentally, Light.js is a library that takes in a Light.js source tree and outputs a single HTML file or string.
864
+
865
+ ```javascript
866
+ const lightjs = require('lightjs');
867
+
868
+ lightjs.compile({
869
+ input: 'src/index.lightjs',
870
+ output: 'public/index.html'
871
+ });
872
+ ```
873
+
874
+ No other step is required for a fully reactive, bundled, minified application.
875
+
876
+ This function may also be used to serve dynamic content in real time.
877
+
878
+ ```javascript
879
+ const express = require('express');
880
+ const lightjs = require('lightjs');
881
+
882
+ const app = express();
883
+
884
+ app.get('/', async (req, res) => {
885
+ const html = await lightjs.compile({
886
+ input: 'src/index.lightjs'
887
+ });
888
+ res.end(html);
889
+ });
890
+
891
+ app.listen(3838);
892
+ ```
893
+
894
+ In order for the above example to have production quality speed, you must enable caching. And if desired, Javascript minification can be enabled as well:
895
+
896
+ ```javascript
897
+ const html = await lightjs.compile({
898
+ input: 'src/index.lightjs',
899
+ cache: true,
900
+ minify: true
901
+ });
902
+ ```
903
+
904
+ The last thing to know about Light.js's compile function is document data.
905
+
906
+ ```javascript
907
+ const html = await lightjs.compile({
908
+ input: 'src/about.lightjs',
909
+ data: {
910
+ pageTitle: 'About me'
911
+ }
912
+ });
913
+ ```
914
+
915
+ In your Light.js document pageTitle can be found on the global 'data' object:
916
+
917
+ ```javascript
918
+ // index.lightjs
919
+ html [
920
+ head []
921
+ body [
922
+ h1 '{{data.pageTitle}}'
923
+ ]
924
+ ]
925
+ ```
926
+
927
+ ### `lightjs.app()`
928
+
929
+ As mentioned above, Light.js ships with a built-in backend router. This router is exposed through the 'app' function, which returns a Node.js HTTP request handler.
930
+
931
+ ```javascript
932
+ const http = require('http');
933
+ const light = require('lightjs');
934
+
935
+ const PORT = 4477;
936
+
937
+ const app = light.app({
938
+ publicDir: './public',
939
+ cache: true,
940
+ minify: true,
941
+ routes: {
942
+ // map a route directly to a light file
943
+ '/': 'src/index.light',
944
+
945
+ // or for more complex arrangements, you can map the route to the same arguments you would pass to light.compile()
946
+ '/blog/:id': {
947
+ input: 'src/blog.light',
948
+ data: async (req) => {
949
+ const post = 'hi' // get blog post with req.params.id
950
+ return post
951
+ }
952
+ }
953
+ }
954
+ })
955
+
956
+ http.createServer(app).listen(PORT);
957
+ ```
958
+
959
+ Light.js's router is also completely compatible with Express:
960
+
961
+ ```javascript
962
+ const http = require('http');
963
+ const light = require('lightjs');
964
+ const express = require('express');
965
+
966
+ const PORT = 4477;
967
+
968
+ const app = express();
969
+
970
+ const lightRouter = light.app({
971
+ cache: true,
972
+ minify: true,
973
+ routes: {
974
+ // ...
975
+ }
976
+ })
977
+
978
+ app.use(express.static('public'));
979
+ app.use(lightRouter);
980
+
981
+ http.createServer(app).listen(PORT);
982
+ ```
983
+
984
+ Or, as previously mentioned, you can simply use `light.compile` with Express:
985
+
986
+ ```javascript
987
+ const http = require('http');
988
+ const light = require('lightjs');
989
+ const express = require('express');
990
+
991
+ const PORT = 4477;
992
+
993
+ const app = express();
994
+
995
+ app.get('/', async (req, res) => {
996
+ const html = await light.compile({
997
+ input: 'src/index.light',
998
+ // for production
999
+ minify: true,
1000
+ cache: true
1001
+ });
1002
+
1003
+ res.end(html);
1004
+ });
1005
+
1006
+ http.createServer(app).listen(PORT);
1007
+ ```
1008
+
1009
+ This is the entire feature set of Lightjs. If there is even one aspect of Lightjs that is missing from this document, it is considered a bug.
1010
+