Webpack generates duplicate images - javascript

I have a problem, Webpack generates duplicate images, while one of the duplicates is broken.
I have an image image, and two duplicates are generated from it, a working one: image, and a non-working one: image. I 'm in CSS for a class .logo I'm hanging the background-image style: image. After compiling the code, it inserts the path to the non-working image: image, and I don't understand what's the matter :(
Please help me fix it, Thanks in advance!!!
My webpack.config.js:
const path = require('path')
const HTMLWebpackPlugin = require('html-webpack-plugin')
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
module.exports = {
context: path.resolve(__dirname, 'src'),
mode: 'development',
entry: {
main: './index.js',
analytics: './analytics.js'
},
output: {
filename: '[name].[contenthash].js',
path: path.resolve(__dirname, 'dist')
},
plugins: [
new HTMLWebpackPlugin({
title: 'Webpack Tenzo',
template: './index.html'
}),
new CleanWebpackPlugin()
],
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /\.(png|jpg|svg|gif)$/,
use: ['file-loader']
}
]
}
}

I solved the problem. The point was that it was necessary to use "assets" instead of leaders such as "file-loader".

Related

WebPack: problem when compiling JS files in html

I am having a problem while working with Webpack. I'm using a JS file to call an API, but this API should be called only in escudos.html, but when I do the Webpack build, the JS file calls the API int both (index.html, escudos.html). I only want that the ./src/js/teams.js call API when I am in the escudos.html, not in in both (index.html, escudos.html) HTML.
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
index: './src/js/index.js',
teams: './src/js/teams.js',
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'js/[name].bundle.js',
},
plugins: [
new HtmlWebpackPlugin({
filename: 'index.html',
template: './src/index.html',
}),
new HtmlWebpackPlugin({
filename: 'escudos.html',
template: './src/escudos.html',
}),
],
devServer: {
static: './dist',
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: { loader: 'babel-loader' },
},
],
},
};
for some reason my webpacked file index.html has the teams.js too
The problem (and the solution) is in HtmlWebpackPlugin. HtmlWebpackPlugin injects all entries in every page by default.
There exists three solutions I can think of:
inject: false: This disables auto injection of <script> tags into the templete. You have to manually write <script>tag(s) with the proper src. (Psss: don't)
chunks: specifiy which entries you want to be included for this template. E.G: (Solves the OP problem, what you will need/use in most cases)
new HtmlWebpackPlugin({
template: "./src/index.html",
chunks: ["index"]
}),
new HtmlWebpackPlugin({
template: "./src/escudos.html",
chunks: ["teams"]
})
exclude: inject all entries except the ones specified in this array. E.G
new HtmlWebpackPlugin({
template: "./src/test.html",
exclude: ["index"]
})

Script Path for CSS and Bundle is a bit off after WebPack Creates index.html

For some reason, webpack is trying to append client to the href of the script tags for my CSS and bundle. The problem with this is that it's wrong. And I don't know how to tell it to trim that part off.
Before moving to webpack, here is how it looks in production when I was building it with Gulp:
notice above how everything was rooted from within the client folder. You don't even see the client folder because I think expressJS said to start from that point so you only see the root of what's in client such as lib, scripts, etc.
here's what the dist directory looked like when I was using Gulp for that:
Here's how I'm serving my static assets. My ExpressJS server sets the root folder for static asses as dist/client. This has always been the case even when I was using Gulp:
.use(
express.static('dist/client', {
maxage: oneYear,
})
)
Forward to now: It's using my new webpack.config now
Here is a Screenshot of dist from IDE as it is now after using webpack:
But now the index.html is gened by webpack:
<!doctype html><html lang="en"><head><title>My Title</title><meta charset="utf-8"><link href="https://ink.global.ssl.fastly.net/3.1.10/css/ink.min.css"><script src="https://ink.global.ssl.fastly.net/3.1.10/js/ink-all.min.js"></script><script src="https://ink.global.ssl.fastly.net/3.1.10/js/autoload.js"></script><link href="../client/lib/assets/css/main.c09764908684c2f56919.css?c09764908684c2f56919" rel="stylesheet"></head><body><div id="app"></div><script src="../client/scripts/app.c09764908684c2f56919.bundle.js?c09764908684c2f56919"></script></body></html>
webpack.config.js
const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const TerserJSPlugin = require('terser-webpack-plugin');
const HtmlWebPackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const CopyPlugin = require('copy-webpack-plugin');
const isProduction = process.env.NODE_ENV === 'production';
const html = () => {
return new HtmlWebPackPlugin({
template: './src/client/index.html',
filename: './client/index.html',
hash: true,
});
};
const copyAllOtherDistFiles = () => {
return new CopyPlugin({
patterns: [
{ from: 'src/client/assets', to: 'client/lib/assets' },
{ from: 'src/server.js', to: './' },
{ from: 'src/api.js', to: './' },
{ from: 'package.json', to: './' },
{ from: 'ext', to: 'client/lib' },
{ from: 'feed.xml', to: 'client' },
{
from: 'src/shared',
to: './shared',
globOptions: {
ignore: ['**/*supressed.json'],
},
},
],
});
};
module.exports = {
entry: './src/client/index.js',
output: {
filename: 'client/scripts/app.[hash].bundle.js',
path: path.resolve(__dirname, 'dist'),
},
target: 'web',
devServer: {
writeToDisk: true,
},
devtool: 'source-map',
optimization: {
minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})],
splitChunks: {
cacheGroups: {
styles: {
name: 'styles',
test: /\.css$/,
chunks: 'all',
enforce: true,
},
},
},
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
},
},
{
test: /\.html$/,
use: [
{
loader: 'html-loader',
},
],
},
{
test: /\.less$/,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'less-loader'],
},
{
test: /\.(png|svg|jpg|gif)$/,
use: ['url-loader'],
},
],
},
plugins: isProduction
? [
new CleanWebpackPlugin(),
new MiniCssExtractPlugin({
filename: isProduction
? 'client/lib/assets/css/main.[hash].css'
: 'main.css',
}),
html(),
copyAllOtherDistFiles(),
]
: [new CleanWebpackPlugin(), html(), copyAllOtherDistFiles()],
};
Notice for my bundle the src generated includes ../client/ and same for my href for the CSS script.
The problem with this is that my app is served from the root of the client folder in dist. You'd think that ../client/ or ./client/ or client/ would work but it doesn't. When I run the site I get this because it can't find the bundle:
As you can see below, everything it stemming from context of the client folder already in the browser:
(what's also odd about this after moving to webpack, is why do I see a client folder if I told ExpressJS to start from the client folder already? When I was using the same exact code with Gulp, I did not see a client folder because I was already in it from the context of the browser)
So when I change the generated index.html manually in my dist folder, just to see if I can fix it, it all resolves just fine (notice I changed it to just lib/ and scripts/):
</script><link href="lib/assets/css/main.c09764908684c2f56919.css?c09764908684c2f56919" rel="stylesheet"></head><body><div id="app"></div><script src="scripts/app.c09764908684c2f56919.bundle.js?c09764908684c2f56919"></script></body></html>
The problem is I don't know how to get webpack to strip out that ..client/ part of the url when it gens the index.html. I've tried adding a publicPath property with '/', or './' or '' but no luck so far.
In other words this does not load: http://localhost:8080/client/scripts/app.b4b3659d9f8b3681c26d.bundle.js
but this does:
http://localhost:8080/scripts/app.b4b3659d9f8b3681c26d.bundle.js
http://localhost:8080/lib/assets/css/main.b4b3659d9f8b3681c26d.css
I think as long as you just write your output assets to same folder with the public folder set at your server, then it would work. Assuming the client will still be the public:
.use(
express.static('dist/client', {
maxage: oneYear,
})
)
I suggest to set entire output as client dir along side with its publicPath in webpack config for client:
output: {
filename: 'scripts/app.[hash].bundle.js',
path: path.resolve(__dirname, 'dist/client'),
publicPath: '/'
}
with the setting above, we don't have to specify the folder the html template location:
new HtmlWebPackPlugin({
template: path.resolve(__dirname, 'src/client', 'index.html'),
filename: 'index.html',
hash: true,
});
I don't quite understand yet why this fixed it but here is what made it work.
Definitely didn't need the publicPath:
output: {
filename: 'scripts/app.[hash].bundle.js',
path: path.resolve(__dirname, 'dist'),
},
Changed my static path to be:
.use(
express.static('dist', {
maxage: oneYear,
})
)
move index.html out of the client folder and into the root of dist:
return new HtmlWebPackPlugin({
template: path.resolve(__dirname, 'src/client', 'index.html'),
filename: 'index.html',
hash: true,
});
Same with my bundle
output: {
filename: 'scripts/app.[hash].bundle.js',
publicPath: '/',
path: path.resolve(__dirname, 'dist'),
},
Same with assets:
patterns: [
{ from: 'src/client/assets', to: 'lib/assets' },
I don't see what moving it to the root of dist makes any difference but for some reason rendering / requesting to process index.html from the root of dist instead of dist/client works`

Webpack config: devServer.historyApiFallback and output.publicPath

Recently I came across the same issue as the post "historyApiFallback doesn't work in Webpack dev server".
I will first quote the accepted answer in that post.
Answer:
I meet the same question today. let config in webpack.config.js:
output.publicPath be equal to devServer.historyApiFallback.index and
point out html file route.my webpack-dev-server version is 1.10.1 and work well. http://webpack.github.io/docs/webpack-dev-server.html#the-historyapifallback-option doesn't work, you must point out html file route.
module.exports = {
entry: "./src/app/index.js",
output: {
path: path.resolve(__dirname, 'build'),
publicPath: 'build',
filename: 'bundle-main.js'
},
devServer: {
historyApiFallback:{
index:'build/index.html'
},
},
};
I tried to use this answer to fix the problem(set output.publicPath: 'dist' and devServer.historyApiFallback:{index:'dist/index.html'})
but somehow it didn't work.
After some search I found this page. According to the description in the page:
This section is for everyone who ran into this problem in development
using webpack-dev-server.. Just as above, what we need to do it tell
Webpack Dev Sever to redirect all server requests to /index.html.
There are just two properties in your webpack config you need to set
to do this, publicPath and historyApiFallback.
module.exports = {
entry: './app/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'index_bundle.js',
publicPath: '/'
},
module: {
rules: [
{ test: /\.(js)$/, use: 'babel-loader' },
{ test: /\.css$/, use: [ 'style-loader', 'css-loader' ]}
]
},
devServer: {
historyApiFallback: true,
},
plugins: [
new HtmlWebpackPlugin({
template: 'app/index.html'
})
]
};
According to the config I modified my devServer.historyApiFallback to be true, and output.publicPath to be /.
My webpack config:
const webpack = require("webpack")
const path = require("path")
const CleanWebpackPlugin = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
mode: "development",
entry: {
app: "./src/base/index.js"
},
output: {
filename: "[name].bundle.js",
publicPath: '/',
path: path.resolve(__dirname, "dist")
},
devtool: 'inline-source-map',
devServer: {
hot: true,
port: 3000,
historyApiFallback: true
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.(scss|css)$/,
use: [
"style-loader",
"css-loader",
"sass-loader"
]
},
{
test: /\.(pdf|jpg|png|gif|svg|ico)$/,
use: [
{
loader: 'url-loader'
},
]
},
]
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
template: './src/base/index.html'
}),
new webpack.HotModuleReplacementPlugin()
],
}
Everything seemed working now.
But I have the puzzle that I don't know why it's working.
To be specific
devServer.historyApiFallback: true is clear according to webpack doc, so I'm not doubt about that part.
output.publicPath:/ is pretty vague for me though.
Question:
If I tried to use something like output.publicPath:/public, it
will not work. So why I must use output.publicPath:/ here?
How output.publicPath:/ can tell webpack-devserver to find the
right place and server the right index.html(which is generated by the
devserver I believe)?
Sry if it's a bit tedious. I just want to provide some detail.
But I have the puzzle that I don't know why it's working.
Setting 1
In webpack.config.js the setting
output: {
...
publicPath: '/static1/',
},
tells webpack to embed '/static1/' into the bundle's path in the generated .html file:
<script src="/static1/<name>.bundle.js" type="text/javascript"></script>
You can open the generated .html file(s) on disk and see the above tag with '/static1/' prepended to the bundle.
Setting 2
This setting:
devServer: {
publicPath: '/static/', // different from 'static1' we used above
tells webpack-dev-server to create a route handler for the path /static and serve resourses e.g. /static/<name>.bundle.js. The webpack-dev-server is based on Express which uses route handlers e.g. app.use(/mypath, ...); to serve requests.
If now you point a browser to localhost:8080, you will see blank screen. Righ-click on it to see Page Source. You will see the above <script>tag that makes the browser issue GET request for the bundle using the path /static1/xxx that doesn't work because you didn't tell webpack-dev-server to create a route handler for this path. Now type in the browser navigation bar
http://localhost:8080/static/<name>.bundle.js and you will see the internals of your bundle.
Eliminate the discrepancy between static1 and static and the page will render. In your case it works because one setting is set explicitly to '/' and the second one defaults to the same value.
Setting 3
historyApiFallback has a more narrow scope than other two settings because it is used with SPAs only. During the initial rendering a user sees the landing page of the SPA e.g. /mysample.html. This is the file with our <script> tag shown above. It should be used without any path like /static prepended to it:
historyApiFallback: {
...
index: mysample.html,
because Setting1 and Setting2 apply to bundles, not to bundle-containing .html pages.
Faced the same problem, it was succeeded to solve, having specified a route, instead of a path to index.html
devServer: {
publicPath: `/myApp`,
historyApiFallback: {
rewrites: [
{ from: /\/myApp/, to: `/myApp` }
]
}
}

Webpack application error

I am a webpack newcomer, I have set it up but when i run my angular application from webpack I receive the following error. totally baffled as too why? I am not sure what else to do from this point onwards, any help is appreciated!
Webpack config:
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
// const ExtractTextPlugin = require('extract-text-webpack-plugin');
// OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
mode: "production",
entry: {
polyfills: './src/polyfills.ts',
app: './src/main.ts',
vendor: './src/vendor.ts'
},
output: {
path: path.resolve(__dirname, "dist"),
filename: 'bundle.[name].js'
},
// watch: true,
resolve: {
extensions: ['.ts', '.js']
},
devServer: {
contentBase: './dist'
},
externals: {
jquery: 'jQuery'
},
plugins: [
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
title: 'App'
})
],
module: {
rules: [
{
test: /\.ts$/,
loaders: ['ts-loader','angular2-template-loader?keepUrl=true'],
exclude: /node_modules/
},
{
test: /\.(html|css)$/,
loader: 'raw-loader',
exclude: /\.async\.(html|css)$/
},
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
},
{
test: /\.html$/,
loaders: 'html-loader'
}
]
}
}
update:
After adding the module.id to all the components I have created, I now receive this error.
That's indeed a massive stack trace. When I see those I always try to figure out where it originates from, which file and where do I load it. On the right top corner, I see that it's coming from bundle.polyfills.js
Try temporarily disabling the polyfills entry point to see if that solves the issue. This will exclude that part of the code from being bundled.
polyfills: './src/polyfills.ts',
Here's what the Webpack docs say about the entry point.
An entry point indicates which module webpack should use to begin
building out its internal dependency graph, webpack will figure out
which other modules and libraries that entry point depends on
(directly and indirectly).
You can read more on how to configure them here.
UPDATE:
To get a more meaningful message, add devtool: "source-map" into your Webpack config and see if that improves the output of the error message. Also, have a look at this post on SO? It might be applicable to your project too.

