UNPKG

html-bundler-webpack-plugin

Version:

Generates complete single-page or multi-page website from source assets. Built-in support for Markdown, Eta, EJS, Handlebars, Nunjucks, Pug. Alternative to html-webpack-plugin.

139 lines (116 loc) 4.16 kB
const { readFileSync } = require('fs'); const path = require('path'); const { loadModule } = require('../../../Common/FileUtils'); const { stringifyJSON } = require('../../Utils'); const currentPath = process.cwd(); // node module name const moduleName = 'tempura'; // replace all single quotes around of require with "`", because the template function is generated using template literal // `<img src="' + require('file.png') + '">` => `<img src="` + require('file.png') + `">` const requireRegexp = /(?:')(\s+\+\s+require\(.+?\)\s+\+\s+)(?:')/g; /** * TODO: add the feature later * Require CommonJS or JSON file in template. * * @param {string} file * @param {string} dir * @return {*} */ const requireFile = (file, dir) => { const fullFilePath = path.join(dir, file); return file.endsWith('.json') ? JSON.parse(readFileSync(fullFilePath, 'utf-8')) : require(fullFilePath); }; /** * Transform the raw template source to a template function or HTML. * * @param {BundlerPluginLoaderContext} loaderContext * @param {{}} options * @return {{compile: (function(string, {resourcePath: string, data?: {}}): *), render: (function(string, {resourcePath: string, data?: {}}): *), export: (function(string, {data: {}}): string)}} */ const preprocessor = (loaderContext, options) => { const Tempura = loadModule(moduleName); const fs = loaderContext.fs.fileSystem; const { rootContext } = loaderContext; const extensions = ['.html', '.hbs', '.tmpr']; if (!options?.root) { options.root = currentPath; } if (!options?.views) { options.views = []; } if (!options.views.includes(currentPath)) { options.views.push(currentPath); } if (!options.views.includes(options.root)) { options.views.push(options.root); } if (!options?.blocks) { options.blocks = {}; } const builtInHelpers = { include: require('./helpers/include')({ Tempura, fs, root: options.root, views: options.views, extensions, options, }), }; options.blocks = { ...builtInHelpers, ...options.blocks }; const helpersString = stringifyJSON(options.blocks); return { /** * Unique preprocessor ID as the module name. */ id: moduleName, /** * Render template into HTML. * Called for rendering of template defined as entry point. * * @param {string} source The template source code. * @param {string} resourcePath * @param {{}} data * @return {string} */ render(source, { resourcePath, data = {} }) { options._data = data; const render = Tempura.compile(source, options); return render(data); }, /** * Compile template into template function. * Called when a template is loaded in JS in `compile` mode. * * @param {string} source The template source code. * @param {string} resourcePath * @param {{}} data * @return {string} */ compile(source, { resourcePath, data = {} }) { options.format = 'cjs'; return Tempura.transform(source, options); }, /** * Export the compiled template function contained resolved source asset files. * Note: this method is required for `compile` mode. * * @param {string} templateFunction The source code of the template function. * @param {{}} data The object with external variables passed in template from data option. * @return {string} The exported template function. */ export(templateFunction, { data }) { // the name of template function in generated code const exportFunctionName = 'templateFn'; const exportCode = 'module.exports='; templateFunction = templateFunction.replaceAll(requireRegexp, '`$1`'); templateFunction = templateFunction.replace(';module.exports=', `;var ${exportFunctionName}=`); return `${templateFunction}; var data = ${stringifyJSON(data)}; var helpers = ${helpersString}; ${exportCode} (context) => ${exportFunctionName}(Object.assign({}, data, context), helpers);`; }, }; }; module.exports = preprocessor; module.exports.test = /\.(html|hbs|tmpr)$/i;