I've read through almost all of the posts here about CSS background images not loading, and I'm convinced I have (yet another) special case.
I've set up my webpack configuration like so (just the relevant parts):
{
test: /\.(png|svg|jpg|gif)$/,
use: [
{
loader: 'file-loader',
}
]
},
{
test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
use: [
{
loader: 'file-loader',
}
]
},
{
test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
use: [
{
loader: 'url-loader',
}
]
},
{
test: /\.less$/,
use: [
{
loader: "style-loader"
},
{
loader: "css-loader"
},
{
loader: "less-loader",
options: {
includePaths: [
path.resolve(__dirname, "assets", "less")
]
},
}
],
exclude: /node_modules/
}
I have my public path set as follows:
output: {
path: path.resolve(__dirname, "public"),
filename: "bundle.js",
publicPath: "public/"
},
When I build the webpack file everything gets moved to my /public directory just fine and my styles are rewritten properly. I can even manually find the image that is not loading in the public directory. However, this style is goofed up:
.section-intro {
background: url(public/76d7fa525cc5b3d641b9f774b7a79c92.png) center center no-repeat;
background-size: cover;
}
I thought maybe it wasn't getting set correctly, however hovering over the style in chrome seems to imply it is working - it shows localhost:8080/public/76d7fa525cc5b3d641b9f774b7a79c92.png.
Other things, such as fonts seem to load correctly. However, I did notice that manually going to localhost:8080/public/76d7fa525cc5b3d641b9f774b7a79c92.png gives me a 404. Which I find weird.
In my express server I have the following line:
this.app.use(express.static(path.resolve(__dirname, "..", "public")));
which should allow me to see the images, right?
I'm not sure if this is on the express side, or the webpack side, but it is causing me to pull my hair out. I hope someone can help.
Thank you!
I don't want to call this a fix, so I won't mark my own answer correct until someone else can confirm.
However, changing file-loader to url-loader for the png matcher fixed. It, I don't think this fully fixes the problem though. The only difference is url-loader can pass a data URL if the file is small enough. Chances are my images are small enough to make this a "fix", but if I put a larger image in I'm sure it'll break again.
I'd love to see a more complete solution.
Related
I am currently migrating an AngularJs project (v1.7.5) to Angular7.
I followed the migration instructions and everything is going pretty well.
Everything?
No, because a small problem resists over and over again.
Since I come from the AngularJs world I don't use AngularCLI and had to write my Webpack configuration by hand.
My problem:
When I try to use the pseudo-selector ":host" in my css files, it is not transformed into "_ngSomething" in my generated output (I use the ViewEncapsulation.Emulated mode).
My question:
Which module (component/loader) is in charge of transforming this pseudo-selector, and how to configure it?
I tried an "ng eject" to extract the webpack config from a project based on angularCLI, but this command seems inaccessible for the moment
Here is my current css section in webpack.conf file
{
test: /\.css$/,
use: [
"exports-loader?module.exports.toString()",
{ loader: "style-loader" },
{ loader: "css-loader", options: { importLoaders: 1 } },
{ loader: "postcss-loader" },
]
}
Thx for any help
I'm having a lot of trouble working with SVG in my webpack workflow. I'm trying to get it to display with the background: url(sample.svg) property in CSS. Using this alone did not work, so I figured I had use a loader. Here are the steps I used.
I used svg-url-loader to load the SVG.
1.
I installed svg-url-loader via npm and added this to my module.exports:
{
test: /\.svg/,
use: {
loader: 'svg-url-loader'
}
},
2.
I added this to the top of my index.js file:
require('svg-url-loader!./images/topography.svg');
3.
I added background-image with the SVG path to my CSS:
body {
background-image: url("../images/topography.svg");
background-size: 340px, auto;
min-height: calc(100vh - 100px);
margin: 50px;
background-attachment: fixed;
letter-spacing: -1px;
}
4. The SVG is not being rendered to the page. When I inspect the body in browser, I find this:
background: url(data:image/svg+xml,module.exports = __webpack_public_path__ + '8dccca4….svg';);
I don't know too much about data-uri, so maybe I am running into the issue there.
Also, I've tried this using different SVG files, and none of them worked.
I met the same exact error. After some investigation I found I added another svg loader which caused this problem, so I fixed it by deleting the other svg loader:
{
test: /\.svg/,
use: {
loader: 'svg-url-loader'
}
},
{
test: /\.svg$/,
use: [
"babel-loader",
{
loader: "react-svg-loader",
options: {
svgo: {
plugins: [{ removeTitle: false }],
floatPrecision: 2
},
jsx: true
}
}
]
}
So you maybe also added some extra loaders to handle the svg files at the same time, please check.
You can:
a) set up loaders in webpack.config.js:
example.js:
import ExampleIcon from 'assets/icons/example-icon.svg';
...
<ExampleIcon className={styles.exampleIcon} />
webpack.config.js:
{
test: /\.svg$/,
use: [
{
loader: 'babel-loader',
},
{
loader: 'react-svg-loader',
options: {
svgo: {
plugins: [{ removeTitle: false }],
floatPrecision: 2
},
jsx: true
}
}
]
},
b) or set up loaders in the import string:
import ExampleIcon from '!babel-loader!react-svg-loader!assets/icons/example-icon.svg';
...
<ExampleIcon className={styles.exampleIcon} />
I met the same problem too. We have a custom url-loader which is based on url-loader and file-loader. When the size of svg is limited to 10Kb, it will call the url-loader to process the svg,otherwise it will call the file-loader to process. It seems ok,but the bundled file shows that it was processed twice by different loaders. The base64 encoded string was exported through module.exports, but in the page the path was not replaced. This is because I used vue-cli to create project, and the svg was processed by the file-loader. When I deleted the default configuration of file-loader, it worked as expected.
I had the same problem as you. Updating my file-loader from 2.x.x to the latest version fixed the issue.
Introduction
I have already setup bundling for my Javascript files with webpack in my project. Now I am in the process of adding CSS files to the webpack configuration. So far, I have been including the CSS files manually in the HTML header by adding <link> elements for every CSS file I depend on (e.g. bootstrap, my own css, etc.). Obviously this is not very elegant and using webpack would be much better, so I would like to replace the link elements and bundle them via webpack.
This should be easy, everything is pretty much documented in the webpack documentation. After reading the documentation and experimenting a bit with webpack I have arrived at the configuration below which already works.
Problem
The problem with my current setup is that I would like to have proper source map support and that does not seem to work. By proper, I mean that I expect that when I run a development build with webpack and I inspect some element in Chrome DevTools, that I will see from which file and which line in the file a certain CSS class originated and that I can click on the CSS rules and the browser jumps to that file.
I do not want to have inline styles in the head element, because then the browser will show something like .foobar { <style>..</style>, rather then .foobar { app.css:154.
With my current setup I have all CSS files combined (but not minified) into one app.css file. This means that if I inspect a bootstrap class such as .btn then it appears as .btn { app.css:3003. However, what I want to achieve is that the browser shows it as .btn { bootstrap.css:3003.
So now I am trying to understand how webpack and the different plugins such as css-loader and min-css-extract-plugin apply CSS source maps, and how I can configure them to achieve a proper debugging experience.
I am not sure how relevant this is, but when I navigate in DevTools under Sources to webpack://./bootstrap/dist/css/bootstrap.css I see that it only contains a single line:
// extracted by mini-css-extract-plugin.
Webpack Setup
index.js:
window.jQuery = require('jquery/dist/jquery');
require('bootstrap/dist/css/bootstrap.css');
require('bootstrap/dist/js/bootstrap');
/* other dependencies */
webpack.config.js:
const devMode = process.env.NODE_ENV !== 'production';
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module: {
rules: [
{ /* Javascript rules excluded */ },
{
test: /\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader
},
{
loader: 'css-loader',
options: {
sourceMap: true
}
}
]
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader'
]
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: [
'file-loader'
]
}
plugins: [
new UglifyJSPlugin (),
new HtmlWebpackPlugin({
template: 'app/index.tpl.html'
}),
new MiniCssExtractPlugin({ filename: devMode ?
'[name].css' :
'[name].[hash].css'
})
],
Conclusion
It seems I just passed the rubber duck test. While I was writing this I arrived at a solution. I will still publish the question, maybe it can help others.
The problem was that I was also using the mini-css-extract-plugin for development and not just for production. I thought that I needed to do that, because when at first I was using the style-loaded I would get styles included in the header and the browser would show me all styles as .foobar { <style>..</style>.
However, the actual problem seemed to be, that I was not using devtools. So the solution was to add devtool: devMode ? 'cheap-module-eval-source-map' : 'source-map', to the webpack configuration to conditionally use the style-loader plugin during development builds and mini-css-extract-plugin during production builds.
webpack.config.js
{
test: /\.css$/,
use: [
{
- loader: MiniCssExtractPlugin.loader,
+ loader: devMode ? 'style-loader' : MiniCssExtractPlugin.loader,
},
{
loader: 'css-loader',
options: {
sourceMap: true
}
}
]
},
/* ... */
+ devtool: devMode ? 'cheap-module-eval-source-map' : 'source-map',
CSS blocks just went open source and I wanted to incorporate it into my React app while still using the boilerplate CRA webpack because I want to keep all the other functionality.
From what I understand the majority of the configuration is simply adding another babel-loader with the css-block plugin.
So instead of just:
{
test: /\.(js|jsx|mjs)$/,
include: paths.appSrc,
loader: require.resolve('babel-loader'),
options: {
// This is a feature of `babel-loader` for webpack (not Babel itself).
// It enables caching results in ./node_modules/.cache/babel-loader/
// directory for faster rebuilds.
cacheDirectory: true,
},
},
You follow it with:
{
test: /\.[j|t]s(x?)$/,
exclude: /node_modules/,
use: [
{
loader: require.resolve('babel-loader'),
options: {
presets: [require.resolve("babel-preset-react-app")],
cacheDirectory: true,
compact: true,
}
},
// Run the css-blocks plugin in its own dedicated loader because the react-app preset
// steps on our transforms' feet. This way, we are guaranteed a clean pass before any
// other transforms are done.
{
loader: require.resolve('babel-loader'),
options: {
plugins: [
require("#css-blocks/jsx/dist/src/transformer/babel").makePlugin({ rewriter: CssBlockRewriter }),
],
cacheDirectory: true,
compact: true,
parserOpts: {
plugins: [
"jsx",
"doExpressions",
"objectRestSpread",
"decorators",
"classProperties",
]
}
}
},
But, I cannot for the life of me get the second bit to parse anything. It's like it doesn't even exist and my CSS modules are just being referenced inside the class. Result ends up being like:
<div class="/src/test.css">
instead of
<div class="a b cD">
If anyone has any pointers of where I should try to look I would greatly appreciate it!
P.S. For reference I'll include links to the docs below since it's very new
http://css-blocks.com/
https://github.com/linkedin/css-blocks/blob/master/packages/%40css-blocks/website/config/webpack.config.dev.js
I get the example from Linkedin example /website and works fine with react-create-app scripts.
Fallow boilerplate extracted from CSS Blocks by me ralfting/boilerplate-css-blocks... Maybe this help you.
I have recently moved to WebPack (v3) from a Gulp based build system, and for the most part its pretty good. I am however struggling to get the CSS development experience to match what I previously had.
I write my CSS using SASS and then use the following setup in WebPack
Module.Rules:
{
test: /\.(s*)css$/,
exclude: /node_modules/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [
{
loader: 'css-loader',
options: { minimize: isProd }
},
{
loader: "postcss-loader"
},
{
loader: 'sass-loader'
}
],
})
},
Plugins:
new ExtractTextPlugin({
filename: 'app.bundle.css',
disable: !isProd
}),
So when I am in develpoment i.e. !isProd the ExtractTestPlugin is disabled and it uses the fallback of style-loader. This allows Hot CSS replacement. Without this the entire page would have to be refreshed to show CSS updates.
This all works great, I change CSS and a split second later its shown on screen, however, trying to debug what file or rule a CSS selector is in is proving problematic.
In this case I want to see what style is causing the font-size to be 1.5rem. I dont believe it to be in my CSS (I think its a third party library) but its nigh on impossible for me to find out the cause (I have ~50 inline styles added) and clicking the style tag link (which would previously take me to the CSS file with correct line number) now just takes me to the start of the <style> tag.
How can I improve this experience? I'd be happy with a single app.bundle.css file that is linked normally (not inline - so I get line numbers) but I really want to keep HMR for CSS.
It turns out that by adding source maps it effectively masks the delivery method (style tags) and gives the browser direct links to the source code which works correctly.
See this github post for some information.
Here is my final CSS WebPack code
{
test: /\.(s*)css$/,
exclude: /node_modules/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [
{
loader: 'css-loader',
options: { minimize: isProd, sourceMap: true }
},
{
loader: "postcss-loader",
options: { sourceMap: true }
},
{
loader: 'sass-loader',
options: { sourceMap: true }
}
],
})
},