I'm using pug as my Node.JS view engine.
And I'm bundling my javascript files using webpack with hashname for cache busting.
The problem here is that I don't know how to include the bundled javascript file name in my pug template because every time it generates a new hash name.
How can I get the hash name generated from webpack and include it in my pug file?
This is how it should include the script file:
doctype html
html
include _head
body
script(src='/_bundle/main.649c4c4e6c8076189257.js')
My webpack.config.js
const path = require("path")
const HtmlWebpackPlugin = require("html-webpack-plugin")
module.exports = {
mode: "production",
entry: "./src/_public/js/index.js",
output: {
filename: "main.[contenthash].js",
path: path.resolve(__dirname, "src/_public/_bundle"),
},
module: {
rules: [
{
test: /\.scss$/,
use: [
"style-loader", "css-loader", "sass-loader",
],
},
],
},
plugins: [
new HtmlWebpackPlugin({
filetype: "pug",
}),
new HtmlWebpackPlugin({
filename: "./src/views/base.pug",
}),
],
}
Configure HtmlWebpackPlugin and HtmlWebpackPugPlugin properly:
const path = require("path")
const HtmlWebpackPlugin = require("html-webpack-plugin")
const HtmlWebpackPugPlugin = require('html-webpack-pug-plugin');
module.exports = {
mode: "production",
entry: "./src/_public/js/index.js",
output: {
filename: "main.[contenthash].js",
path: path.resolve(__dirname, "src/_public/_bundle"),
},
module: {
rules: [
{
test: /\.scss$/,
use: [
"style-loader", "css-loader", "sass-loader",
],
},
],
},
plugins: [
new HtmlWebpackPugPlugin(),
new HtmlWebpackPlugin({
template: './src/views/base.pug',
filename: 'layout.pug',
}),
],
}
Install npm i HtmlWebpackPugPlugin. You will find the js and css references in the layout.pug file.
Actual solution for 2022.
Install the pug-plugin:
npm i -D pug-plugin
Using the pug-plugin:
the Webpack entry-point is the Pug file
all source scripts (JS/TS) can be loaded via require() in Pug
all source styles (CSS/SCSS) can be loaded via require() in Pug
Webpack config for Pug + JS + SCSS:
const path = require('path');
const PugPlugin = require('pug-plugin');
module.exports = {
output: {
path: path.join(__dirname, 'dist/'),
filename: 'js/[name].[contenthash:8].js' // output hashed filename of JS
},
entry: {
// define Pug files in entry:
index: './src/views/index.pug', // => index.html
about: './src/views/about/index.pug' // => about.html
// ...
},
plugins: [
// enable using Pug files as entry point
new PugPlugin({
extractCss: {
filename: 'css/[name].[contenthash:8].css' // output hashed filename of CSS
},
})
],
module: {
rules: [
{
test: /\.pug$/,
loader: PugPlugin.loader, // the Pug loader
},
{
test: /\.(css|sass|scss)$/,
use: ['css-loader', 'sass-loader']
},
],
},
};
Pug file ./src/views/index.pug:
doctype html
html
head
//- load source styles via require()
link(href=require('./path/to/scss/styles.scss') rel='stylesheet')
body
h1 Hello Pug!
//- load source scripts via require()
script(src=require('./path/to/js/index.js'))
Generated HTML:
<html>
<head>
<link href="/css/styles.f57966f4.css" rel="stylesheet">
</head>
<body>
<h1>Hello Pug!</h1>
<script src="/js/index.b855d8f4.js"></script>
</body>
</html>
Related
Im stuck and can't get to work my webpack configuration for loading images with src attribute from HTML. I cloned a repo with full setup of webpack, but I know there is a way to simply customize and load images directly from HTML.
Webpack.config.js file:
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
module.exports = {
entry: {
main: "./src/index.js"
},
output: {
path: path.join(__dirname, "../build"),
filename: "[name].bundle.js"
},
mode: "development",
devServer: {
contentBase: path.join(__dirname, "../build"),
compress: true,
port: 3000,
overlay: true
},
devtool: "cheap-module-eval-source-map",
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader" // transpiling our JavaScript files using Babel and webpack
}
},
{
test: /\.(sa|sc|c)ss$/,
use: [
"style-loader", // creates style nodes from JS strings
"css-loader", // translates CSS into CommonJS
"postcss-loader", // Loader for webpack to process CSS with PostCSS
"sass-loader" // compiles Sass to CSS, using Node Sass by default
]
},
{
test: /\.(png|svg|jpe?g|gif)$/,
use: [
{
loader: "file-loader", // This will resolves import/require() on a file into a url
and emits the file into the output directory.
options: {
name: "[name].[ext]",
outputPath: "assets",
}
},
]
},
{
test: /\.html$/,
use: {
loader: "html-loader",
options: {
attrs: ["img:src", ":data-src"],
minimize: true
}
}
}
]
},
plugins: [
// CleanWebpackPlugin will do some clean up/remove folder before build
// In this case, this plugin will remove 'dist' and 'build' folder before re-build again
new CleanWebpackPlugin(),
// The plugin will generate an HTML5 file for you that includes all your webpack bundles
in
the body using script tags
new HtmlWebpackPlugin({
template: "./src/index.html",
filename: "index.html"
}),
Before this project I was able to make that images would simply load from HTML but now ironicly im stuck and can't get this working.
Any help will be very appriciated.
When loading a image directly form HTML, I get the following error:
Error: Child compilation failed:
Module not found: Error: Can't resolve '
./src/assets/images/portret.jpg' in '/home/viktoras/www/sites/painter-new/src':
You can do this:
<img src="<%=require('./src/assets/logo.png')%>">
Plugin Conf
$new HtmlWebpackPlugin({
filename: 'index.html',
template: 'index.html'
}),
I want to load images directly from HTML with Webpack 4 and add custom Javascript files to my HTML file but both files inspected at console show Not found 404.
How to properly load images and Javascipt files with Webpack 4?
My Webpack 4 config file:
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
module.exports = {
entry: {
main: "./src/index.js"
},
output: {
path: path.join(__dirname, "../build"),
filename: "[name].bundle.js"
},
mode: "development",
devServer: {
contentBase: path.join(__dirname, "../build"),
compress: true,
port: 3000,
overlay: true
},
devtool: "cheap-module-eval-source-map",
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader" // transpiling our JavaScript files using Babel and webpack
}
},
{
test: /\.(sa|sc|c)ss$/,
use: [
"style-loader", // creates style nodes from JS strings
"css-loader", // translates CSS into CommonJS
"postcss-loader", // Loader for webpack to process CSS with PostCSS
"sass-loader" // compiles Sass to CSS, using Node Sass by default
]
},
{
test: /\.(png|svg|jpe?g|gif)$/,
use: [
{
loader: "file-loader", // This will resolves import/require() on a file into a url and emits the file into the output directory.
options: {
name: "[name].[ext]",
outputPath: "assets",
}
},
]
},
{
test: /\.html$/,
use: {
loader: "html-loader",
options: {
attrs: ["img:src", ":data-src"],
minimize: true
}
}
}
]
},
plugins: [
// CleanWebpackPlugin will do some clean up/remove folder before build
// In this case, this plugin will remove 'dist' and 'build' folder before re-build again
new CleanWebpackPlugin(),
// The plugin will generate an HTML5 file for you that includes all your webpack bundles in the body using script tags
new HtmlWebpackPlugin({
template: "./src/index.html",
filename: "index.html"
}),
]
My webpack.prod.js file:
const path = require("path");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
const CompressionPlugin = require("compression-webpack-plugin");
const TerserJSPlugin = require("terser-webpack-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-
plugin");
const BrotliPlugin = require("brotli-webpack-plugin");
const PurgecssPlugin = require('purgecss-webpack-plugin');
const glob = require("glob");
module.exports = {
entry: {
main: "./src/index.js"
},
output: {
path: path.join(__dirname, "../build"),
filename: "[name].[chunkhash:8].bundle.js",
chunkFilename: "[name].[chunkhash:8].chunk.js"
},
mode: "production",
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader" // transpiling our JavaScript files using
Babel and webpack
}
},
{
test: /\.(sa|sc|c)ss$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader", // translates CSS into CommonJS
"postcss-loader", // Loader for webpack to process CSS with
PostCSS
"sass-loader" // compiles Sass to CSS, using Node Sass by
default
]
},
{
test: /\.(png|svg|jpe?g|gif)$/,
use: [
{
loader: "file-loader", // This will resolves import/require()
on a file into a url and emits the file into the output directory.
options: {
name: "[name].[ext]",
outputPath: "assets/"
}
},
]
},
{
test: /\.html$/,
use: {
loader: "html-loader",
options: {
attrs: ["img:src", ":data-src"],
minimize: true
}
}
}
]
},
optimization: {
minimizer: [new TerserJSPlugin(), new OptimizeCSSAssetsPlugin()],
splitChunks: {
cacheGroups: {
commons: {
test: /[\\/]node_modules[\\/]/,
name: "vendors",
chunks: "all"
}
},
chunks: "all"
},
runtimeChunk: {
name: "runtime"
}
},
plugins: [
// CleanWebpackPlugin will do some clean up/remove folder before build
// In this case, this plugin will remove 'dist' and 'build' folder
before re-build again
new CleanWebpackPlugin(),
// PurgecssPlugin will remove unused CSS
new PurgecssPlugin({
paths: glob.sync(path.resolve(__dirname, '../src/**/*'), { nodir:
true })
}),
// This plugin will extract all css to one file
new MiniCssExtractPlugin({
filename: "[name].[chunkhash:8].bundle.css",
chunkFilename: "[name].[chunkhash:8].chunk.css",
}),
// The plugin will generate an HTML5 file for you that includes all
your webpack bundles in the body using script tags
new HtmlWebpackPlugin({
template: "./src/index.html",
filename: "index.html"
}),
My project nesting:
--Build
--src
----html
----js
----styles
----assets
------images
I want that files would load simply:
<img src="assets/images/myimage.jpg">
<srcipt src="js/custom.js"></script>
Any help would be appreciated.
Ironically this is my second project with Webpack 4 and this time I can't fix this issue, the first time there was no problem.
This is how img work in Webpack:
<img src=require("./assets/images/myimage.jpg")>
if you use "require" with file-loader, you need to add default.
<img src=require("./assets/images/myimage.jpg").default>
For script tag, src should be your output bundle.js file; because Webpack writes all the code into the bundle.js with the help of Babel. So when browser request html, browser will have only one Javascript file which is the bundle to download. That is the whole point of bundle, smaller bundle.js is better for performance.
// According to your Webpack config, it is main.bundle.js
<srcipt src="main.bundle.js"></script>
but in order to browser to use this main.bundle.js, it has to be publicly available. So you need express to define the public folder, when browser looks for main.bundle.js, you app will be looking into the public folder and if that file exists, it will ship it to the browser.
const express = require("express");
const server = express();
const staticMiddleware = express.static("build");
server.use(staticMiddleware);
Recently, I managed to use ejs-loader with Webpack 4. But, I started to get trouble with the script tag that webpack create into index.html when it launch : <script type="text/javascript" src="main.js"></script>. His src is not right because if we look my build I need src="/dist/main.js" :
node_modules/
dist/
index.html
main.js
publics/
src/
views/
server.js
package.json
webpack.config.js
What I need to add into my webpack.congfig.js to create a src like I want ?
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
devtool: 'source-map',
module: {
rules: [{
test: /\.ejs$/,
use: ['ejs-loader']
}]
},
plugins: [
new HtmlWebpackPlugin({
template: './views/pages/index.ejs'})
]
}
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
devtool: 'source-map',
output: {
publicPath: '/dist/' // <---- this
},
module: {
rules: [{
test: /\.ejs$/,
use: ['ejs-loader']
}]
},
plugins: [
new HtmlWebpackPlugin({
template: './views/pages/index.ejs'})
]
}
I have created a project using react and flux architecture. Need to chunk the bundle.js file because by combining all the files it is creating a huge js file of 4mb which is causing problem in downloading on slow network so how to chunk the js file so that only the required libraries are included when a page opens
I am using webpack 1.x
my directory structure is
webpack.config.js file
var path = require('path');
var webpack = require('webpack');
module.exports = {
devtool: 'cheap-module-source-map',
entry: [
'./src/index'
],
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js',
publicPath: ''
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.optimize.CommonsChunkPlugin({
// names: ["app", "subPageA"]
// (choose the chunks, or omit for all chunks)
children: true,
// (use all children of the chunk)
async: true,
// (create an async commons chunk)
// minChunks: 3,
// (3 children must share the module before it's separated)
})
],
module: {
loaders: [{
test: /\.js$/,
loaders: ['react-hot', 'babel'],
include: path.join(__dirname, 'src')
}, {
test: /\.css$/,
exclude: /\.useable\.css$/,
loader: "style-loader!css-loader"
}, {
test: /\.useable\.css$/,
loader: "style-loader/useable!css-loader"
}, {
test: /\.png$/,
loaders: ["url-loader?mimetype=image/png"]
}, {
test: /\.(png|woff|woff2|eot|ttf|svg)$/,
loader: 'url-loader?limit=100000'
}]
}
};
server.js file
var webpack = require('webpack');
var WebpackDevServer = require('webpack-dev-server');
var config = require('./webpack.config');
new WebpackDevServer(webpack(config), {
publicPath: config.output.publicPath,
hot: true,
historyApiFallback: true
}).listen(3000, 'localhost', function(err, result) {
if (err) {
return console.log(err);
}
console.log('Listening at http://localhost:3000/');
});
index.html file
<html>
<head>
<title>Project</title>
</head>
<body>
<div id="app" />
<script src="bundle.js" type="text/javascript"></script>
</body>
</html>
When you need a particular module, that is not required on the initial load you can use
require.ensure(["module-a", "module-b"], function() {
var a = require("module-a");
// ...
});
That way it only gets loaded when you need it, thus decreasing your bundle size.
If you use routes and react-router you can use per route code splitting as described in this article
http://moduscreate.com/code-splitting-for-react-router-with-es6-imports/
Im my experience, typically with webpack-optimize-chunk-plugin, you split your projects code into a vendor.js and a bundle.js. like this:
module.exports = {
entry:{
vendor: ["react", "react-dom"], // list all vender libraries here
app: ['./path/to/entry.js']
},
output: {
path: path.join(__dirname, './public'),
filename:'bundle.js'
},
plugins: [
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.optimize.CommonsChunkPlugin("vendor", "vendor.js")
]
}
So this would output a bundle.js and a vendor.js. I haven't seen webpack-optimize-chunk-plugin used in the way you described. (it would be very cool if possible).
Also I would check out all the other webpack optimization plugins to also help with the over all file size. (i.e. DedupePlugin, UglifyJsPlugin, OccurenceOrderPlugin...). More info here. Also here is an example of multi entry point that you may find helpful. Best of luck.
I need to inject a Stylus bundle into the html file in webpack config file.
I already inject the js bundle using HtmlWebpackPlugin and I thought that it was possible to inject a compiled stylus bundle using this plugin too.
Below is my current webpack.config.js file:
var HtmlWebpackPlugin = require('html-webpack-plugin');
var HtmlWebpackPluginConfigForJS = new HtmlWebpackPlugin({
template: __dirname + '/app/index.html',
filename: 'index.html',
inject: 'body'
});
var HtmlWebpackPluginConfigForStyles = new HtmlWebpackPlugin({
template: __dirname + '/app/index.html',
filename: 'index.styl',
inject: 'head'
});
module.exports = {
entry: [
'babel-polyfill',
'./app/index.js'
],
output: {
path: __dirname + '/dist',
filename: 'index_bundle.js'
},
devtool: 'source-map',
cache: true,
module: {
loaders: [
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
loader: 'babel-loader'
},
{
test: /\.styl$/,
exclude: /(node_modules|bower_components)/,
loader: 'style-loader!css-loader!stylus-loader'
}
]
},
plugins: [
HtmlWebpackPluginConfigForJS,
HtmlWebpackPluginConfigForStyles
],
stylus: {
use: [require('nib')(), require('rupture')()],
import: ['~nib/lib/nib/index.styl', '~rupture/rupture/index.styl']
}
}
The only way I got the styles work was to add require('./index.styl); in my javascript file, but this is not what I need.
HtmlWebpackPluginConfigForJS works fine and successfuly injects the index_bundle.js file in my index.html. But it doesn't work with the styles.
Could you please help me to improve my webpack config to make it inject my stylus bundle correctly?
By default HtmlWebpackPlugin injects css files, from the docs:
If you have any css assets in webpack's output (for example, css extracted with the ExtractTextPlugin) then these will be included with tags in the HTML head.
So you can use ExtractTextPlugin to extract all your styles into one or several files. But to extract you should require your index.styl in your main index.js so that loader could see and make extraction.