I want to use the HTMLWebpackPlugin to take my index.ejs
template file, insert my bundled assets, and output a final index.ejs
file.
This example has a EJS variable <%= API_URL %>
, but webpack is interpreting it.
How can I stop webpack from substituting the variable?
Starting "template":
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Monitor</title>
<script>
window.config = {
API_URL: "<%= API_URL %>"
}
</script>
</head>
<body>
<div class="container"></div>
</body>
</html>
When you try to run webpack:
ERROR in Template execution failed: ReferenceError: API_URL is not defined
Desired result index.ejs: (has bundled assets and EJS var)
Monitor window.config = { API_URL: "<%= API_URL %>" }
webpack.config.js
var webpack = require('webpack');
var path = require('path');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
entry: {
bundle: './src/index.js'
},
output: {
path: path.join(__dirname, 'dist'),
filename: '[name].[chunkhash].js'
},
module: {
rules: [
{
test: /\.js$/,
use: 'babel-loader',
exclude: /node_modules/
},
{
// CSS is imported in app.js.
test: /\.scss$/,
use: ExtractTextPlugin.extract({
fallbackLoader: 'style-loader',
loader: ["css-loader", "sass-loader"]
})
}]
},
plugins: [
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify(process.env.NODE_ENV),
'API_URL': JSON.stringify(process.env.API_URL)
}
}),
new HtmlWebpackPlugin({
template: 'src/index.ejs',
inject: true
}),
new ExtractTextPlugin("styles.css")
],
};
The HtmlWebpackPlugin simplifies creation of HTML files to serve your webpack bundles. This is especially useful for webpack bundles that include a hash in the filename which changes every compilation. You can either let the plugin generate an HTML file for you, supply your own template using lodash templates, or use your own loader.
Whilst most people use Webpack primarily for their JS scripts, there's always one final part of deploying that is forgotten: the HTML.
You can either let the plugin generate an HTML file for you, supply your own template using lodash templates, or use your own loader. The plugin will generate an HTML5 file for you that includes all your webpack bundles in the body using script tags.
This will generate a file dist/index.html containing the following: If you have multiple webpack entry points, they will all be included with <script> tags in the generated HTML.
Here is a really bad hacky solution, and I hope someone else has a real answer / understanding of how to do this.
In your template file (index.ejs), do this:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Monitor</title>
<script>
window.config = {
API_URL: "<%= htmlWebpackPlugin.options.API_URL_TEMPLATE_VAR %>"
}
</script>
</head>
<body>
<div class="container"></div>
</body>
</html>
In your webpack config, do this (the relevant part is the new HtmlWebpackPlugin where I define a variable.:
plugins: [
// Define environment variables that are accessible inside of app javascript.
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify(process.env.NODE_ENV)
}
}),
// Adds bundled file links to the index.html
new HtmlWebpackPlugin({
// The input file name
template: 'src/index.prod.ejs',
// Injects scripts into the <body>
inject: true,
// This is so hacky. I inject a string so the built .ejs file has this template var. Lets us set api_url when server is started instead of at bundle time.
API_URL_TEMPLATE_VAR: '<%= process.env.API_URL %>',
// The output file name
filename: 'index.ejs'
}),
new ExtractTextPlugin("styles.css")
],
Because I defined API_URL_TEMPLATE_VAR
, when html-webpack-plugin evaluates it, it will print out <%= process.env.API_URL %>
into the final template.
Hacky, but works. Not accepting my own answer / waiting for a better answer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With