Laravel-mix: Template Engine loaders

Created on 7 Feb 2017  路  9Comments  路  Source: JeffreyWay/laravel-mix

Hi!

Any plans for adding handlebars, jade or markdown out of the box?

If not can anyone tell how to make work markdown for example?

Most helpful comment

@vladimir-yuldashev this is how I use Handlebars in my project, simple extend the webpackConfig with the handlebars-loader plugin.

mix.webpackConfig({
    module: {
        rules: [
            {
                test: /\.handlebars?$/,
                loader: 'handlebars-loader'
            }
        ]
    }
});

You should be able to do something similar with Markdown.

All 9 comments

No plans, but you can use mix.webpackConfig to add any custom configuration.

@vladimir-yuldashev this is how I use Handlebars in my project, simple extend the webpackConfig with the handlebars-loader plugin.

mix.webpackConfig({
    module: {
        rules: [
            {
                test: /\.handlebars?$/,
                loader: 'handlebars-loader'
            }
        ]
    }
});

You should be able to do something similar with Markdown.

@puredazzle Great, thanks!

To add another solution I'm using for handlebars.js:

let mix = require('laravel-mix');
let Handlebars = require("handlebars");
let path = require('path');
let fs = require('fs');

mix.extend('hbs', function(webpackConfig, ...args) {
    fs.writeFileSync(args[1], 'Handlebars.templates = Handlebars.templates || {};\n\n');

    Object.keys(args[0]).map(function(name, index) {
        let relPath = args[0][name];
        let template = fs.readFileSync(path.resolve(relPath), 'utf8');
        let compiled = Handlebars.precompile(template);
        fs.appendFileSync(args[1], 'Handlebars.templates[\''+name+'\'] = Handlebars.template('+compiled+');\n\n');
    });
});

mix.hbs({
        'array.key_name': 'path/to/handlebars/template.hbs',
    }, 'public/js/templates.hbs.js');

and in your JavaScript you can use it after this Handlebars.templates['array.key_name'](data). I bet that this could be improved - but it's working. :)

This is what worked for me, I needed one template compiled with different data to two different files:

let mix = require('laravel-mix')
const Task = require('laravel-mix/src/tasks/Task')
const FileCollection = require('laravel-mix/src/FileCollection')
const Handlebars = require('handlebars')
const fs = require('fs')
const spanish = require('./src/lang/spanish')
const english = require('./src/lang/english')

class CompileHandlebarsTask extends Task {
  run() {
    this.files = new FileCollection(this.data.template_path);
    this.compile()
  }
  onChange(updatedFile) {
    this.compile()
  }
  compile () {
    let template = Handlebars.compile(fs.readFileSync(this.data.template_path).toString())
    fs.writeFileSync(this.data.compiled_path, template(this.data.data))
    console.log(`Handlebars template ${this.data.compiled_path} compiled`)
  }
}
class Hbs {
  name () {
    return 'hbs';
  }
  register(template_path, compiled_path, data) {
    console.log('mix.hbs() was called ', template_path, '->', compiled_path);
    Mix.addTask(new CompileHandlebarsTask({ template_path, compiled_path, data }))
  }
}
mix.extend('hbs', new Hbs())
mix
  .hbs('src/home.hbs', 'dist/index.html', spanish)
  .hbs('src/home.hbs', 'dist/english.html', english)
  .copyDirectory('src/img', 'dist/img')
  .js('src/js/script.js', 'dist/js')
  .sass('src/css/styles.scss', 'dist/css')
  .sourceMaps();

I use laravel-mix as a stand-alone project and here I need handlebars with layout. So I built a small package for this, so handlebars can be easily integrated into Laravel Mix.

@ramsesmoreno Many thanks for your code snippet helped me a lot in developing the package.

laravel-mix-handlebars

@4ern thanks for your extension!

Does it work for you with browserSync? I can't get page automatically reloading then .hbs files is updated

Unfortunately not with mix.browserSync. Unfortunately, I don't know why. But it works if you load it directly over webpack.

// example
mix.webpackConfig(() => {
    return {
        plugins: [
            new BrowserSyncPlugin({
                host: 'localhost',
                port: 3003,
                watch: true,
                server: { baseDir: ['dist'] }
            })
        ]
    };
});

@ramsesmoreno Thank you so much for your snippet.
@4ern Thanks for your package as well. Unfortunately I can't get it working properly and have filed an issue under your repo with all the details.

Below is a modified version of @ramsesmoreno 's code to include support for Handlebars Layouts. This works in the same way as @4ern 's package. This is no where near perfect, but for now it works for me.
Files with _ prefixed get registered as partials. The name of the partial registered has the _ prefix stripped.
Example: _layout.hbs will get registered as layout

const mix = require('laravel-mix');
const Task = require('laravel-mix/src/tasks/Task');
const FileCollection = require('laravel-mix/src/FileCollection');
const Handlebars = require('handlebars');
const HandlebarsLayouts = require('handlebars-layouts');
const fs = require('fs');

Handlebars.registerHelper(HandlebarsLayouts(Handlebars));

class CompileHandlebarsTask extends Task {
    run() {
        this.files = new FileCollection(this.data.template_path);
        this.compile()
    }
    onChange(updatedFile) {
        this.compile()
    }
    compile () {
        let template = Handlebars.compile(fs.readFileSync(this.data.template_path).toString())
        fs.writeFileSync(this.data.compiled_path, template(this.data.data))
        console.log(`Handlebars template ${this.data.compiled_path} compiled`)
    }
}
class Hbs {
    constructor(tplPath) {
        console.log('mix extending hbs - register partials', tplPath);
        fs.readdirSync(tplPath).forEach(file => {
            if (file.charAt(0) == '_') {
                let partialName = file.substring(1).replace('.hbs', '');
                let partialPath = tplPath + file;

                console.log('handlebars registering partial', partialName, partialPath);

                Handlebars.registerPartial(
                    file.substring(1).replace('.hbs', ''),
                    fs.readFileSync(tplPath + file, 'utf8')
                );
            }
        });
    }

    name () {
        return 'hbs';
    }
    register(template_path, compiled_path, data) {
        console.log('mix.hbs() was called ', template_path, '->', compiled_path);
        Mix.addTask(new CompileHandlebarsTask({
            template_path,
            compiled_path,
            data
        }));
    }
}

mix.extend('hbs', new Hbs('src/hbs/'));
Was this page helpful?
0 / 5 - 0 ratings

Related issues

rderimay picture rderimay  路  3Comments

rlewkowicz picture rlewkowicz  路  3Comments

stefensuhat picture stefensuhat  路  3Comments

hasnatbabur picture hasnatbabur  路  3Comments

jpmurray picture jpmurray  路  3Comments