boxwood 0.74.1 → 0.75.0

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.
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2018 - 2022 buxlabs
3
+ Copyright (c) 2018 - 2024 buxlabs
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -5,9 +5,28 @@
5
5
 
6
6
  > Server side templating engine written in JavaScript
7
7
 
8
+ [boxwood](https://github.com/buxlabs/boxwood) was created to achieve the following design goals:
9
+
10
+ 1. templates can be split into components
11
+ 2. css is hashed per component
12
+ 3. css is automatically minified
13
+ 4. critical css is inlined
14
+ 5. templates can import other dependencies
15
+ 6. inline images or svgs
16
+ 7. i18n support
17
+ 8. server side
18
+ 9. good for seo
19
+ 10. small (1 file, 700 LOC~)
20
+ 11. easy to start, familiar syntax
21
+ 12. easy to test
22
+
23
+ The template starts with a standard js file, which builds a tree of nodes, that get rendered to html.
24
+
8
25
  ## Table of Contents
9
26
 
10
27
  - [Install](#install)
28
+ - [Usage](#usage)
29
+ - [Syntax](#syntax)
11
30
  - [Maintainers](#maintainers)
12
31
  - [Contributing](#contributing)
13
32
  - [License](#license)
@@ -16,6 +35,98 @@
16
35
 
17
36
  `npm install boxwood`
18
37
 
38
+ ## Usage
39
+
40
+ ```js
41
+ const { compile } = require("boxwood")
42
+ const { join } = require("path")
43
+ // ...
44
+ const path = join(__dirname, "index.js")
45
+ const { template } = await compile(path)
46
+ // ...
47
+ const html = template({ foo: "bar" })
48
+ console.log(html)
49
+ ```
50
+
51
+ ## Syntax
52
+
53
+ ```js
54
+ // example/index.js
55
+ const layout = require("./layout")
56
+ const banner = require("./banner")
57
+
58
+ module.exports = () => {
59
+ return layout([
60
+ banner({
61
+ title: "Hello, world!",
62
+ description: "Lorem ipsum dolor sit amet",
63
+ }),
64
+ ])
65
+ }
66
+ ```
67
+
68
+ ```js
69
+ // example/layout/index.js
70
+
71
+ const { component, css, html, head, body } = require("boxwood")
72
+ const head = require("./head")
73
+
74
+ const styles = css.load(__dirname)
75
+
76
+ module.exports = component(
77
+ (children) => {
78
+ return html([head(), body({ className: styles.layout }, children)])
79
+ },
80
+ { styles }
81
+ )
82
+ ```
83
+
84
+ ```js
85
+ // example/head/index.js
86
+ const { head, title } = require("boxwood")
87
+
88
+ module.exports = () => {
89
+ return head([title("example")])
90
+ }
91
+ ```
92
+
93
+ ```js
94
+ // example/banner/index.js
95
+ const { component, css, h1, p, section } = require("boxwood")
96
+
97
+ const styles = css.load(__dirname)
98
+
99
+ module.exports = component(
100
+ ({ title, description }) => {
101
+ return section({ className: styles.banner }, [
102
+ h1(title),
103
+ description && p(description),
104
+ ])
105
+ },
106
+ { styles }
107
+ )
108
+ ```
109
+
110
+ ```js
111
+ // example/banner/index.test.js
112
+ const test = require("node:test")
113
+ const assert = require("node:assert")
114
+ const { compile } = require("boxwood")
115
+
116
+ test("banner renders a title", () => {
117
+ const { template } = await compile(__dirname)
118
+ const html = template({ title: 'foo' })
119
+ assert(html.includes('<h1>foo</h1>'))
120
+ })
121
+
122
+ test('banner renders an optional description', () => {
123
+ const { template } = await compile(__dirname)
124
+ const html = template({ title: 'foo', description: 'bar' })
125
+ assert(html.includes('<h1>foo</h1>'))
126
+ assert(html.includes('<p>bar</p>'))
127
+ })
128
+ ```
129
+
19
130
  ## Maintainers
20
131
 
21
132
  [@emilos](https://github.com/emilos)
@@ -6,7 +6,6 @@ const {
6
6
  } = require("fs")
7
7
  const { Suite } = require("benchmark")
8
8
  const underscore = require("underscore")
9
- const template = require("lodash.template")
10
9
  const handlebars = require("handlebars")
11
10
  const mustache = require("mustache")
12
11
  const { compile } = require("..")
@@ -34,10 +33,9 @@ async function benchmark(dir) {
34
33
  path.join(__dirname, `./fixtures/${dir}/boxwood.js`)
35
34
  )
36
35
  const fn2 = underscore.template(source2)
37
- const fn3 = template(source3)
38
- const fn4 = handlebars.compile(source4)
39
- const fn5 = (data) => mustache.render(source5, data)
40
- const fn6 = require(path.join(__dirname, `./fixtures/${dir}/vanilla.js`))
36
+ const fn3 = handlebars.compile(source4)
37
+ const fn4 = (data) => mustache.render(source5, data)
38
+ const fn5 = require(path.join(__dirname, `./fixtures/${dir}/vanilla.js`))
41
39
  mustache.parse(source5)
42
40
 
43
41
  const data = require(path.join(__dirname, `./fixtures/${dir}/data.json`))
@@ -52,12 +50,11 @@ async function benchmark(dir) {
52
50
  assert.deepEqual(result, normalize(fn3(data)))
53
51
  assert.deepEqual(result, normalize(fn4(data)))
54
52
  assert.deepEqual(result, normalize(fn5(data)))
55
- assert.deepEqual(result, normalize(fn6(data)))
56
53
 
57
54
  await new Promise((resolve) => {
58
55
  suite
59
56
  .add("vanilla[js]", function () {
60
- fn6(data)
57
+ fn5(data)
61
58
  })
62
59
  .add("boxwood[js]", function () {
63
60
  fn1(data)
@@ -65,14 +62,11 @@ async function benchmark(dir) {
65
62
  .add("underscore[ejs]", function () {
66
63
  fn2(data)
67
64
  })
68
- .add("lodash[ejs]", function () {
69
- fn3(data)
70
- })
71
65
  .add("handlebars[hbs]", function () {
72
- fn4(data)
66
+ fn3(data)
73
67
  })
74
68
  .add("mustache[mst]", function () {
75
- fn5(data)
69
+ fn4(data)
76
70
  })
77
71
  .on("cycle", function (event) {
78
72
  console.log(`${dir}: ${String(event.target)}`)
package/index.js CHANGED
@@ -314,9 +314,20 @@ function js(inputs) {
314
314
  }
315
315
 
316
316
  js.load = function () {
317
- const path = join(...arguments)
317
+ const parts = []
318
+ for (const param of arguments) {
319
+ if (typeof param === "string") {
320
+ parts.push(param)
321
+ }
322
+ }
323
+ const path = join(...parts)
318
324
  const file = path.endsWith(".js") ? path : join(path, "index.js")
319
325
  const content = readFileSync(file, "utf8")
326
+
327
+ const options = arguments[arguments.length - 1]
328
+ if (options && options.transform) {
329
+ return js`${options.transform(content)}`
330
+ }
320
331
  return js`${content}`
321
332
  }
322
333
 
@@ -539,7 +550,7 @@ i18n.load = function () {
539
550
  }
540
551
  }
541
552
 
542
- function component(fn, { styles, i18n, code } = {}) {
553
+ function component(fn, { styles, i18n, scripts } = {}) {
543
554
  function execute(a, b) {
544
555
  if (typeof a === "string" || typeof a === "number" || Array.isArray(a)) {
545
556
  return fn({}, a)
@@ -571,11 +582,11 @@ function component(fn, { styles, i18n, code } = {}) {
571
582
  }
572
583
  return function (a, b) {
573
584
  const tree = execute(a, b)
574
- if (styles && code) {
585
+ if (styles && scripts) {
575
586
  if (Array.isArray(tree)) {
576
- return tree.concat(styles.css, code.js)
587
+ return tree.concat(styles.css, scripts.js)
577
588
  }
578
- return [tree, styles.css, code.js]
589
+ return [tree, styles.css, scripts.js]
579
590
  }
580
591
  if (styles) {
581
592
  if (Array.isArray(tree)) {
@@ -583,11 +594,11 @@ function component(fn, { styles, i18n, code } = {}) {
583
594
  }
584
595
  return [tree, styles.css]
585
596
  }
586
- if (code) {
597
+ if (scripts) {
587
598
  if (Array.isArray(tree)) {
588
- return tree.concat(code.js)
599
+ return tree.concat(scripts.js)
589
600
  }
590
- return [tree, code.js]
601
+ return [tree, scripts.js]
591
602
  }
592
603
  return tree
593
604
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "boxwood",
3
- "version": "0.74.1",
3
+ "version": "0.75.0",
4
4
  "description": "Compile HTML templates into JS",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -45,13 +45,11 @@
45
45
  },
46
46
  "homepage": "https://github.com/buxlabs/boxwood#readme",
47
47
  "devDependencies": {
48
- "ava": "^6.1.2",
49
48
  "benchmark": "2.1.4",
50
49
  "c8": "^9.1.0",
51
50
  "express": "^4.19.2",
52
51
  "handlebars": "^4.7.8",
53
52
  "jsdom": "^24.0.0",
54
- "lodash.template": "4.5.0",
55
53
  "mustache": "^4.2.0",
56
54
  "underscore": "^1.13.6"
57
55
  },
@@ -65,6 +63,6 @@
65
63
  "dependencies": {
66
64
  "css-tree": "^2.3.1",
67
65
  "string-hash": "^1.1.3",
68
- "yaml": "^2.4.1"
66
+ "yaml": "^2.4.2"
69
67
  }
70
68
  }