Files
asciidisco.com/build/tasks/htaccess.js
2023-08-01 13:49:46 +02:00

118 lines
4.7 KiB
JavaScript

const fs = require('fs')
const path = require('path')
const filewalker = require('filewalker')
const Handlebars = require('handlebars')
const Manifest = require('http2-push-manifest/lib/manifest')
const chalk = require('chalk')
const log = console.log;
const PUSH_MANIFEST_FILE_TEMPLATE = ' <FilesMatch "{{file}}">\n{{{ressources}}}\n </FilesMatch>'
const PUSH_MANIFEST_RESSOURCE_TEMPLATE = ' Header add Link "<{{file}}>; rel=preload; as={{type}}"'
const NEWLINE = '\n'
/* PUSH Manifest functions */
// loads all generated .html files from the dist directory
const find_generated_html_files = (basepath, dist_path) => {
return new Promise(async (resolve, reject) => {
const fetch_all_files = () => {
return new Promise((resolve, reject) => {
let paths = []
filewalker(path.join(basepath, dist_path))
.on('file', file => paths.push(path.join(basepath, dist_path, file)))
.on('done', () => resolve(paths))
.walk()
})
}
const all_files = await fetch_all_files()
const html_files = all_files.filter(file => path.extname(file) === '.html')
resolve(html_files)
})
}
// analyze files & generate a json manifest
const generate_manifest = (manifestName, files, singleFile) => {
return new Promise((resolve, reject) => {
let jsonOutput = {}
if (!files.length) return resolve({manifest: new Manifest({name: manifestName}), jsonOutput})
// Make a path if one wasn't given. e.g. basic.html -> ./basic.html
let f = files[0]
if (f.indexOf(path.sep) === -1) f = `.${path.sep}${f}`
// determine base & inoput paths
let basePath = f.slice(0, f.lastIndexOf(path.sep))
let inputPath = f.slice(f.lastIndexOf(path.sep) + 1);
// generate the manifest
let manifest = new Manifest({basePath, inputPath, name: manifestName});
manifest.generate().then(output => {
if (singleFile) return resolve({manifest})
jsonOutput[inputPath] = output.file
// Remove processed file from list and proceed with next.
files.shift();
generate_manifest(manifestName, files, singleFile)
}).catch(err => reject(err))
})
}
/* Templating functions */
// load .htaccess template
const load_htaccess_template = basepath => {
return new Promise((resolve, reject) => {
fs.readFile(path.join(basepath, '.htaccess'), (err, body) => {
if (err) return reject(err)
resolve(String(body))
})
})
}
// add public dir to .htaccess rewrite & push manifest
const compile_template = (source, root_dir, manifest) => {
const template = Handlebars.compile(source)
return template({PUBLIC_FOLDER: root_dir, PUSH_MANIFEST: manifest})
}
// generate push manifest templates
const generate_push_manifest = (config, html_files) => {
return new Promise(async (resolve, reject) => {
let manifest_promises = html_files.map(file => generate_manifest(config.root_dir, [file], [file].length < 2))
const manifests = await Promise.all(manifest_promises)
const httaccess_parts = manifests.map(manifest => {
const res_template = Handlebars.compile(PUSH_MANIFEST_RESSOURCE_TEMPLATE)
const file_template = Handlebars.compile(PUSH_MANIFEST_FILE_TEMPLATE)
const ressources = Object.keys(manifest.manifest.fileContent).map(file => res_template({file: file, type: manifest.manifest.fileContent[file].type})).join(NEWLINE)
return file_template({ressources: ressources, file: manifest.manifest.inputPath})
})
resolve(httaccess_parts.join(NEWLINE))
})
}
// write .htaccess files
const write_htaccess = (config, content) => {
new Promise((resolve, reject) => {
fs.writeFile(path.join(config.basepath, config.dist_path, '.htaccess'), content, err => {
if (err) return rej(err)
resolve()
})
})
}
module.exports = config => {
return new Promise(async (resolve, reject) => {
try {
// load source
log(' ', chalk.green('>>'), 'Loading .htaccess template')
const source = await load_htaccess_template(config.basepath)
// get generated html files
log(' ', chalk.green('>>'), 'Grepping generated HTML files')
const html_files = await find_generated_html_files(config.basepath, config.dist_path)
// get push manifest
log(' ', chalk.green('>>'), 'Generating push manifests')
const push_manifest = await generate_push_manifest(config, html_files)
// add push manifests & public dir
log(' ', chalk.green('>>'), 'Compiling .htaccess')
const result = compile_template(source, config.root_dir, push_manifest)
// write htaccess files
log(' ', chalk.green('>>'), 'Writing .htaccess')
await write_htaccess(config, result)
// resolve task
resolve({result})
} catch(err) {
reject(err)
}
})
}