How can I remove duplicate JS bundle created by webpack4? - javascript

I am trying to create JavaScript Library and CSS bundle (extracting all CSS used in a single file) using webpack 4.
My webpack.config.js file configuration is as below:
var path = require("path");
var HtmlWebpackPlugin = require("html-webpack-plugin"); // Require to generate html file
var MiniCssExtractPlugin = require("mini-css-extract-plugin"); // Require to generate css file
module.exports = {
entry: __dirname + "/src/app/index.js", // webpack entry point. Module to start building dependency graph
output: {
path: path.join(__dirname, "dist"), // Folder to store generated bundle
filename: "chart.min.js", // Name of generated bundle after build
library: ["Chart"],
libraryTarget: "umd"
},
module: { // where we defined file patterns and their loaders
rules: [
{
test: /\.js$/,
use: "babel-loader",
exclude: [
/node_modules/
]
},
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader"
],
exclude: [
/node_modules/
]
}
]
},
optimization: {
splitChunks: {
cacheGroups: {
styles: {
name: "chart",
test: /\.css$/,
chunks: "all",
enforce: true
}
}
}
},
plugins: [ // Array of plugins to apply to build chunk
new HtmlWebpackPlugin({
template: __dirname + "/src/public/index.html",
inject: "body"
}),
new MiniCssExtractPlugin({
filename: "[name].css"
})
],
devServer: { // configuration for webpack-dev-server
contentBase: "./src/public", //source of static assets
port: 7700 // port to run dev-server
}
};
By running above code, I am getting following files in my dist folder
"1.chart.min.js", "chart.min.js", "chart.css", "index.html"
May I know why I am getting "1.chart.min.js" file and How can I stop generating same?

You may like to clean the output path using clean-webpack-plugin

Related

CSS and other assets from the public folder not getting included in the build

In my public folder I have index.html, the css file and the fonts.
In my source folder I have the index.js file.
This is how the folder structure looks
I have setup the webpack.config.js file like this
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: path.join(__dirname, 'src', 'index.js'),
output: {
path: path.resolve(__dirname, 'dist'),
publicPath: '',
filename: 'bundle.js',
},
mode: 'development',
module: {
rules: [
{
test: /\.?js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env', '#babel/preset-react'],
plugins: ['#babel/transform-runtime'],
},
},
},
{
test: /\.css$/i,
exclude: /node_modules/,
use: ['style-loader', 'css-loader'],
},
{
test: /\.(png|jp(e*)g|svg|gif)$/,
exclude: /node_modules/,
use: 'file-loader',
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
exclude: /node_modules/,
use: 'url-loader',
},
],
},
plugins: [
new HtmlWebpackPlugin({
template: path.join(__dirname, 'public', 'index.html'),
publicPath: './',
}),
],
};
Everything is working fine in dev, but when I create the build the files inside the public folder except the index.html are not included.
The dist folder after the build
You can use the copyWebpackPlugin to move the files from /public to the new build destination (/dist).
Example:
const CopyPlugin = require("copy-webpack-plugin");
module.exports = {
plugins: [
new CopyPlugin({
patterns: [
{ from: "./public/*", to: "./" },
],
}),
],
};
However, how are you using this CSS and Font files? Webpack should also help to pack your CSS correctly along with the rest of your code. I recommend you to follow the oficial documentation: Webpack.

How to set image links for a multipage webpack configuration when the landing page is not in a subdirectory?

