Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I'm trying to migrate an old express site to webpack, but don't wanna rework all the layout tempaltes which use express-handlebars. Is it possible to use express-handlebars with webpack?

handlebars-loader seems not to support the layout concept of express-handlebars, so is no help here.

question from:https://stackoverflow.com/questions/65917650/webpack-with-express-handlebars

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
1.7k views
Welcome To Ask or Share your Answers For Others

1 Answer

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: []
};

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...