95 lines
3.1 KiB
JavaScript
95 lines
3.1 KiB
JavaScript
import fs from 'node:fs'
|
|
import { spawn } from 'node:child_process'
|
|
import path from 'node:path'
|
|
import { defineConfig } from 'vite'
|
|
import { createRegenerationQueue } from './dev-reload.js'
|
|
import { contentDirectories, contentSources, generatedRoot } from './site.config.js'
|
|
|
|
function generatedPages(directory) {
|
|
const inputs = {}
|
|
for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
|
|
const filePath = path.join(directory, entry.name)
|
|
if (entry.isDirectory()) Object.assign(inputs, generatedPages(filePath))
|
|
else if (entry.name === 'index.html') {
|
|
const relativePath = path.relative(generatedRoot, filePath)
|
|
const key = relativePath.endsWith('/index.html') ? relativePath.slice(0, -'/index.html'.length) : relativePath
|
|
inputs[key] = path.resolve(filePath)
|
|
} else if (entry.name === '404.html' && directory === generatedRoot) {
|
|
inputs['404'] = path.resolve(filePath)
|
|
}
|
|
}
|
|
return inputs
|
|
}
|
|
|
|
function copyGeneratedFiles() {
|
|
const files = ['feed.xml', 'sitemap.xml']
|
|
return {
|
|
name: 'copy-generated-files',
|
|
closeBundle() {
|
|
const dist = path.resolve('dist')
|
|
if (!fs.existsSync(dist)) return
|
|
for (const file of files) {
|
|
const source = path.resolve(generatedRoot, file)
|
|
if (fs.existsSync(source)) fs.copyFileSync(source, path.join(dist, file))
|
|
}
|
|
},
|
|
}
|
|
}
|
|
|
|
function contentGenerator() {
|
|
return {
|
|
name: 'content-generator',
|
|
configureServer(server) {
|
|
const queue = createRegenerationQueue({
|
|
generate: () => new Promise((resolve, reject) => {
|
|
const child = spawn(process.execPath, ['generator.js', '--drafts'], { stdio: 'inherit' })
|
|
child.once('error', reject)
|
|
child.once('close', (code) => code === 0 ? resolve() : reject(new Error(`exit ${code ?? 'unknown'}`)))
|
|
}),
|
|
onSuccess: () => server.ws.send({ type: 'full-reload' }),
|
|
onError: (error) => {
|
|
console.error(`Content generation failed: ${error.message}`)
|
|
server.ws.send({
|
|
type: 'error',
|
|
err: { message: `Content generation failed (${error.message}). Check the terminal for details.`, stack: '' },
|
|
})
|
|
},
|
|
})
|
|
const sources = new Set(contentSources.map((source) => path.resolve(source)))
|
|
server.watcher.add([...sources])
|
|
server.httpServer?.once('close', () => queue.close())
|
|
server.watcher.on('all', (event, file) => {
|
|
if (!['add', 'change', 'unlink'].includes(event)) return
|
|
const isMarkdown =
|
|
file.endsWith('.md') &&
|
|
contentDirectories.some((dir) => file.startsWith(`${path.resolve(dir)}/`))
|
|
if (!isMarkdown && !sources.has(file)) return
|
|
queue.request()
|
|
})
|
|
},
|
|
}
|
|
}
|
|
|
|
export default defineConfig({
|
|
plugins: [contentGenerator(), copyGeneratedFiles()],
|
|
root: generatedRoot,
|
|
publicDir: '../public',
|
|
resolve: {
|
|
alias: {
|
|
'/src': path.resolve('src'),
|
|
},
|
|
},
|
|
server: {
|
|
watch: {
|
|
ignored: [`**/${generatedRoot}/**`],
|
|
},
|
|
},
|
|
build: {
|
|
outDir: path.resolve('dist'),
|
|
emptyOutDir: true,
|
|
rollupOptions: {
|
|
input: generatedPages(generatedRoot),
|
|
},
|
|
},
|
|
})
|