Importing CSS file in React - Webpack / Inline styles - css

I was assigned a project where I need to stylize an application built with React + Wepback.
When I look at the output in the inspector element, I can see that most elements have a dynamically created class that looks like this: css-18s71b6
Looking at the styles, it's a stylesheet that's imported from a node module... Microsoft Frabric to be exact.
I'm able to add my custom stylesheet so that I can add my className to the elements but the problem I'm having is that my styles are never considered because React's dynamic css rule always has priority.
The only way to overcome this is by putting !important in all my css rules which doesn't make sense.
My guess is that I need to tell React + Webpack to use my stylesheet when compiling the dynamic inline css styles or to disable dynamic classes.
I'm completely new to React + Webpack. I've been working on this for hours, reading and testing but never found any solution. Any input is appreciated.
For what it's worth, my webpack.bable.js file looks like this
module: {
loaders: [{
test: /\.js$/, // Transform all .js files required somewhere with Babel
loader: 'babel-loader',
exclude: /node_modules/,
query: options.babelQuery,
}, {
test: /\.css$/,
include: /node_modules/,
loaders: ['style-loader', 'css-loader'],
},
[... more stuff ...]
}

After countless hours, I finally found the answer and am posting it in case other people have the same problem.
The problem is that in the config file, when you include: /node_modules/ it won't include your custom CSS styles. You need a separate loader to accomplish this.
My final webpack config looks like this
[...] {
// Preprocess our own .css files
test: /\.css$/,
exclude: /node_modules/,
use: ['style-loader', 'css-loader'],
},{
test: /\.css$/,
include: /node_modules/,
loaders: ['style-loader', 'css-loader'],
} [...]
Notice that the first rule excludes node_modules and the second one includes /node_modules/
For more information on the topic, visit this forum post on Github.

Related

pseudo-selector :host not "compiled"

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

Improve CSS debugging experience in WebPack

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 }
}
],
})
},

Webpack file-loader and images in CSS

I'm using images in my stylesheet (less) fine by doing:
.foo { background: url('../images/foo.png') }
When using HMR they're base64 encoded into the stylesheet which I'm fine about. However when compiling for production I want the images not to be embedded in the stylesheet. I've tried both url-loader and file-loader.
With url-loader I couldn't get it to emit the images properly. If I set no limit then the files were emitted to output/images/ and had the right size but weren't valid images. If I set the limit to something smaller than 8k the images were emitted to output and correct.
In either case the emitted images appeared in the CSS like so (example when using url-loader with limit=1):
url(data:image/png;base64,bW9kdWxlLmV4cG9ydHMgPSBfX3dlYnBhY2tfcHVibGljX3BhdGhfXyArICJhMDdjZWVkMGRiZTNlMjk5ODY5NWQ3ZjM4MzYxZDY1Zi5wbmciOw==);
Which when you decode it is:
module.exports = __webpack_public_path__ + "a07ceed0dbe3e2998695d7f38361d65f.png";
How do I get the css to use the URL rather than trying to base64 encode the value?
This is my webpack (still on webpack 1) loaders config:
{
test: /\.jsx?$/,
loader: 'babel-loader',
exclude: /node_modules/,
},
{
test: /\.css$/,
loader: ExtractTextPlugin.extract('style-loader', 'css!postcss'),
},
{
test: /\.less$/,
loader: ExtractTextPlugin.extract('style-loader', 'css!less!postcss'),
},
{
test: /\.(png|jpg|gif)$/,
loader: 'file-loader?name=/images/[name].[ext]'
}
Update: Turns out disabling the less-loader stops the URLs from being encoded when using the url-loader (but the images are still not valid) but not when using the file-loader.
Update 2: Added a custom loader at the end of the css!less!postcss loaders and the source still has the image URL of ../images/foo.png so it appears the issue is further down the line. Also tried removing the ExtractTextPlugin but the compiled JS for the image then has the Base64 encoded value for the export like the CSS does.
It seems that having the 2 ExtractTextPlugins (for the css & less tests were causing the problems) as I don't have any css files I removed the first and it's now working as expected.

Minify and add hash to css files webpack

