Skip to content

Commit 985721d

Browse files
committed
Update README
1 parent a1cedc0 commit 985721d

File tree

1 file changed

+39
-29
lines changed

1 file changed

+39
-29
lines changed

README.md

Lines changed: 39 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -14,59 +14,67 @@ Unlike traditional template engines, Boxwood templates are **just JavaScript fun
1414
const HomePage = ({ posts }) => {
1515
return Div([
1616
H1("Blog"),
17-
posts.map(post => Article([
18-
H2(post.title),
19-
P(post.summary)
20-
]))
17+
posts.map((post) => Article([H2(post.title), P(post.summary)])),
2118
])
2219
}
2320
```
2421

2522
## Key Advantages
2623

2724
### Zero Learning Curve
25+
2826
If you know JavaScript, you already know Boxwood. Use `map`, `filter`, `if/else`, and all standard JS features naturally.
2927

3028
### IDE Support
29+
3130
Get autocomplete, refactoring, and go-to-definition out of the box. Your templates are just code, so your editor understands them.
3231

3332
### True Composition
33+
3434
Components are functions. Compose them like functions. No slots, no special APIs - just parameters and return values.
3535

3636
### Performance
37+
3738
No template parsing at runtime. Templates are already JavaScript functions, eliminating parsing overhead.
3839

3940
### Security Helpers
41+
4042
- Automatic HTML escaping by default
4143
- Basic sanitization for loaded SVG/HTML files
4244
- Path traversal protection for file operations
4345
- Remember: security is ultimately your responsibility
4446

4547
### Integrated CSS Management
48+
4649
- Automatic CSS scoping with hash-based class names
4750
- CSS-in-JS with zero runtime
4851
- Critical CSS inlining
4952
- Automatic minification
5053

5154
### Built-in i18n Support
55+
5256
First-class internationalization support with a simple, component-friendly API for multi-language applications.
5357

5458
### Asset Handling
59+
5560
- Inline images as base64
5661
- SVG loading with automatic sanitization
5762
- JSON data loading
5863
- Raw HTML imports with XSS protection
5964

6065
### SEO Friendly
66+
6167
- Pure server-side rendering - search engines see fully rendered HTML
6268
- Lightning fast pages with inlined critical CSS
6369
- Minimal payload size improves Core Web Vitals scores
6470
- No client-side hydration delays
6571

6672
### Minimal Footprint
67-
Single file implementation (~950 lines). No complex build process or heavy dependencies.
73+
74+
Short implementation. No complex build process or heavy dependencies.
6875

6976
### Testable by Design
77+
7078
Templates are pure functions - easy to unit test with any testing framework.
7179

7280
## Table of Contents
@@ -91,10 +99,7 @@ Create a template file:
9199
const { Div, H1, P } = require("boxwood")
92100

93101
module.exports = ({ name, message }) => {
94-
return Div([
95-
H1(`Hello, ${name}!`),
96-
P(message)
97-
])
102+
return Div([H1(`Hello, ${name}!`), P(message)])
98103
}
99104
```
100105

@@ -105,9 +110,9 @@ Compile and render it:
105110
const { compile } = require("boxwood")
106111

107112
const { template } = compile("./templates/greeting.js")
108-
const html = template({
113+
const html = template({
109114
name: "World",
110-
message: "Welcome to Boxwood"
115+
message: "Welcome to Boxwood",
111116
})
112117

113118
console.log(html)
@@ -119,40 +124,41 @@ console.log(html)
119124
Boxwood includes built-in Express support:
120125

121126
```js
122-
import express from 'express'
123-
import engine from 'boxwood/adapters/express'
124-
import crypto from 'crypto'
127+
import express from "express"
128+
import engine from "boxwood/adapters/express"
129+
import crypto from "crypto"
125130

126131
const app = express()
127132

128133
// Register Boxwood as template engine
129-
app.engine('js', engine())
130-
app.set('views', './views')
131-
app.set('view engine', 'js')
134+
app.engine("js", engine())
135+
app.set("views", "./views")
136+
app.set("view engine", "js")
132137

133138
// CSP (Content Security Policy) nonce for inline scripts
134139
// A nonce is a unique random value generated for each request that allows
135140
// specific inline scripts to execute while blocking potential XSS attacks
136141
app.use((req, res, next) => {
137142
// Generate a cryptographically secure random nonce
138-
res.locals.nonce = crypto.randomBytes(16).toString('base64')
139-
143+
res.locals.nonce = crypto.randomBytes(16).toString("base64")
144+
140145
// Set CSP header - only scripts with this exact nonce can execute
141146
res.setHeader(
142-
'Content-Security-Policy',
147+
"Content-Security-Policy",
143148
`script-src 'nonce-${res.locals.nonce}' 'strict-dynamic';`
144149
)
145150
next()
146151
})
147152

148153
// Render templates - nonce is automatically injected into all inline scripts
149-
app.get('/', (req, res) => {
150-
res.render('home', { title: 'Welcome' })
154+
app.get("/", (req, res) => {
155+
res.render("home", { title: "Welcome" })
151156
// Boxwood automatically adds nonce="${res.locals.nonce}" to script tags
152157
})
153158
```
154159

155160
The Express adapter automatically:
161+
156162
- Handles template caching in production
157163
- Hot reloads templates in development
158164
- Injects CSP nonces from `res.locals.nonce` into all inline scripts and styles
@@ -171,6 +177,7 @@ A Content Security Policy (CSP) nonce is a security feature that helps prevent C
171177
- Attackers can't guess the nonce, so injected scripts are blocked
172178

173179
Example output:
180+
174181
```html
175182
<!-- HTTP Header -->
176183
Content-Security-Policy: script-src 'nonce-rAnd0m123' 'strict-dynamic';
@@ -205,10 +212,13 @@ const styles = css`
205212
`
206213

207214
const Button = ({ variant, children }) => {
208-
return ButtonTag({
209-
// className accepts arrays - falsy values are automatically filtered
210-
className: [styles.button, variant === 'secondary' && styles.secondary]
211-
}, children)
215+
return ButtonTag(
216+
{
217+
// className accepts arrays - falsy values are automatically filtered
218+
className: [styles.button, variant === "secondary" && styles.secondary],
219+
},
220+
children
221+
)
212222
}
213223

214224
module.exports = component(Button, { styles })
@@ -223,12 +233,12 @@ const { component, i18n, H1, P } = require("boxwood")
223233
const Welcome = ({ translate, username }) => {
224234
return [
225235
H1(translate("greeting").replace("{name}", username)),
226-
P(translate("intro"))
236+
P(translate("intro")),
227237
]
228238
}
229239

230-
module.exports = component(Welcome, {
231-
i18n: i18n.load(__dirname)
240+
module.exports = component(Welcome, {
241+
i18n: i18n.load(__dirname),
232242
})
233243
```
234244

0 commit comments

Comments
 (0)