I am trying my hand at a multipage webpack configuration and have a question about how to load images differently for a landing page compared to the other pages on the site. The landing page builds to the root directory, while the other pages build to their respective subfolders.
Webpack appends the correct relative path ../images/ for the other pages, however the landing page needs to remain as images/, as it is located on the root directory along with the images folder.
How can I configure webpack such that <img src="images/00.jpg"> stays the same for the landing page, but is updated to <img src="../images/00.jpg"> for all other pages?
Here is the source folder:
/ src /
-home.html
-about.html
js/
-home.js
-about.js
images/
-00.jpg
-01.jpg
scss/
-style.scss
Here is the build folder webpack generates:
/ public_html /
-index.html // relative links in this file become broken :(
-bundle.js
about/
-index.html
-bundle.js
images/
-00.jpg
-01.jpg
css/
-style.css
Finally, here is the webpack configuration. Please excuse the wall of code, I decided to include the entire configuration in case there is a better way to set this up.
// webpack.config.js
const webpack = require('webpack');
const path = require('path');
const HtmlWebPackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
entry: {
home: './src/js/home.js',
about: './src/js/about.js',
},
output: {
filename: (pathData) => {
return pathData.chunk.name === 'home' ? 'bundle.js' : '[name]/bundle.js';
},
path: path.resolve(__dirname, 'public_html')
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},{
test: /\.html$/,
use: [
{
loader: "html-loader",
options: { minimize: true }
}
]
},{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, "css-loader"]
},{
test: /\.sass$|\.scss$/,
use: [
MiniCssExtractPlugin.loader,
{ loader: 'css-loader' },
{ loader: 'sass-loader' },
],
},{
test: /\.(jpg|png|svg)$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath:'images/',
publicPath:'../images/' // how to exclude home.html ?
}
}
]
}
]
},
plugins: [
new HtmlWebPackPlugin({
hash: true,
filename: 'index.html', // landing page remains in root directory
template: 'src/index.html',
chunks: ['home']
}),
new HtmlWebPackPlugin({
hash: true,
filename: 'about/index.html', // all other pages move to subdirectories
template: 'src/about.html',
chunks: ['about']
}),
new MiniCssExtractPlugin({
filename: "css/style.css"
}),
new CleanWebpackPlugin()
]
};
Thank you! And also, let me know how you like this configuration file!
I have it working. horray!
I never ended up using publicPath. Maybe there would have been a way to change it, but this ended up being a red herring. Instead I restructured my src directory to follow the pattern I was looking for, and removed html-loader so the paths wouldn't get changed during the build process.
Here is my new source directory:
/ src /
-home.html
templates/
-about.html
js/
-home.js
-about.js
images/
-00.jpg
-01.jpg
scss/
-style.scss
You can see home.html is purposely on the main directory rather than in /templates. Image sources are referenced as images/ in home.html, and ../images/ elsewhere.
Now instead of html-loader, I used copy-webpack-plugin to require / copy the images from the source directory to the build folder, as html-loader was changing the paths during the build process. It took me a few tries to figure out that html-loader was the culprit.
Here is my final working webpack config for the record.
// webpack.config.js
const webpack = require('webpack');
const path = require('path');
const HtmlWebPackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const CopyPlugin = require('copy-webpack-plugin');
module.exports = {
context: path.resolve(__dirname, 'src'),
entry: {
home: './js/home.js',
about: './js/about.js',
},
output: {
filename: (pathData) => {
return pathData.chunk.name === 'home' ? 'bundle.js' : '[name]/bundle.js';
},
path: path.resolve(__dirname, 'public_html')
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, "css-loader"]
},{
test: /\.sass$|\.scss$/,
use: [
MiniCssExtractPlugin.loader,
{ loader: 'css-loader' },
{ loader: 'sass-loader' },
],
},{
test: /\.(jpg|png|svg)$/,
use: [
{
loader: 'file-loader',
options: {
name: '[path][name].[ext]'
}
}
]
}
]
},
plugins: [
new CopyPlugin({
patterns: [
{from:'./image',to:'image'}
],
}),
new HtmlWebPackPlugin({
hash: true,
filename: 'index.html', // landing page remains in root directory
template: 'index.html',
chunks: ['home']
}),
new HtmlWebPackPlugin({
hash: true,
filename: 'about/index.html', // all other pages move to subdirectories
template: 'templates/about.html',
chunks: ['about']
}),
new MiniCssExtractPlugin({
filename: "style.css"
}),
new CleanWebpackPlugin()
]
};
I solve the problem on this Way.
Import images on views
Import YourImage from '../../public/assets/img/your-image.png';
Call where you need with implement them
src={YourImage}
Or in your classNames
background-image: `url(${YourImage})`
Config the path to your project repository from GitHub in the rules section of webpack.config.js file.
Repository: "https://maikpwwq.github.io/your-repository/"
rules: [ { type: "asset", test: /\.(png|svg|jpg|gif|jpeg)$/i, use: [{ options: { publicPath: '/your-repository/'}, loader: 'file-loader' ]} } ]

Using html-webpack-plugin to generate an index.html file in Webpack (project using vue-simple boilerplate)

