118 lines
4.7 KiB
JavaScript
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)
|
|
}
|
|
})
|
|
} |