I am using webpack for my Angular 2 project.
Inside the src folder I have a global css folder and component and other folders.
My webpack.config.js is outside the src folder.
I am using CopyWebpackPlugin to copy the css folder to the dist folder :
new CopyWebpackPlugin([
{ from: 'src/css', to: 'css'}
]),
I am using the following loader also for css :
exports.css = {
test: /\.css$/,
loader: 'to-string!css?-minimize!postcss',
};
But the deal is that I want to add a hash to each css file name and also then change the css file name in the index.html since these are global files included in the index.html. What is the best way to achieve this?
EDIT : While changing the code i realised that the loader property only applies to the css inside the components folder and not to the outside folder. why is this?
Use https://github.com/webpack/extract-text-webpack-plugin.
example in webpack.config.js
config.plugins.push(
new ExtractTextPlugin({filename: 'css/[name].[hash].css'})
);
...
config.module = {
rules: [
{
test: /\.css$/,
exclude: root('src', 'app'),
loader: ExtractTextPlugin.extract({ fallbackLoader: 'style-loader', loader: ['css', 'postcss']})
}
]
}
Do not use CopyWebpackPlugin for application sources. This will bypass Webpack's loaders and lock you out of all of Webpack's features.
Simply use ES6 imports, require, require.ensure or System.import to require your stylesheets. Alterantively, as MichaƂ suggested, use ExtractTextPlugin in production when applicable.

Adding less support to a production webpack configuration (from Facebook's create-react-app)

I have forked (or ejected) off Facebook's create-react-app project, with the requirement to add a few additional tools (e.g. testing, redux, less etc.), and the perhaps naive assumption that straying a bit off the path wouldn't be too much of a problem.
I think I have just about managed to add less using the following webpack.config.dev.js:
//......
module: {
preLoaders: [
{
test: /\.js$/,
loader: 'eslint',
include: paths.appSrc,
}
],
loaders: [
// Process JS with Babel.
{
test: /\.js$/,
include: paths.appSrc,
loader: 'babel',
query: require('./babel.dev')
},
{
test: /\.css$/,
loader: 'style!css!postcss'
},
{
test: /\.less$/,
loader: 'style!css!postcss!less'
},
{
test: /\.json$/,
loader: 'json'
},
//......
}
]
},//.....
I have left the CSS loader in there (perhaps incorrectly) so that I can bring in the react/bootstrap library. Perhaps there is a better way of doing this.
Anyway, I am confused about how to add a pre-processor into webpack.config.prod.js. Here is a snippet (with Facebook's helpful comments):
loaders: [
// Process JS with Babel.
{
test: /\.js$/,
include: paths.appSrc,
loader: 'babel',
query: require('./babel.prod')
},
// The notation here is somewhat confusing.
// "postcss" loader applies autoprefixer to our CSS.
// "css" loader resolves paths in CSS and adds assets as dependencies.
// "style" loader normally turns CSS into JS modules injecting <style>,
// but unlike in development configuration, we do something different.
// `ExtractTextPlugin` first applies the "postcss" and "css" loaders
// (second argument), then grabs the result CSS and puts it into a
// separate file in our build process. This way we actually ship
// a single CSS file in production instead of JS code injecting <style>
// tags. If you use code splitting, however, any async bundles will still
// use the "style" loader inside the async code so CSS from them won't be
// in the main CSS file.
{
test: /\.css$/,
// "?-autoprefixer" disables autoprefixer in css-loader itself:
// https://github.com/webpack/css-loader/issues/281
// We already have it thanks to postcss. We only pass this flag in
// production because "css" loader only enables autoprefixer-powered
// removal of unnecessary prefixes when Uglify plugin is enabled.
// Webpack 1.x uses Uglify plugin as a signal to minify *all* the assets
// including CSS. This is confusing and will be removed in Webpack 2:
// https://github.com/webpack/webpack/issues/283
loader: ExtractTextPlugin.extract('style', 'css?-autoprefixer!postcss')
// Note: this won't work without `new ExtractTextPlugin()` in `plugins`.
},
How can I add a less pre-processor step in a stable and performant way?
For context my index.js imports look as follows:
import React from 'react';
import ReactDOM from 'react-dom';
import 'bootstrap/dist/css/bootstrap.css';
import 'bootstrap/dist/css/bootstrap-theme.css';
import { CommentsSectionContainer } from './components/CommentsSection';
import './index.less';
Install less and less-loader from npm or yarn:
npm install --save-dev less less-loader
Follow this link to install extract-text-webkit-plugin:
https://github.com/webpack/extract-text-webpack-plugin
First you need to add the loader in the loaders array, after css probably makes sense for readability. It will look like this:
{
test: /\.less$/,
loader: ExtractTextPlugin.extract("style-loader", "css-loader!less-loader")
}
Then initialize the plugin in the plugins array:
new ExtractTextPlugin('[name].css')
Thaaaaaat should do it with another yarnpkg start

Resources