Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Webpack: chaining loaders

Tags:

webpack

Everything works fine when I use ejs-loader and html-loader separately:

<body>
    <%= require('./header.html')({x:1})  %>
</body>

// compiles to:

<body>
    <header><div>1</div></header>
</body>

But when I chain them, I'm getting js code instead of html:

module.exports = function (obj) {
obj || (obj = {});
var __t, __p = '';
with (obj) {
__p += '\n<body>\n  ' +
((__t = ( require('./header.html')({x:1})  )) == null ? '' : __t) +
'\n</body>';

}
return __p
}

What is happening and how can I fix it?

Here is my config:

const config = {
    //...
    module: {
        rules: [
            {
                test: /\.html$/,
                use: ['html-loader', 'ejs-loader']
            }
        ]
    },
    //...
    plugins: [
        new HtmlWebpackPlugin({
            filename: 'index.html',
            template: './src/index.html',
        })
    ]

}
like image 623
dodd0ro Avatar asked Oct 31 '25 21:10

dodd0ro


1 Answers

I am now struggling with the same problem and found the answer.

First, we need to understand how loaders work. In short: they take whatever file types as input, but output from a loader is always JS, which webpack then executes to get final output.

Both ejs-loader and html-loader expect html code as their input. When we chain loaders, the second loader receives not HTML, but javascript which was returned by the first loader. So we need to make HTML from that JS. To do so I wrote a simple loader which needs to be put between html- and ejs- loader.

Let's call it 'loader.js':

module.exports = function (source) {
    let x = eval(source);
    let z = x();
    return z;
}

Webpack config then will be:

module: {
    rules: [
        {
            test: /\.html$/,
            use: ['html-loader', path.resolve('loader.js'), 'ejs-loader']
        }
    ]
},

Important note: The order or loaders matter. If i swap ejs and html loaders in the chain, then eval fails because html-loader returns js code which has other imports which eval cannot resolve. However ejs-loader returns pure self-contained code which evaluates with eval() successfully.

So, because loaders get executed in reverse order, we put ejs first (meaning - at the end of array), then our intermediate loader, and the html-loader goes last (at the beginning of array)

UPDATE: There is a ready-to-use loader which does this job, called extract-loader. Simple eval will fail in many cases while extract-loader always works fine.

like image 110
Phantom Lord Avatar answered Nov 04 '25 11:11

Phantom Lord



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!