bundle.js not found while refreshing the page having ID in it's URL

I ran into a problem where I am redirecting a user into its corresponding profile page where the profile information is being displayed.
Let's take for example http://localhost:8080/user/1.
when I am redirecting the user using the link in the navbar the page is successfully rendering but while I am refreshing the page in the same URL (i.e. http://localhost:8080/user/1 ) I get an error saying that ERROR http://localhost:8080/user/bundle.js not found.
I am new to react router v4 please help me out for this.
Thanks in advance.
My webpack.config.js is
var HtmlWebpackPlugin = require('html-webpack-plugin');
var webpack = require('webpack');
var path = require("path");
var config = {
entry: ["./src/index.tsx", 'webpack-dev-server/client?http://localhost:8080'],
plugins: [
new HtmlWebpackPlugin({
template: 'index.ejs',
filename: 'index.html'
}),
],
output: {
path: path.resolve(__dirname, "build"),
filename: "bundle.js"
},
resolve: {
extensions: [".ts", ".tsx", ".js"]
},
devtool: 'source-map',
module: {
rules: [
{ test: /\.tsx?$/, use: 'tslint-loader', enforce: 'pre' },
{ test: /\.tsx?$/, use: ['babel-loader', 'awesome-typescript-loader'] },
{ test: /\.(css|scss)$/, use: ['style-loader', 'css-loader', 'sass-loader'] },
{ test: /.(png|woff(2)?|eot|ttf|svg)(\?[a-z0-9=\.]+)?$/, use: 'url-loader?limit=1024&name=fonts/[name].[ext]' },
{ test: /\.(jpg|jpeg|gif|png)$/, use: 'url-loader?limit=10&mimetype=image/(jpg|jpeg|gif|png)&name=images/[name].[ext]' }
]
},
devServer: {
contentBase: path.join(__dirname, 'build'),
hot: true,
inline: true,
historyApiFallback: true
}
};
module.exports = config;
Looks like you need a public (aka static) folder! This way your files will always be available from a relative location.
If it's not cheating, here's an answer from another StackOverflow:
webpack.config.js
output: {
// your stuff
publicPath: '/assets/'
}
It is the concept of clientSide and server side code. If you will refresh your page in middle of journey the url will hit to the server and it will try to find out that method in server side which is not there because it is on client side.
For more explanation -
React-router urls don't work when refreshing or writting manually

Categories