A custom loader seems to do the trick:
express-handlebars-loader.js:
const loaderUtils = require('loader-utils');
const validateOptions = require('schema-utils');
const path = require('path');
const express = require('express');
const exphbs = require('express-handlebars');
module.exports = function (content) {
const options = loaderUtils.getOptions(this);
const app = options.app;
const contextCallback = options.contextCallback;
const view = path.relative(options.basePath, this.resourcePath);
const context = contextCallback(this.resourcePath, view);
var loaderAsyncCallback = this.async();
app.render(view, context, function (err, html) {
if (err) {
return loaderAsyncCallback(err);
}
const slug =
'// Module
'
+ 'var code = ' + JSON.stringify(html) + ';
'
+ '// Exports
'
+ 'module.exports = code;'
loaderAsyncCallback(null, slug);
});
};
webpack.config.js:
const CopyPlugin = require("copy-webpack-plugin");
const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
const fs = require('fs');
const url = require('url');
const express = require('express');
const exphbs = require('express-handlebars');
const app = express();
// Handlebars Setup
/**
* Instantiate a Handlebars instance with our config (default layout, helpers, etc.)
*/
const handlebasInstance = exphbs.create({
defaultLayout: 'mainLayout',
// Specify helpers which are only registered on this instance.
helpers
});
app.engine('handlebars', handlebasInstance.engine);
app.set('view engine', 'handlebars');
app.use('/assets', express.static('assets'));
const basePath = path.resolve(__dirname, './views');
function generateHtmlPlugins(templateDir) {
const itemList = fs.readdirSync(templateDir);
return itemList.flatMap(item => {
const [ name, extension ] = item.split('.');
if (extension == 'handlebars') {
const templatePath = path.resolve(templateDir, item);
const outputPath = path.resolve(templateDir, name + '.html');
const outputName = path.relative(basePath, outputPath);
return new HtmlWebpackPlugin({
filename: outputName,
inject: false,
template: templatePath
})
} else {
return [];
}
})
}
const siteHtmlPlugins = generateHtmlPlugins(basePath);
function contextCallback(resourcePath, view) {
var context = {};
if (view.includes('documentation/')) {
context.layout = 'documentationLayout';
}
return context;
}
module.exports = {
mode: 'development',
resolveLoader: {
modules: [ 'node_modules', path.resolve(__dirname, 'loaders') ]
},
entry: './src/entry-workaround.js',
output: {
filename: 'entry-workaround.js',
path: path.resolve(__dirname, 'public'),
},
module: {
rules: [{
test: /.handlebars$/,
loader: "express-handlebars-loader",
options: {
app: app,
basePath: basePath,
contextCallback: contextCallback,
}
}]
},
plugins: []
};
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…