Welcome toVigges Developer Community-Open, Learning,Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.4k views
in Technique[技术] by (71.8m points)

webpack with express-handlebars

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to Vigges Developer Community for programmer and developer-Open, Learning and Share
...