incremental builds, fast dev preview server
This commit is contained in:
parent
252560ac04
commit
9c8d87401a
8 changed files with 141 additions and 10 deletions
36
dev_server.js
Normal file
36
dev_server.js
Normal 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)
|
||||||
|
|
@ -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
44
docs/test.md
Normal 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 }} |
|
||||||
|
:::
|
||||||
|
|
||||||
19
export.js
19
export.js
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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) => {
|
||||||
|
|
|
||||||
27
src/util.js
27
src/util.js
|
|
@ -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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue