Webpack to only inject variables into HTML - javascript

I am using a basic example of the HtmlWebpackPlugin to inject variables into my HTML page. I do not have an index.js and do not want the bundle.js. How can I exclude the dist bundle.js and only output the updated HTML?
webpack.config.js:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
plugins: [
new HtmlWebpackPlugin({
template: 'index.html',
title: 'HTML Webpack Plugin',
bar: 'bar'
})
]
};
index.html (the template):
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title><%= JSON.stringify(htmlWebpackPlugin.options.title) %></title>
<script><script src="<%=htmlWebpackPlugin.options.favWord%>/socket.io.js"></script></script>
</head>
<body>
<h1>Hello, Webpack!</h1>
<p> My favorite word is <%= JSON.stringify(htmlWebpackPlugin.options.bar) %> </p>
</body>
</html>
The HTML page is generated perfectly, just I do not want the bundle.js generated.

Old question, but for anyone else with the same issue, you can set the inject option to false.
plugins: [
new HtmlWebpackPlugin({
template: 'index.html',
title: 'HTML Webpack Plugin',
bar: 'bar',
inject: false,
}),
];

Related

Html-webpack-plugin URIError: Failed to decode param '/%3C%=%20htmlWebpackPlugin.files.css%20%%3E'

I ran into a problem from the title. Initially, I only had index.html and everything was going great.
index.html
<!DOCTYPE html>
<html lang="ru" data-base="/"><!-- data-base="//assets.htmlacademy.ru/scripts/demos/"-->
<head>
<meta charset="utf-8">
<title>Test</title>
<link rel="stylesheet" href="<%= htmlWebpackPlugin.files.css %>">
</head>
<body>
<div class="layout loader" id="root"></div>
<script
id="init"
src="main.min.js"
></script>
</body>
</html>
and webpack.config.js
module.exports = () => {
const isProd = process.argv.includes("production");
const mode = isProd ? "production" : "development";
return {
mode,
entry: {
main: './src/main.tsx',
},
output: {
path: resolve(__dirname, 'dist'),
filename: '[name].min.js',
chunkFilename: '[name].bundle.js?hash=[contenthash]',
},
module: {
...
},
plugins: [
new HtmlWebpackPlugin({
template: 'public/index.html',
inject: false,
files: {
js: 'main.js',
css: 'main.css',
},
cache: false,
}),
...
],
devServer: {
historyApiFallback: true,
host: `0.0.0.0`,
port: process.env.PORT || 8080,
static: resolve('public'),
},
};
};
After that I created a new entry point new-index.html, similar like index.html, but new id. And new webpack config with changes only in html-webpack-plugin:
new HtmlWebpackPlugin({
template: 'public/new-index.html',
filename: 'new-index.html',
inject: false,
files: {
js: 'main.js',
css: 'main.css',
},
cache: false,
}),
At the end package.json scripts:
"start": "webpack serve --mode development",
"start:new-engine": "webpack serve --mode development --config=webpack.new-engine.js",
When I run npm start everything remains as before.
When I run npm run start:new-engine I get this error:
URIError: Failed to decode param '/%3C%=%20htmlWebpackPlugin.files.css%20%%3E'
at decodeURIComponent (<anonymous>)
And my styles isn't processed
DOM screen here
I updated webpack-dev-server and html-webpack-plugin to the latest. Trying run on 14.20 and 16.13 node.
What I'm doing wrong? Thx for ur time.

Webpack 5: How to inject CSS into head tag directly

I want to place CSS in the head tag of my HTML template directly instead of loading CSS into JS. But I can't find any reliable examples how to do this.
/* webpack.config.js */
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyPlugin = require("copy-webpack-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");
module.exports = {
mode: 'development',
entry: {
main: path.resolve(__dirname, 'src/script.js'),
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].[contenthash].js',
clean: true,
},
optimization: {
minimize: true,
minimizer: [
new CssMinimizerPlugin(),
],
},
module: {
rules: [
{test: /\.css$/, use: ['style-loader', 'css-loader']},
],
},
plugins: [
new HtmlWebpackPlugin({
title: 'My optimized file',
filename: 'index.html',
template: path.resolve(__dirname, 'src/temp.html'),
templateParameters: {
'style': '[name].[contenthash].css' // doesn't bind with CopyPlugin
},
}),
new CopyPlugin({
patterns: [
{ from: path.resolve(__dirname, 'src/style.css'), to: '[name].[contenthash].css' },
],
}),
],
};
And my HTML template src/temp.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><%= htmlWebpackPlugin.options.title %></title>
<link rel="stylesheet" href="<%= style %>">
</head>
<body>
<h1>Hello there!</h1>
</body>
</html>
Now as the result in my compiled HTML file dist/index.html I get this:
<head>
...
<link rel="stylesheet" href="[name].[contenthash].css">
</head>
After webpack build href attribute has just a wapback parameter [name].[contenthash].css instead of compiled CSS filename style.347572c74109b5f9ef4e.css.
And my folder structure:
dist
├─ index.html
├─ main.3d522b68c880128437a8.js
└─ style.347572c74109b5f9ef4e.css
src
├─ script.js
├─ style.css
└─ temp.html
webpack.config.js
package.json
For now I found temporary solution to this problem. I've just tried mini-css-extract-plugin and looked at example from html-webpack-plugin.
/* webpack.config.js */
...
module: {
rules: [
{ test: /\.css$/, use: [MiniCssExtractPlugin.loader, 'css-loader'] },
]
},
plugins: [
new HtmlWebpackPlugin({
template: 'template.html'
}),
new MiniCssExtractPlugin({ filename: 'style.css' })
]
But to make it work you must require CSS in JS file:
/* script.js */
require('./style.css');
...
But I'm still looking for how to do it without hardcoding CSS in JS using only webpack.config.js file since style.css has nothing to do with script.js in my case.

Webpack serve does not include exports on var

I'm working on a project using webpack, I'm trying to use the webpack-dev-serve package to preview my changes. However when I start the server and load the page the object created by webpack does not have the functions on it Uncaught TypeError: test.a is not a function, when I console log the object webpack creates I can see its an empty object Object { }. Using the exact same webpack config to build the package and including it on my page works fine.
Here is my webpack.config:
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
mode: "development",
entry: "./src/index.js",
target: "web",
output: {
filename: "test.js",
library: {
name: "test",
type: "var"
}
},
module: {
rules: [{
exclude: /node_modules/
}]
},
resolve: {
symlinks: false
},
plugins: [
new HtmlWebpackPlugin({
title: "Development",
template: "./src/index.html",
scriptLoading: "blocking",
inject: "head"
})
]
};
My index.js is very simple:
export function a(){
console.log("A has been called");
}
My index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<script>
console.log(test);
test.a();
</script>
</body>
</html>
I found a fix from the problem here:
WebPack output.library.type var is undefined
After adding injectClient: false to devServer, and removing scriptloading and inject from the HtmlWebpackPlugin config, webpack serve now works as expects.

How to inject css styles from file to WebComponent

I am wondering is it possible to inject .css styles imported from file to WebComponent (If yes then please tell me how can I achieve this). I used Webpack style-loader to load .css styles inside .js a file but then I do not know how (or is it possible) to inject those styles into WebComponent the template.
I know that I can export styles from .js file declared in template string but it is not a solution which I am looking for.
I created a repository with simple example which you can find here: inject-css-from-file. I also include those files here:
index.html :
<!DOCTYPE html>
<html>
<head>
<meta charset='utf-8'>
<meta http-equiv='X-UA-Compatible' content='IE=edge'>
<title>Page Title</title>
<meta name='viewport' content='width=device-width, initial-scale=1'>
</head>
<body>
<kk-app></kk-app>
</body>
</html>
index.js :
import style from "./index.css";
const template = `
<style>${style}</style>
<div>
<p>Example component</p>
</div>
`;
export class App extends HTMLElement {
constructor() {
super()
this.attachShadow({ mode: 'open' });
this.shadowRoot.innerHTML = template;
}
}
customElements.define('kk-app', App);
index.css :
p {
color: red;
}
webpack.config.js :
const HTMLWebpackPlugin = require('html-webpack-plugin');
const path = require('path');
module.exports = {
mode: 'production',
entry: './index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
],
},
resolve: {
extensions: ['.js'],
},
devServer: {
contentBase: path.join(__dirname, 'dist'),
},
plugins: [
new HTMLWebpackPlugin({
template: path.resolve(__dirname, 'index.html'),
filename: 'index.html',
}),
]
};
So the solution for that was to remove style-loader from webpack.config.js. Rule for .css file should look like that:
rules: [
{
test: /\.css$/,
use: ['css-loader'],
},
],
I do not know why but style-loader changed this .css styles into an object.
P.S. If you are using MiniCssExtractPlugin.loader it will cause same problem

How to use Webpack 4 SplitChunksPlugin with HtmlWebpackPlugin for Multiple Page Application?

