Is there a way to add hash values to images that are referenced in CSS when you compile using Webpack?
I'm using React, and have separate scss files for each component file (e.g header.js & header.scss). Within some of the scss files, I have a background image. However, my server has super high caching levels, and is caching the images within the compiled css files.
What I'd like to do is, during the css compilation, add a hash value to each image reference, which would update on every build. So for example, it would compile to this:
.background-class {
background-image: url('images/my-image.jpg?0adg83af0');
}
I've tried to use the url-loader, but because these images aren't being referenced in the JS files, I don't think they're being picked up?
I ended up using a combination of PostCSS and PostCSS CacheBuster. If anyone wants to add this to their webpack setup, you need to run npm i postcss-loader postcss-cachebuster, then in your webpack.config.js, add const PostCssCacheBuster = require('postcss-cachebuster'); to the top of your file, and add the following loader config in between css-loader and sass-loader (obviously if you use this setup):
loader: 'postcss-loader',
options: {
sourceMap: true,
plugins: () => [
PostCssCacheBuster({
imagesPath: "/src/Frontend",
cssPath: "/" + distributionPath,
supportedProps: [
'background',
'background-image'
],
paramName: 'v='
})
]
}
},
Related
The goal is to configure a development environment for Tailwindcss v3 that supports #import and the removal of unused custom CSS classes.
I am not using a bundler. The project depends on just HTML, CSS, and JS i.e. no frameworks. If it's important, I use VS Code.
This is what I've tried.
Project's configuration:
// tailwind.config.js
const defaultTheme = require('tailwindcss/defaultTheme');
module.exports = {
content: [
'./src/**/*.{html,js}',
],
darkMode: 'media',
theme: {
extend: {
fontFamily: {
primary: '"Inter", sans-serif',
mono: ['"DM Mono"', ...defaultTheme.fontFamily.mono]
}
},
},
variants: {
extend: {}
},
plugins: [
// ...
]
};
// postcss.config.js
module.exports = {
plugins: [
require('postcss-import'),
require('tailwindcss'),
require('autoprefixer'),
require('cssnano')
]
/* styles.css*/
#import "tailwindcss/base";
#import "./custom-base-styles.css";
#import "tailwindcss/components";
#import "./custom-components.css";
#import "tailwindcss/utilities";
#import "./custom-utilities.css";
And this is my commend line:
$ npx tailwindcss -i ./src/css/styles.css -o ./css/styles.css --watch
Running just the above command, the setup does not inline the custom*.css files.
To achieve inlining, I also have to execute below, which on the surface, seems as if it should not be necessary.
$ npx postcss-cli './src/css/styles.css' -o './css/styles.css' -w
The end result is, Tailwindcss is not removing my unused custom styles, even when wrapped in the required #layer {}.
Step 5 here (Using PostCSS) just says to start your build process and does not offer any details.
Step 4 here (Tailwind CLI) only says to start the Tailwind CLI process.
So, what am I missing?
Do I need to use a bundler? If so, my preferred one is Rollup.
Other details:
autoprefixer:^10.4.0
cssnano:^5.0.10
postcss-cli:^9.0.2
postcss-import:^14.0.2
tailwindcss: "^3.0.7
Your intuition is correct. You do not need to run post-cli. PostCSS will execute once you update your Tailwind command.
You are missing the --postcss parameter.
Assuming that postcss.config.js is in your project's root, copy this to the script section of your package.json:
"tw": "tailwindcss -i ./src/css/styles.css -o ./css/styles.css --postcss postcss.config.js --watch"
Then from the command line at the project's root, run:
npm run tw
Note: with the above command, Tailwind will not rebuild the output file after the HTML file has been saved. You'll need to edit and save one of the CSS source files to initiate a rebuild. (Perhaps I still have a configuration problem?)
One other item, how are you testing for the removal of unused custom classes?
The mistake I made was just commenting out the HTML utilizing the custom class and then looking at the CSS output to see if the class was removed. But Tailwind (as documented somewhere) won't remove a class if the class appears anywhere in the markup, even in a commented line. If you're testing your build process, rename the class in the markup to anything, and then Tailwind will drop the custom class from the CSS output.
I currently have a Angular project which I am looking to purge the css using purgecss.
I have got everything working but when I import node_modules it struggles as it cannot find the paths which are located in the node_modules folder.
I have the current app.scss file
#import "#fortawesome/fontawesome-pro/scss/fontawesome";
#import "#fortawesome/fontawesome-pro/scss/regular";
#import "./_buttons";
The buttons class is actually called _buttons.scss but for some reason the postcss does not pick this up so I have to define the _ although I know it can be imported without.
So that is the first issue which I would like to fix if possible but the second is that when importing font awesome, it finds the font awesome package but it cannot find the file variables after I looked into the package I can see that there is no relative path and it is just variables. As this is a package is there a way to mitigate this issue within webpack to stop this from happening and the build from failing?
Here is my webpack.config.js
const purgecss = require("#fullhuman/postcss-purgecss");
module.exports = {
module: {
rules: [
{
test: /\.scss$/,
loader: "postcss-loader",
options: {
modules: true,
importLoaders: 1,
ident: "postcss",
syntax: "postcss-scss",
plugins: () => [
require("postcss-import"),
require("autoprefixer"),
purgecss({
content: ["./**/*.html"],
whitelistPatterns: [/^cdk-|mat-/],
defaultExtractor: content =>
content.match(/[\w-/:]+(?<!:)/g) || []
})
]
}
}
]
}
};
I've tried setting importLoaders: 1 which didn't seem to make a difference at all.
How can I get postcss to run from the files root directory? Even without the ./ which is used in the fontawesome package and also the postcss recognising the scss file without having to explicit prefix everything with _
Edit (font awesome error):
fontawesome.scss
#import 'variables';
#import 'mixins';
#import 'core';
#import 'larger';
#import 'fixed-width';
#import 'list';
#import 'bordered-pulled';
#import 'animated';
#import 'rotated-flipped';
#import 'stacked';
#import 'icons';
#import 'screen-reader';
Error: Failed to find 'variables'
Well, maybe this could help you, in the webpack.config.js you should add, specifically in purgeCss -> content, the diferents paths.
content: [
"./node_modules/name_package/**/**/*.{css,scss}"
]
I had the same issue using NextJS in production.
After a day of wasting time, finally, i found the souloution. There is a postcss plugin to do it for us!
First, install it using npm as dev dependency:
npm i postcss-url -D
Now you must update your webpack.config.js to use postcss-url. Just add postcss-url directly after postcss-import
It worked for me, when I removed the
require("postcss-import") from the webpack.config.js file. It took me 1 day to resolve it. Found the explanation here: Webpack style-loader / css-loader: url() path resolution not working
I was setting the Webpack loaders config for .css and .scss files, I noticed that when using --mode production I'm getting minimized CSS as the final output without even using a minimizer explicitly, here's my loaders config:
{
// Match .css or .scss
test: /\.s?css$/,
use: [
isProd
// In production extract the CSS into separate files
? {
loader: MiniCssExtractPlugin.loader,
options: {
hmr: !isProd
}
}
// In development inject the styles into the DOM
: 'style-loader',
{
loader: 'css-loader'
},
{
loader: 'sass-loader',
options: {
sourceMap: false
}
}
]
}
I'm using sass-loader with node-sass and mini-css-extract-plugin to extract the CSS into separate files, which suggests using optimize-css-assets-webpack-plugin for minimizing the CSS by overriding optimization.minimizer, but I'm already getting minimized output without installing this plugin.
To find what's causing this behavior I tried processing CSS files with and without sass-loader and I found out that sass-loader might be causing this behavior but it doesn't have any option for minimizing the CSS.
So what's causing this behavior? And do I even still need optimize-css-assets-webpack-plugin if my CSS files are minimized?
Option outputStyle in sass-loader options determines the output format of the final CSS style. Default: nested.
For more detailed https://github.com/sass/node-sass#outputstyle
To disable minification, set this option to expanded:
{
loader: 'sass-loader',
options: {
sassOptions: {
outputStyle: 'expanded'
}
}
}
For minify css i reccomend plugin css-nano. It is flexible in settings. It's good work with postcss-loader.
According to the webpack docs,
webpack v4+ will minify your code by default in production mode.
So it's not sass-loader doing the minification, it's just that removing that means webpack isn't processing your SCSS into CSS and therefore not creating a file to be minified.
I'd say if you're happy with simple minification the default is probably fine for production. Other tools might give you more control over the final output including things like source maps, removing duplicate rules, dumping old prefixes, etc.
Can someone please tell me if it is worth using Sass/SCSS with React?
I finally set up SCSS to work with Create-React-App without ejecting, but it doesn't seem to work well since it is recommended to use CSS modules with each component.
How would I go about sharing variables, mixins, etc. Is it better just to use CSS?
Any help would be greatly appreciated.
The 2. version of create-react-app supports Sass now. Install node-sass (e.g. npm install node-sass) to enable it. For further instructions, check out the documentation. If you need an example, check out this application's Navigation component.
I highly recommend using scss, as you can still use CSS-Modules with SCSS.
I'm not familiar with the create react app setup, but usually you'd configure webpack with style-loaders like so:
{
test: /\.scss$/,
loaders: [
'style-loader',
{ loader: 'css-loader', options: { modules: true } },
'sass-loader',
],
exclude: [srcDir + '/assets/scss/']
},
The loaders will execute backwards, starting with the sass-loader which will transpile your scss to normal css, then with the css-loader and the option "modules: true" these styles will be made available to use as modules.
Of course it could look a bit different but that would be the basic approach to use css modules with scss.
To share variables and mixins I always use a global scss file, which will be required in the app (e.g. in the app.js). However you'll still have to import that file/s in every component-scss where you need the variables and mixins.
// GLOBAL STYLES
{
test: /\.scss$/,
loaders: [
'style-loader',
'css-loader',
'sass-loader',
],
include: [srcDir + '/assets/scss/']
},
Alternatively you could use PostCSS-Properties to make your components even more flexible (e.g. to provide different themes for your app, without explicitly importing the files in your component styles) but afaik those are not supported by IE and would require you to add specific postcss loaders.
see http://cssnext.io/features/#custom-properties-var
The flexibility and maintainability that SASS provides is very useful for big projects especially with react.
However, don't let yourself be influenced by my or the opinion of others - you're free to use the things you're most comfortable with and should always question the way things are done.
create-react-app V2 corresponding section doc: (support out of the box)
https://facebook.github.io/create-react-app/docs/adding-a-sass-stylesheet#docsNav
Using Sass/SCSS is pretty much completely unlinked to React. Sass is compiled to regular CSS, and then you use it as such within your HTML or React.
As for sharing variables, when you use #import it basically just takes everything from the file your importing and pastes it in, so you could just make a _variables.sccs file and import it into each file where you want to use your global variables.
//variables.scss
$primary: red;
$secondary: blue;
//main.scss
#import 'variables';
body {
background-color: $primary;
color: $secondary;
}
I am using webpack 2 and react-bootstrap in my project ; I can't find how to have bootstrap CSS styles properly applied it seems like the .css file is not loaded, no matter which import statement I tried to use.
As far as I understand I do not need the full bootstrap package with javascript etc. since I am using react-bootstrap ; I just need the CSS. So I added this in my main.js file:
import 'bootstrap/dist/css/bootstrap.css';
It seems to work (no error message) but the styles are not applied...
I configured the css loader in my webpack config file as described on webpack 2 documentation.
Any help would be appreciated :)
When setting modules: true in the css-loader, the CSS is locally scoped by default, but you need them to be available globally. The simplest solution is to remove modules: true entirely. You could still use modules in your own CSS files by using :local.
But if you would like to use modules, there are some workarounds to import globals.
Defining separate rules
Instead of enabling modules for all the CSS files, you can make two different rules, that match the desired files. So let's say all CSS imports from node_modules should be treated as regular (global) CSS. The rules would look like this:
{
// For all .css files except from node_modules
test: /\.css$/,
exclude: /node_modules/,
use: [
'style-loader',
{ loader: 'css-loader', options: { modules: true } }
]
},
{
// For all .css files in node_modules
test: /\.css$/,
include: /node_modules/,
use: ['style-loader', 'css-loader']
}
Of course you can be more specific in what you want to include/exclude, if you don't want the entire node_modules.
Specifying loaders inline
You can specify the loaders in the import and webpack will use those over the configured ones. You would import bootstrap as follows:
import '!style-loader!css-loader!bootstrap/dist/css/bootstrap.css';
This is just a quick workaround without having to change any config, but it's probably not desirable, especially when having multiple such cases.