incremental builds, fast dev preview server

This commit is contained in:
Loren Norman 2025-08-22 14:17:57 -04:00
parent 252560ac04
commit 9c8d87401a
8 changed files with 141 additions and 10 deletions

36
dev_server.js Normal file
View file

@ -0,0 +1,36 @@
import process from 'node:process'
import { exec, execSync, spawnSync, spawn } from 'node:child_process'
import { promisify } from 'node:util'
const execAsync = promisify(exec)
// run a clean build, wait for it to complete
console.log("Building docs from scratch...")
spawnSync("node", ["export.js", "docs", "skipImages"], { stdio: 'inherit' })
console.log("Done")
// start the incremental build
console.log("Starting incremental builder and file watcher...")
const docBuilder = spawn("node", ["--watch-path=./app", "export.js", "docs-incremental"], { stdio: 'inherit' })
docBuilder.on('error', err => console.log('Builder Error:', err))
docBuilder.on('exit', code => console.log('Builder Exited', code === 0 ? "Cleanly" : `With Error Code ${code}`))
// start the docs server
console.log("Starting Vitepress docs server...")
const docServer = spawn("npm", ["run", "docs:dev"], { stdio: 'inherit' })
docServer.on('error', err => console.log('Server Error:', err))
docServer.on('exit', code => console.log('Server Exited', code === 0 ? "Cleanly" : `With Error Code ${code}`))
const killAll = () => {
console.log('Shutting down...')
docBuilder.kill()
docServer.kill()
process.exit()
}
// if either one exits, kill the other
console.log("Watching files for changes and servers for crashes")
docServer.on('exit', killAll)
docBuilder.on('exit', killAll)

View file

@ -6,6 +6,10 @@ const REPO = 'https://github.com/adafruit/io-actions'
// https://vitepress.dev/reference/site-config // https://vitepress.dev/reference/site-config
export default defineConfig({ export default defineConfig({
vite: {
clearScreen: false
},
title: "IO Actions: Block Reference", title: "IO Actions: Block Reference",
description: "Documentation for Adafruit IO's block-based Actions", description: "Documentation for Adafruit IO's block-based Actions",

44
docs/test.md Normal file
View file

@ -0,0 +1,44 @@
# Markdown Tester
## Works
<span v-pre>
{{ span v-pre }}
::: warning
what a warning!
:::
</span>
```
{{ triple_backticks }}
```
```js
{{ js_triple_backticks }}
```
::: details Embedded in a panel
::: details multiple panels
::: details multiple panels
::: details multiple panels
a message!
:::
## Doesn't Work
<span v-pre>
`{{ single_backticks }}`
</span>
## Experiment
::: v-pre
| Separator |
|-----------|
| <span v-pre>{{ in_span_table }}</span> |
| {{ in_span_table }} |
:::

View file

@ -54,6 +54,25 @@ const
}) })
}, },
"docs-incremental": async () => {
// allow option to skip image generation
// const skipImages = taskArgs.includes("skipImages")
// if(!skipImages) {
// await exporters.blockImages()
// cleanDir("docs/block_images")
// cpSync("tmp/block_images/images", "docs/block_images", { recursive: true })
// }
// await exporters.app("docs/blockly")
// cleanDir("docs/blocks")
await exportTo("docs", definitions, exportItem => {
exportItem.blockIndex("blocks/index.md")
exportItem.blockPages()
exportItem.sidebar("blocks/_blocks_sidebar.json")
})
},
"blockImages": async () => { "blockImages": async () => {
const destination = "tmp/block_images" const destination = "tmp/block_images"
cleanDir(destination) cleanDir(destination)

View file

@ -11,7 +11,7 @@
}, },
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"start": "vite --force", "start": "node dev_server.js",
"test": "node --test", "test": "node --test",
"test-watch": "node --test --watch", "test-watch": "node --test --watch",
"test-snapshots": "node --test test/app/blocks/snapshots/block_snapshots_test.js", "test-snapshots": "node --test test/app/blocks/snapshots/block_snapshots_test.js",

View file

@ -1,7 +1,6 @@
import { mkdirSync, writeFileSync } from 'fs'
import { dirname } from 'path'
import { forEach, identity, pickBy } from 'lodash-es' import { forEach, identity, pickBy } from 'lodash-es'
import { writeFileIfDifferent } from '#src/util.js'
import toBlockMarkdown from "#src/docs/render_block.js" import toBlockMarkdown from "#src/docs/render_block.js"
@ -25,10 +24,10 @@ export default class BlockPageExporter {
forEach(this.definitionSet.blocks, blockDefinition => { forEach(this.definitionSet.blocks, blockDefinition => {
const const
docPath = options.filenameFunc(blockDefinition), docPath = options.filenameFunc(blockDefinition),
fullPath = `${this.destination}/${docPath}` fullPath = `${this.destination}/${docPath}`,
newContent = toBlockMarkdown(blockDefinition)
mkdirSync(dirname(fullPath), { recursive: true }) writeFileIfDifferent(fullPath, newContent)
writeFileSync(fullPath, toBlockMarkdown(blockDefinition))
}) })
} }
@ -41,3 +40,4 @@ export default class BlockPageExporter {
this.export(exportOptions) this.export(exportOptions)
} }
} }

View file

@ -1,5 +1,6 @@
import { writeFileSync } from 'fs' import { find, forEach, isString, map, sortBy } from 'lodash-es'
import { find, forEach, isString, map } from 'lodash-es'
import { writeFileIfDifferent } from '#src/util.js'
export default class SidebarExporter { export default class SidebarExporter {
@ -34,7 +35,7 @@ export default class SidebarExporter {
blockSidebar.items.push(uncategorizedCategory) blockSidebar.items.push(uncategorizedCategory)
forEach(this.definitionSet.blocks, blockDefinition => { forEach(sortBy(this.definitionSet.blocks, 'type'), blockDefinition => {
const const
sidebarEntry = { sidebarEntry = {
text: blockDefinition.name, text: blockDefinition.name,
@ -69,7 +70,7 @@ export default class SidebarExporter {
? options.toFile ? options.toFile
: `_blocks_sidebar.json` : `_blocks_sidebar.json`
writeFileSync(`${this.destination}/${filename}`, JSON.stringify(blockSidebar, null, 2)) writeFileIfDifferent(`${this.destination}/${filename}`, JSON.stringify(blockSidebar, null, 2))
} }
exportToFile = (toFile=true) => { exportToFile = (toFile=true) => {

View file

@ -1,6 +1,21 @@
import { dirname } from 'path'
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs'
import { createHash } from 'crypto'
import { map } from 'lodash-es' import { map } from 'lodash-es'
const getStringHash = stringToHash => {
const hash = createHash('sha256')
hash.update(stringToHash)
return hash.digest('hex')
}
const getFileHash = filePath => {
if(!existsSync(filePath)) { return '' }
return getStringHash(readFileSync(filePath))
}
export const export const
niceTemplate = tplString => { niceTemplate = tplString => {
const const
@ -19,4 +34,16 @@ export const
// TODO: support niceties for markdown, double-newlines, escaping, etc // TODO: support niceties for markdown, double-newlines, escaping, etc
return tplString return tplString
},
writeFileIfDifferent = (filename, content) => {
const
fileHash = getFileHash(filename),
contentHash = getStringHash(content)
if(fileHash !== contentHash) {
console.log("writing", filename)
mkdirSync(dirname(filename), { recursive: true })
writeFileSync(filename, content)
}
} }