I'm trying to utilize the SplitChunksPlugin to produce separate bundles per each page/template in a MPA. When I use the HtmlWebpackPlugin, I get an html file for each page with a script tag pointing to the correct bundle. That is great! However, the trouble I'm having is with my vendor files. I want separate html files to point to only the vendor bundles they need. I can't get each separate html file to point to the correct vendor bundles when the SplitChunksPlugin creates multiple vendor bundles. The bundles produced are:
home.bundle.js
product.bundle.js
cart.bundle.js
vendors~cart~home~product.bundle.js
vendors~cart~product.bundle.js
So basically the home template should reference home.bundle.js, vendors~cart~home~product.bundle.js, and not the second vendor bundle. Only the cart and product templates should reference both vendor bundles. I am utilizing the chunks option for the HtmlWebpackPlugin but can't get it to pull the correct vendor bundles unless I explicitly reference the name of it like so:
chunks: ['vendors~cart~home~product.bundle','home']
But this kinda defeats the purpose of dynamically rendering your script tags. I've tried creating a vendor entry point but this lumps all my vendors together.
Is there some simple config I'm missing?
My webpack.config.js:
const path = require('path');
const webpack = require('webpack');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const Visualizer = require('webpack-visualizer-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
mode: 'development',
devtool: 'cheap-module-eval-source-map',
entry: {
home: './src/js/page-types/home.js',
product: './src/js/page-types/product.js',
cart: './src/js/page-types/cart.js'
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist/js')
},
optimization: {
splitChunks: {
chunks: 'all'
}
},
plugins: [
new CleanWebpackPlugin(['dist']),
new Visualizer(),
new HtmlWebpackPlugin({
filename: 'home.html',
chunks: ['vendors','home']
}),
new HtmlWebpackPlugin({
filename: 'product.html',
chunks: ['vendors','product']
}),
new HtmlWebpackPlugin({
filename: 'cart.html',
chunks: ['vendors~cart~product','cart']
}),
], ...
My js modules:
/* home.js */
import jQuery from 'jquery';
import 'bootstrap';
cart and product also reference the react library:
/* cart.js */
import jQuery from 'jquery';
import 'bootstrap';
import React from 'react';
import ReactDOM from 'react-dom';
/* product.js */
import jQuery from 'jquery';
import 'bootstrap';
import React from 'react';
import ReactDOM from 'react-dom';
Example html output home.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Webpack App</title>
</head>
<body>
<script type="text/javascript" src="home.bundle.js"></script></body>
</html>
Use version4 of html-webpack-plugin (which is in beta now), and only include the entry chunk in the chunks option.
npm i -D html-webpack-plugin#next
and
module.exports = {
new HtmlWebpackPlugin({
filename: 'home.html',
chunks: ['home']
}),
new HtmlWebpackPlugin({
filename: 'product.html',
chunks: ['product']
}),
new HtmlWebpackPlugin({
filename: 'cart.html',
chunks: ['cart']
}),
};
This will include related chunks automatically.
One option is to manually create your vendor chunks and then include whichever of those chunks needed for a page in the chunks option of HtmlWebpackPlugin.
webpack.config.js:
const path = require('path');
const webpack = require('webpack');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const Visualizer = require('webpack-visualizer-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
mode: 'development',
devtool: 'cheap-module-eval-source-map',
entry: {
home: './src/js/page-types/home.js',
product: './src/js/page-types/product.js',
cart: './src/js/page-types/cart.js'
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist/js')
},
optimization: {
splitChunks: {
cacheGroups: {
'vendor-bootstrap': {
name: 'vendor-bootstrap',
test: /[\\/]node_modules[\\/](jquery|bootstrap)[\\/]/,
chunks: 'initial',
priority: 2
},
'vendor-react': {
name: 'vendor-react',
test: /[\\/]node_modules[\\/]react.*?[\\/]/,
chunks: 'initial',
priority: 2
},
'vendor-all': {
name: 'vendor-all',
test: /[\\/]node_modules[\\/]/,
chunks: 'initial',
priority: 1
},
}
}
},
plugins: [
new CleanWebpackPlugin(['dist']),
new Visualizer(),
new HtmlWebpackPlugin({
filename: 'home.html',
chunks: ['vendor-bootstrap', 'vendor-all', 'home']
}),
new HtmlWebpackPlugin({
filename: 'product.html',
chunks: ['vendor-bootstrap', 'vendor-react', 'vendor-all', 'product']
}),
new HtmlWebpackPlugin({
filename: 'cart.html',
chunks: ['vendor-bootstrap', 'vendor-react', 'vendor-all', 'cart']
}),
], ...
The vendor-all chunk is to catch any other vendor libraries that are not included in the other chunks.

Categories