better separation for block image task

This commit is contained in:
Loren Norman 2025-08-22 15:42:07 -04:00
parent d65750fc92
commit 3a36c1bb2d
3 changed files with 43 additions and 34 deletions

View file

@ -41,6 +41,9 @@ jobs:
- name: Install dependencies - name: Install dependencies
run: npm ci run: npm ci
- name: Export Block Images
run: npm run export:block-images
- name: Export Block Definitions to Markdown - name: Export Block Definitions to Markdown
run: npm run docs:export run: npm run docs:export

View file

@ -1,5 +1,5 @@
import { spawn, spawnSync } from 'node:child_process' import { spawn, spawnSync } from 'node:child_process'
import { copyFileSync, cpSync } from 'node:fs' import { copyFileSync, cpSync, existsSync } from 'node:fs'
import { cleanDir, write, totalBytesWritten } from "./export_util.js" import { cleanDir, write, totalBytesWritten } from "./export_util.js"
import DefinitionSet from '#src/definitions/definition_set.js' import DefinitionSet from '#src/definitions/definition_set.js'
@ -20,6 +20,7 @@ const
definitions = await DefinitionSet.load(), definitions = await DefinitionSet.load(),
exporters = { exporters = {
// Build the Blockly application itself
"app": async (destination="export") => { "app": async (destination="export") => {
// clear the export directory // clear the export directory
@ -34,13 +35,13 @@ const
}) })
}, },
// Build the documentation for the Blockly application
"docs": async () => { "docs": async () => {
// allow option to skip image generation // TODO: check and warn if block images haven't been generated
const skipImages = taskArgs.includes("skipImages") if(!existsSync("docs/block_images/action_root.png")) {
if(!skipImages) { console.log("Block images missing from docs/block_images!")
await exporters.blockImages() console.log("Run: `npm run export:block-images` before exporting the docs")
cleanDir("docs/block_images") process.exit(1)
cpSync("tmp/block_images/images", "docs/block_images", { recursive: true })
} }
await exporters.app("docs/blockly") await exporters.app("docs/blockly")
@ -54,18 +55,9 @@ const
}) })
}, },
// Build the documentation but only touch files that have changed
// This is good to pair with a process that watches files for changes
"docs-incremental": async () => { "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 => { await exportTo("docs", definitions, exportItem => {
exportItem.blockIndex("blocks/index.md") exportItem.blockIndex("blocks/index.md")
exportItem.blockPages() exportItem.blockPages()
@ -73,31 +65,40 @@ const
}) })
}, },
"blockImages": async () => { // Create png images of all blocks by:
const destination = "tmp/block_images" // - creating a temporary app with no toolbox and all blocks on the workspace
cleanDir(destination) // - serving that application
cleanDir(`${destination}/images`) // - driving a browser to it with Cypress
// - right clicking on each block and clicking "download image"
"blockImages": async (imageDestination="docs/block_images") => {
const tmpAppDestination = "tmp/block_images_app"
cleanDir(tmpAppDestination)
// export a special app with no toolbox, all blocks on workspace // export a special app with no toolbox, all blocks on workspace
await exportTo(destination, definitions, exportItem => { await exportTo(tmpAppDestination, definitions, exportItem => {
exportItem.workspaceAllBlocks("workspace.json") exportItem.workspaceAllBlocks("workspace.json")
write(`${destination}/toolbox.json`, "null") write(`${tmpAppDestination}/toolbox.json`, "null")
exportItem.blocks("blocks.json") exportItem.blocks("blocks.json")
exportItem.script("blockly_app.js") exportItem.script("blockly_app.js")
// TODO: make a DocumentExporter for generating html wrappers // TODO: make a DocumentExporter for generating html wrappers
copyFileSync("src/exporters/document_templates/blockly_workspace.template.html", `${destination}/index.html`) copyFileSync("src/exporters/document_templates/blockly_workspace.template.html", `${tmpAppDestination}/index.html`)
}) })
// serve it // serve the screenshot app
console.log('Serving workspace for screenshots...') console.log('Serving workspace for screenshots...')
const viteProcess = spawn("npx", ["vite", "serve", destination]) const viteProcess = spawn("npx", ["vite", "serve", tmpAppDestination])
// prepare the image location
cleanDir(imageDestination)
// extract the screenshots // extract the screenshots
console.log('Generating screenshots...') console.log('Generating screenshots...')
spawnSync("npx", ["cypress", "run", await spawnSync("npx", ["cypress", "run",
"--config", `downloadsFolder=${destination}/images`, "--config", `downloadsFolder=${imageDestination}`,
"--config-file", `cypress/cypress.config.js`, "--config-file", `cypress/cypress.config.js`,
]) "--browser", "chromium",
"--spec", "cypress/e2e/block_images.cy.js",
], { stdio: 'inherit' })
console.log('Generation complete.') console.log('Generation complete.')
// kill the server // kill the server
@ -105,16 +106,19 @@ const
console.log("Vite failed to exit gracefully") console.log("Vite failed to exit gracefully")
process.exit(1) process.exit(1)
} }
console.log('Server closed.') console.log('Server closed.')
} }
}, },
exporterNames = Object.keys(exporters) exporterNames = Object.keys(exporters)
// Look up the requested exporter
if(!exporterNames.includes(toExport)) { if(!exporterNames.includes(toExport)) {
console.error(`Export Error: No exporter found for: "${toExport}"\nValid exporters: "${exporterNames.join('", "')}"`) console.error(`Export Error: No exporter found for: "${toExport}"\nValid exporters: "${exporterNames.join('", "')}"`)
process.exit(1) process.exit(1)
} }
// Execute the export
const startTime = Date.now() const startTime = Date.now()
console.log(`\nStarting Export: ${toExport}`) console.log(`\nStarting Export: ${toExport}`)
console.log("=======================") console.log("=======================")
@ -124,7 +128,8 @@ await exporter()
const elapsed = Date.now() - startTime const elapsed = Date.now() - startTime
console.log("=======================") console.log("=======================")
console.log(`🏁 Done. Wrote ${totalBytesWritten.toFixed(3)}k in ${elapsed}ms 🏁`) console.log(`🏁 Done (${elapsed}ms) 🏁`)
// Bye!
process.exit(0) process.exit(0)

View file

@ -12,16 +12,17 @@
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"start": "node dev_server.js", "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",
"test-update-snapshots": "node --test --test-update-snapshots test/app/blocks/snapshots/block_snapshots_test.js", "test-update-snapshots": "node --test --test-update-snapshots test/app/blocks/snapshots/block_snapshots_test.js",
"lint": "eslint src/", "lint": "eslint src/",
"lint-export": "eslint export/", "lint-export": "eslint export/",
"export:app": "node export.js app", "export:app": "node export.js app",
"build": "npm run export:app && vite build", "export:block-images": "node export.js blockImages",
"build-all-branches": "node build_all_branches.js",
"preview": "npm run build && vite preview",
"docs:export": "node export.js docs", "docs:export": "node export.js docs",
"docs:dev": "vitepress dev docs", "docs:dev": "vitepress dev docs",
"docs:build": "vitepress build docs", "docs:build": "vitepress build docs",