I'm trying to generate my own index.html file every time I build my application in Webpack and to do so, I installed html-webpack-plugin.
I understand that in order generate an index.html file in my dist folder, I need to have the following in my webpack.config.js file:
output: {
path: path.resolve(__dirname, './dist'),
filename: '[name].js',
},
plugins: [
new HtmlWebpackPlugin(), // creates an index.html file
],
With the above settings, it should generate the following, which is my desired output:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Webpack App</title>
</head>
<body>
<script type="text/javascript" src="build.js"></script></body>
</html>
Unfortunately, I've been using the vue-simple Webpack boilerplate to build my VueJS learning project and as a result, it has a publicPath entry in the output section:
output: {
path: path.resolve(__dirname, './dist'),
publicPath: '/dist/',
filename: '[name].js',
}
With the above settings, the html-webpack-plugin understandably generates the following script tag in the index.html file in my dist folder which is NOT what I need since src is now pointing to "/dist/build.js".
<script type="text/javascript" src="/dist/build.js"></script></body>
If I remove publicPath from my output settings, I can't load my page from my development server since everything breaks. I read this SO post about publicPath but I'm still unsure of what I should do to achieve my goals since everything was set up by the boilerplate. How should I edit my webpack.config.js file in order to generate my desired index.html file when I build without breaking anything on my dev server?
Below is my full webpack.config settings:
const path = require('path');
const webpack = require('webpack');
require("babel-polyfill"); // for async await
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
// babel-polyfill for async await
// entry: ["babel-polyfill", "./src/main.js"],
entry: {
build: ["babel-polyfill", "./src/main.js"]
},
output: {
path: path.resolve(__dirname, './dist'),
publicPath: '/dist/',
filename: '[name].js', // this will output as build.js
},
module: {
rules: [{
test: /\.css$/,
use: [
'vue-style-loader',
'css-loader'
],
}, {
test: /\.scss$/,
use: [
'vue-style-loader',
'css-loader',
'sass-loader'
],
}, {
test: /\.sass$/,
use: [
'vue-style-loader',
'css-loader',
'sass-loader?indentedSyntax'
],
}, {
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
// Since sass-loader (weirdly) has SCSS as its default parse mode, we map
// the "scss" and "sass" values for the lang attribute to the right configs here.
// other preprocessors should work out of the box, no loader config like this necessary.
'scss': [
'vue-style-loader',
'css-loader',
'sass-loader'
],
'sass': [
'vue-style-loader',
'css-loader',
'sass-loader?indentedSyntax'
]
}
// other vue-loader options go here
}
}, {
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
}, {
test: /\.(png|jpg|gif|svg)$/,
loader: 'file-loader',
include: '/src/assets/images',
options: {
name: '[name].[ext]?[hash]'
}
}]
},
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js'
},
extensions: ['*', '.js', '.vue', '.json']
},
devServer: {
historyApiFallback: true,
noInfo: true,
overlay: true
},
performance: {
hints: false
},
plugins: [
new webpack.ProvidePlugin({ // this injects the following into .vue files
_: "lodash",
math: "mathjs",
moment: "moment",
axios: "axios",
Chart: "chart.js",
firebase: "firebase",
}),
new HtmlWebpackPlugin(), // creates an index.html file in dist
],
devtool: '#eval-source-map'
};
if (process.env.NODE_ENV === 'production') {
module.exports.devtool = '#source-map'
// http://vue-loader.vuejs.org/en/workflow/production.html
module.exports.plugins = (module.exports.plugins || []).concat([
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
new webpack.optimize.UglifyJsPlugin({
sourceMap: true,
compress: {
warnings: false
}
}),
new webpack.LoaderOptionsPlugin({
minimize: true
})
]);
}
Below is the folder structure I have:
You can alternatively use vue-cli for scaffolding. (Read the vue documentation for vue-cli here https://vuejs.org/2015/12/28/vue-cli/)
The following will give you a full preconfigured webpack config :
vue init webpack project-name
Then you can use npm run build OR yarn build which will generate your index.html in the "dist" folder.

Webpack-Dev-Server not showing latest files on change

I am trying to get a project running that uses a webpack dev server with HMR and source-mapping but am running into an issue. When I use webpack alone with my configuration file the source-maps are indicated in the console output and HMR works on page-refresh, but there is no server. When I try to instead run the script using webpack-dev-server there is no indication in the console that source-maps are being generated and changes are not being rendered ( either automatically or on page refresh ) when recompilation is appearing in the console output.
Here is my configuration file
/*
Webpack Configuration File
webpack.config.js
===
Webpack configuration file for the, "Debugging Webpack Issues" project.
#version:0.1.1
*/
const webpack = require( "webpack" );
const path = require( "path" );
const htmlWebpackPlugin = require( "html-webpack-plugin" );
const BUILD_PATH = path.resolve( __dirname, "../build" );
const SOURCE_PATH = path.resolve( __dirname, "../src" );
console.log(BUILD_PATH);
console.log(SOURCE_PATH);
let config = {
entry: SOURCE_PATH + "/index.js",
output: {
path: BUILD_PATH + "/rsc/scripts/",
filename: "bundle.js"
},
module: {
rules: [
{
test: /\.js$/,
loader: "babel-loader",
options: {
"presets" : [ "es2015", "react" ]
},
exclude: [/node_modules/],
include: SOURCE_PATH
},
{
test: /\.css$/,
use: [ "style-loader", "css-loader" ],
include: SOURCE_PATH,
exclude: [/node_modules/]
}
]
},
devServer: {
compress: true,
port:9000,
open: true,
hot: true,
contentBase: BUILD_PATH
},
devtool: "source-map",
watch: true,
target: "web",
plugins: [
new htmlWebpackPlugin({
title: "Example React App",
filename: "../../index.html",
template: SOURCE_PATH + "/template.html"
}),
new webpack.NamedModulesPlugin(),
new webpack.HotModuleReplacementPlugin()
]
};
module.exports = config;
I am aware that webpack-dev-server may not be updating because it is trying to load from a static location, but I have attempted changes to my file that others specified in their projects ( such as adding publicPath to the file ) with this issue without success.
Webpack's publicPath value needs to be relative to the build directory in the output.
Here is a working version of my webpack configuration file :
/*
Webpack Configuration File
webpack.config.js
===
Webpack configuration file for the, "Debugging Webpack Issues" project.
#version:0.1.1
*/
const webpack = require( "webpack" );
const path = require( "path" );
const htmlWebpackPlugin = require( "html-webpack-plugin" );
const BUILD_PATH = path.resolve( __dirname, "../build" );
const SOURCE_PATH = path.resolve( __dirname, "../src" );
const PUBLIC_PATH = "/rsc/scripts/";
console.log(BUILD_PATH);
console.log(SOURCE_PATH);
let config = {
entry: SOURCE_PATH + "/index.js",
output: {
path: BUILD_PATH + PUBLIC_PATH,
filename: "bundle.js"
},
module: {
rules: [
{
test: /\.js$/,
loader: "babel-loader",
options: {
"presets" : [ "es2015", "react" ]
},
exclude: [/node_modules/],
include: SOURCE_PATH
},
{
test: /\.css$/,
use: [ "style-loader", "css-loader" ],
include: SOURCE_PATH,
exclude: [/node_modules/]
}
]
},
devServer: {
compress: true,
port:9000,
open: true,
hot: true,
contentBase: BUILD_PATH,
publicPath: PUBLIC_PATH
},
devtool: "source-map",
watch: true,
target: "web",
plugins: [
new htmlWebpackPlugin({
title: "Example React App",
filename: "../../index.html",
template: SOURCE_PATH + "/template.html"
}),
new webpack.NamedModulesPlugin(),
new webpack.HotModuleReplacementPlugin()
]
};
module.exports = config;
Anyone with this problem should make sure that a publicPath is set in the devServer configuration options. The publicPath should be treated as the path ( relative to the build directory ) that your Server's html file should look to grab bundle.js from.
My project structure in my Build folder looks like:
./build
./build/rsc/scripts/bundle.js
./build/index.html
so my publicPath needed to be set to /rsc/scripts so that it knew where to get the virtual file from.
In my case , project was generated by create-react-app.
My solution is:
Find
./node_modules/react-scripts/config/webpackDevServer.config.js
locate below code:
historyApiFallback: {
// Paths with dots should still use the history fallback.
// See https://github.com/facebook/create-react-app/issues/387.
disableDotRule: true,
index: paths.publicUrlOrPath,
},
Remove the above code, and update the above as below:
historyApiFallback: true,
hot: true,

Where is the bundle & the dist folder in html-webpack-plugin?

I have the following Webpack config with the html-webpack-plugin:
/*
./webpack.config.js
*/
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const HtmlWebpackPluginConfig = new HtmlWebpackPlugin({
template: './client/index.html',
filename: 'index.html',
inject: 'body'
});
module.exports = {
entry: './client/index.js',
output: {
path: path.resolve('dist'),
filename: 'index_bundle.js'
},
devServer: {
historyApiFallback: true
},
module: {
loaders: [
{ test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ },
{ test: /\.jsx$/, loader: 'babel-loader', exclude: /node_modules/ }
]
},
plugins: [HtmlWebpackPluginConfig]
}
But I cannot find the actual bundle that is created in the end. Neither can I find the dist folder. Where is all of that?
I would also be keen on removing this plugin again, but all the tutorials I can find online include it. It makes it really difficult for me as a beginner who doesn't know webpack, to include file paths in my react code and style sheets.

Categories