webpack css-loader not finding images within url() reference in an external stylesheet
I'm new to the whole Node/NPM/Webpack world, so apologies if this is obvious.
I'm attempting to build a simple front-end project bundled with Webpack. I've got node installed, and have a package.json file configured. If I run "npm start" in my root directory, I get no errors from the console, and I'm able to go to "localhost:3000" in a browser and see my "hello, world" output.
My next task is to include a stylesheet, which contains a reference to an image, like this:
.myimg {background: url(path/to/file.jpg);}
With things set up like this, I can view the image via the webpack-dev-server (by going to localhost:3000 in a web browser), but if I build the project, the path to the image is wrong. I have no idea what I'm doing wrong, so I'm throwing this out to the Stackiverse in the hopes that somebody out there will know what stupid thing I'm doing.
Here's my package.json file:
{
"name": "webpack-test1",
"version": "0.0.1",
"description": "My project WTF.",
"private": true,
"scripts": {
"start": "node server.js"
},
"devDependencies": {
"css-loader": "^0.15.2",
"file-loader": "^0.8.4",
"style-loader": "^0.12.3",
"url-loader": "^0.5.6"
},
"dependencies": {
"webpack": "^1.9.6",
"webpack-dev-server": "^1.8.2"
}
}
...and here's my webpack.config.js file:
var path = require('path');
var webpack = require('webpack');
module.exports = {
entry: [
"./src/start.js"
],
output: {
filename: "bundle.js",
path: path.join(__dirname, 'build'),
publicPath: '/build/'
},
module: {
loaders: [
{ test: /\.css$/, loader: 'style-loader!css-loader' },
{ test: /\.(png|jpg)$/, loader: 'file-loader' }
]
}
};
...and then the index.html file:
<!doctype html>
<html>
<head>
<title>Webpack Test</title>
</head>
<body>
<div class="imgtest">hello, world</div>
<script src="build/bundle.js"></script>
</body>
</html>
...the "start.js" file referenced in the config file:
require('./test.css');
console.log("y u no work?");
...and finally, the contents of the css file itself:
.imgtest { background: url(img/volcano.jpg);}
Like I said at the top, in webpack-dev-server world, the path to the image resolves properly, and it shows up as the background to the DOM element. In published world, the browser tells me it can't find the file, with Safari's console clearly showing a bad file path:
http://localhost/build/1b05d814aa13ac035c6b122b9f5974f8.jpg
The correct local path is this:
http://localhost/~username/webpack1/build/1b05d814aa13ac035c6b122b9f5974f8.jpg
Clearly, I'm doing something wrong, but I can't figure out what. Any help or advice is appreciated.
Thanks!
Solution 1:
Okay...ugh. I just figured it out. The problem was with the "publicPath" variable inside webpack.config.js. I had this:
publicPath: '/build/'
...which in retrospect is obviously an absolute path. What I needed instead was this:
publicPath: './build/'
...which is a relative path. Things seem to work now.
UPDATE:
I'm still very new to Webpack, so all of this is still pretty confusing. Having said that...
I think I've gone about this the wrong way. My Webpack project has had an index.html file at the root of the project, and I was trying to use that both as the file the webpack-dev-server would hit AND what the build would use as its entry point. That was causing me no end of headaches, and I don't think any solution I hit upon really worked. Then I found this:
https://www.npmjs.com/package/html-webpack-plugin
This lets you create your index.html page from a template, which means it doesn't actually have to exist as a file. webpack-dev-server creates it on the fly and stores it in memory, and when you publish to your "build" folder, an index.html file gets created within that folder.
There may be a true "right" way to handle the problem I raised here, but this seems to work really well, and in a roundabout way, it solves my problems, since it ducks the whole path question entirely.
Anyway, this is kind of rambling. I hope it helps somebody, and/or I hope somebody who knows more about this comes here and sets me straight.
Solution 2:
ERROR that I had faced was
Module parse failed: PATH:\TO\IMG\XYZ.PNG Unexpected character '�' (1:0)
You may need an appropriate loader to handle this file type.
SyntaxError: Unexpected character '�' (1:0)
.
.
.
.
.
@ ./~/css-loader!./~/sass-loader!./node/static/sass/style.scss 6:399692-399747
This solves my problem:
module: {
.
.
.,{
test: /\.scss$/,
exclude: /node_modules/,
loader: ExtractTextPlugin.extract("style-loader", "css-loader!sass-loader"),
root: path.resolve('./node/static/sass')
},
{
test: /\.(jpe?g|gif|png)$/,
loader: 'file-loader?emitFile=false&name=[path][name].[ext]'
}
]}
Run your webpack again.
Append all the background: url('~/../somePath/toImage.png');
> [email protected] react-build PATH:\TO\PROJECT
> webpack --watch --display-error-details --display-cached --content-base ./
Hash: f6e4cbbf0068b5792247
Version: webpack 1.13.2
Time: 4882ms
Asset Size Chunks Chunk Names
js/bundle.js 760 kB 0 [emitted] main
css/bundle.css 393 kB 0 [emitted] main
+ 180 hidden modules
Child extract-text-webpack-plugin:
+ 76 hidden modules
to explain in short, what file loader does is - it copies the file to a new path and puts that path in the css, for my case CSS file was nested within some public folder, whereas file loader would paste it in root of public, with path=[path] defined it would still manpulate the relative path. Thus disabling this completely solves my problem of relative paths and to add I have nested images folder so this evades the challenge of resolving these paths too. And dual copy of same images is something i dont need.