404s on some images from Webpack url-loader - javascript

There are a lot of questions on this, and a lot of answers, read below to see what I've tried, and how they didn't work. I assume my problem is coming from a fundamental misunderstanding of how url-loader works.
I have images included like this in my .less files. I am using two different formats as an example of what I've tried.
app.less
#logo {
background-image: url("~/img/LoginMarketingImage.png");
}
#logotwo{
background-image: url("../public/img/LoginMarketingImage2.png");
}
webpack.config.js
module.exports = {
context: path.resolve(__dirname, '../../'),
entry: {
app: './public/js/app.js'
},
output: {
path: path.resolve(__dirname, '../build'),
filename: '[name].js',
publicPath: '/'
},
I have also tried
webpack.config.js
module.exports = {
context: path.resolve(__dirname, '../../'),
entry: {
app: './public/js/app.js'
},
output: {
path: path.resolve(__dirname, '../build'),
filename: '[name].js',
publicPath: ''
},
As well as below, based on: webpack css-loader not finding images within url() reference in an external stylesheet
webpack.config.js
module.exports = {
context: path.resolve(__dirname, '../../'),
entry: {
app: './public/js/app.js'
},
output: {
path: path.resolve(__dirname, '../build'),
filename: '[name].js',
publicPath: 'https://localhost:9081/'
},
My module config looks like
webpack.config.js
module: {
rules: [
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 2000000,
name: utils.assetsPath('img/[name].[ext]')
}
},
]
}
I have experimented with a limit of 1 and a higher limit, to see if inline vs non-inlined works.
My folder structure is as follows
build/
less/
app.less
public/
img/
LoginMarketingImage.png
LoginMarketingImage2.png
config/
webpack/
webpack.config.js
My Results
If I set the limit to 1, and force all images to be output directly, the only time they are output is if they use the url("../") syntax. url("~/") throw no webpack errors, but the images don't get output to the build folder. In this case, the images using url("../") syntax throw no errors in the browser either. However, this is not ideal, as I want to take advantage of url-loader's ability to return a DataURL. In this scenario, images using url("~/") syntax give the error GET https://localhost:9081/img/logo.png 404 (Not Found), regardless of publicPath setting.
If I set the limit to 20000000, obviously no images are put in the build folder by file-loader. However, all images return a 404 in the browser, regardless of publicPath setting.
I feel like I'm misunderstanding how to use url-loader. What kind of configuration do I need, and how should I be requiring my files inside less, to take advantage of url-loader's ability to return DataURLs?
EDIT: Based on this issue, I have ensured that css sourcemaps are disabled.

I can't pinpoint the problem here, but it seems like the publicPath config is the problem. I threw together a sample gist with the minimium you need to get the url-loader working properly.
Some things to note:
Make sure the test option is correct
You didn't mentioned which version of webpack you're using, but I assume it's > 2. If it's == 2 then you should upgrade because the newer versions fixed a lot of bugs and the config API is almost 100% compatible
Do not use the tilde import path, it's a shortcut to project-root-dir/node_modules (at least in webpack 1.x)
I assume you're using webpack-dev-server. If not, then you should not need to set the publicPath and such
Do not change url-loader's name option unless you got everything working without it. Changing it's path can confuse webpack

Related

Webpack bundler - how to inject many sources

I've got a question. How does one inject the JS code from three different files using webpack?
I've managed to write a code like just below (webpack.config.js), but somehow it doesn't work. In the bundle.js it implements only first source (index.js) but other two are omitted.
Can anyone help me? I'm just a noobie in this and I'm still learning. Thanks a lot.
const path = require('path')
module.exports = {
mode: 'development',
entry: ['./index.js','./chat.js', './ui.js'],
output: {
path: path.resolve(__dirname, ''),
filename: 'bundle.js'
},
watch: true
}
In such cases I prefer to have just one entry point that loading all dependencies, e.g. in index.js import other modules:
import('chat.js')
import('ui.js')

resolving all files from set public directories with webpack

I have built a custom HTML framework that has a pretty simple project structure. I really need to grab from 3 separate directories views,js, and components. I am very new to webpack but I figured with its configurability there would be a way for me to have all of these imports importing something like /components/random_component_name.js I need webpack to resolve these files to be their private path.
I have tried many different things this is what I have most recently tested
const path = require('path');
module.exports = {
entry: path.resolve(__dirname + '/public/js/main.js'),
module: {
generator: {
js: {
// Generator options for asset modules
// Customize publicPath for asset modules, available since webpack 5.28.0
publicPath: '/js',
// Emit the asset in the specified folder relative to 'output.path', available since webpack 5.67.0
outputPath: path.resolve(__dirname + 'public/js'),
},
},
},
}
How can i get this functionality out of webpack. Surely it shouldn't be too hard. I am new to all bundlers like this so sorry if this is horribly wrong.
I finally figured it out. I had tried a method close to this before but neglected the '/' in the alias key names so now this work
const path = require('path');
module.exports = {
//...
entry: {
main: './src/js/main.js',
},
resolve: {
alias: {
'/components': path.resolve(__dirname, 'src/components/'),
'/js': path.resolve(__dirname, 'src/js/'),
'/views': path.resolve(__dirname, 'src/views/'),
},
}
};

webpack and importing js files to scripts and bundling up

I'm pretty inexperienced with webpack. I'm actually using Cloudflare Wrangler, which I believe uses Webpack 4 under the hood. In any case I have an src/index.js file and a helpers/script.js file.
my index.js file works fine, builds and compiles etc etc.
When I copy the content of helpers/script.js into the top of the index.js file, again all is good and works.
When I import script.js with either of
import human from "../helpers/script"
const human = require("../helpers/script")
then I use a webpack.config.js file that looks like
module.exports = {
target: 'webworker',
context: __dirname,
entry: './src/index.js',
mode: 'production',
module: {
rules: [
{
test: /\.index\.js$/,
use: { loader: 'worker-loader' }
}
],
},
resolve: {
extensions: ['.js'],
},
};
I can't seem, no matter what I do to get it to 'like' the imported script file.
I continually get:
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
...
Error: webpack returned an error. Try configuring `entry` in your webpack config relative to the current working directory, or setting `context = __dirname` in your webpack config.
Can anyone help me understand the requirements for being able to import a file to another js. Its amazing how hard this is to do :joy:

Webpack [contenthash] parse in files

I will do versioning via hashing. And this with Webpack.
Content of: webpack.config.js
...
output: {
path: path.resolve(__dirname, 'web/dist'),
filename: '[name].[contenthash].js',
},
...
webpack generate some files, i think its okay, its a hash...
app.d471b97fd69a6837f5bf.js
In my index.html file must replace the filenames to, i do it with "replacer-contenthash-webpack-plugin" Plugin for Webpack. It used the loaderUtils.getHashDigest(buffer) do generate a hash. But its not the same its generate this 174d0b0d04495cf7a970 hash.
Content of: index.html
<script src="dist/app.174d0b0d04495cf7a970.js"></script>
how can i fix it? I dont no how webpack generate the hash with [hashcode]. Its not specified.
i have tried, to specified contenthash digest, length and function:
output: {
path: path.resolve(__dirname, 'web/dist'),
filename: '[name].[contenthash].js',
hashFunction: "md5",
hashDigest: "hex",
hashDigestLength: 32
},
and specified the used Webpack extension getHashDigest() so:
getHashDigest(buffer, "md5", "hex", 32)
=>
app.54949ecc3046a8e7e56e8d9875970ca2.js
but index.html different :(
<script src="dist/app.174d0b0d04495cf7a970e84cc9a96cdb.js"></script>
The webpack plugin you are using (replacer-contenthash-webpack-plugin) is not very reputable, it's only getting around 200 downloads a week.
Check out the HtmlWebpackPlugin, it does the same thing and is getting around 13 million downloads a week.
The docs are straightforward and hopefully will sort your problem.
https://webpack.js.org/plugins/html-webpack-plugin
https://www.npmjs.com/package/html-webpack-plugin

Webpack-dev-server compiles files but does not refresh or make compiled javascript available to browser

I'm trying to use webpack-dev-server to compile files and start up a dev web server.
In my package.json I have the script property set to:
"scripts": {
"dev": "webpack-dev-server --hot --inline",
}
So the --hot and --inline should enable the webserver and the hot reloading (as I understand it).
In my webpack.config.js file I set the entry, output, and devServer settings as well as add a loader to look for changes in .vue files:
module.exports = {
entry: './src/index.js',
output: {
path: __dirname + '/public',
publicPath: '/public',
filename: 'bundle.js'
},
devtool: 'source-map',
devServer:{
contentBase: __dirname + '/public'
},
module:{
loaders:[
{ test: /\.vue$/, loader: 'vue'}
]
}
};
So with this setup, I run npm run dev. The webpack-dev-server starts up, the module loader test works (i.e. when I save any .vue file it causes webpack to recompile), but:
The browser never refreshes
The compiled javascript that gets stored in memory is never made available to the browser
On that second bullet, I can see this because in the browser window the vue placeholders are never replaced and if I open up the javascript console the Vue instance is never created or made available globally.
What am I missing?
Two things were causing my problems here:
module.exports = {
entry: './src/index.js',
output: {
// For some reason, the `__dirname` was not evaluating and `/public` was
// trying to write files to a `public` folder at the root of my HD.
path: __dirname + '/public',
// Public path refers to the location from the _browser's_ perspective, so
// `/public' would be referring to `mydomain.com/public/` instead of just
// `mydomain.com`.
publicPath: '/public',
filename: 'bundle.js'
},
devtool: 'source-map',
devServer:{
// `contentBase` specifies what folder to server relative to the
// current directory. This technically isn't false since it's an absolute
// path, but the use of `__dirname` isn't necessary.
contentBase: __dirname + '/public'
},
module:{
loaders:[
{ test: /\.vue$/, loader: 'vue'}
]
}
};
Here's the fixed webpack.config.js:
var path = require('path');
module.exports = {
entry: [
'./src/PlaceMapper/index.js'
],
output:{
filename: 'bundle.js',
path: path.resolve(__dirname, 'public/')
},
devtool: 'source-map',
devServer:{
contentBase: 'public'
},
module:{
loaders:[
{ test: /\.vue$/, loader: 'vue'}
]
}
};
After a long search I found the solution for my problem, in my case output path wasn't configured correctly.
This configuration solved my problem:
const path = require('path');
module.exports = {
"entry": ['./app/index.js'],
"output": {
path: path.join(__dirname, 'build'),
publicPath: "/build/",
"filename": "bundle.js"
}....
the right solution
Tell dev-server to watch the files served by the devServer.watchContentBase option.
It is disabled by default.
When enabled, file changes will trigger a full page reload.
Example:
module.exports = {
//...
devServer: {
// ...
watchContentBase: true
}
};
I also had a problem with my devserver which stopping working. Previously it had worked, then I added a ton of extras to get a production build. Then when I came back to devserver it didn't work any more.
Took lots of sleuthing - eventually starting with a prior commit in git, then reintroducing changes one-by-one until I figured it out.
Turns out it was a change I had made to package.json, specifically this line:
"browserslist": "> 1%, not dead",
This was useful to guide postcss, regarding the browsers to target.
But, it stops devserver working. Workaround is to add this to the dev webpack config:
target: 'web',
I found the solution here: https://github.com/webpack/webpack-dev-server/issues/2812
Hope that saves someone a few hours of trouble!
Somehow, for my case, removing "--hot" makes it work. So, I removed hot: true
webpack.dev.js
module.exports = merge(common, {
mode: 'development',
devtool: 'inline-source-map',
devServer: {
publicPath: '/js/',
contentBase: path.resolve(__dirname, 'docs'),
watchContentBase: true,
}
});
webpack.common.js
output: {
path: path.resolve(__dirname, 'docs/js'),
filename: '[name].min.js',
library: ['[name]']
},
I had the same problem and I find that in addition to all those points, we also have to put the index.html together with the output bundle.js in the same folder and set the contentBase to this folder, either the root or a subfolder.
This happened to me as well after running two different applications on the same webpack-dev-server port after one another. This happened even though the other project was shut down. When I changed to a port that had not been used it started working directly.
devServer: {
proxy: {
'*': {
target: 'http://localhost:1234'
}
},
port: 8080,
host: '0.0.0.0',
hot: true,
historyApiFallback: true,
},
If you use Chrome like me then just open Developer Tools and click on Clear site data. You can also see if this is the problem by running the site in incognito mode.
It can happen because of ExtractTextPlugin. Deactive the ExtractTextPlugin in development mode. Use it only for production build.
I experienced a similar situation where webpack-dev-server was serving my index.html file but not updating. After reading a few posts I realized that webpack-dev-server does not generate a new js file but instead injects one into index.html.
I added the html-webpack-plugin to my app and with the following configuration in my webpack.config.js file:
const HtmlWebpackPlugin = require('html-webpack-plugin')
plugins: [
new HtmlWebpackPlugin({
filename: 'index.html',
template: 'index.html',
inject: true
})
]
I then commented out the script tag referencing my entry js file in index.html. I can now run webpack-dev-server without any additional flags and any changes to my files will display in the browser instantly.
What worked for me:
cache: false
https://webpack.js.org/configuration/cache/
My case was that I got so deep into experimenting with Webpack features, but totally forgot that I had set inject to be false the entire time like so...
new HTMLWebpackPlugin({
inject: false,
...
}),
Switching that on was my ticket.
I'll add my own special tale of Webpack --watch woe to the wall of suffering here.
I was running
webpack --watch
in order to build a Typescript project. The compiled .js files would update, but the bundle that the browser was seeing would not. So I was basically in the same position as the OP.
My problem came down to the watchOptions.ignored parameter. The original author of the build config had set up ignored as a filter function, which turns out to not be a valid value for that parameter. Replacing the filter function with an appropriate RegExp got the --watch build working again for me.
What helped me was introducing devServer.devMiddleware. For example, in webpack-dev-server 4.10.0, property contentBase was not available anymore.
devServer: {
devMiddleware: {
index: true,
publicPath: './build/static/',
serverSideRender: true,
writeToDisk: true,
}
},
Your project tree is not clear, however the problem may be in contentBase setting. Try to set contentBase: __dirname

Categories