Why is purgeCSS removing styles used by my React-Bootstrap app? - next.js

I am trying to purge unused styles from my app. But when purging it still removes used classes and the site looks broken.
I am using the following packages:
"dependencies": {
"#fullhuman/postcss-purgecss": "^4.0.3",
"autoprefixer": "^10.3.4",
"bootstrap": "^5.1.1",
"next": "^11.1.0",
"postcss-flexbugs-fixes": "^5.0.2",
"postcss-preset-env": "^6.7.0",
"react": "17.0.2",
"react-bootstrap": "^1.6.3",
"react-dom": "17.0.2",
"sass": "^1.40.1"
}
In the ./styles folder I have a layout.scss where I import #import "../node_modules/bootstrap/scss/bootstrap"; as well. I am then importing import "../styles/layout.scss"; in _app.js
I have created a postcss.config.js with the following:
module.exports = {
plugins: [
"postcss-flexbugs-fixes",
[
"postcss-preset-env",
{
autoprefixer: {
flexbox: "no-2009",
},
stage: 3,
features: {
"custom-properties": false,
},
},
],
[
"#fullhuman/postcss-purgecss",
{
content: [
"./pages/**/*.{js,jsx,ts,tsx}",
"./components/**/*.{js,jsx,ts,tsx}",
"./node_modules/react-bootstrap/**/*.js",
],
defaultExtractor: (content) => content.match(/[\w-/:]+(?<!:)/g) || [],
safelist: ["html", "body"],
},
],
],
};
I have included "./node_modules/react-bootstrap/**/*.js", as well as recommended on an earlier post. This does help a little bit but still removes used classes by react-bootstrap.
I tried adding css: ["./styles/**/*.scss, ./styles/**/*.css"] in postcss.config.js as well, which seems to do nothing either.
With all that it still looks broken:
While it should look like this:

This configured prop inside '#fullhuman/postcss-purgecss' plugin saved my modals in boostrap from purge, so I guess you need to add to the safelist the css prefix used in the exact boostrap component you need to maintain unpurged
safelist: {
standard: ['html', 'body', 'btn'],
deep: [/^col/, /^navbar/, /^nav/, , /^modal/]
},

Related

Could not resolve module "tailwindcss/nesting"

While following the official guide for TailwindCSS with PostCSS I find myself with the error:
#parcel/transformer-postcss: Could not resolve module "tailwindcss/nesting" from "C:\Users\Daniel\source\repos\AFP_Reservas\.postcssrc"
My .postcssrc file looks like this:
{
"modules": false,
"plugins": {
"postcss-import": {},
"tailwindcss/nesting": {},
"tailwindcss": {}
"autoprefixer": {
"grid": true
}
}
}
tailwind.config.js looks like this:
module.exports = {
future: {
// removeDeprecatedGapUtilities: true,
// purgeLayersByDefault: true,
},
purge: [
'./Maquetas/home.html'
],
theme: {
extend: {},
},
variants: {},
plugins: [],
}
And I have the following dependencies installed:
"devDependencies": {
"#parcel/transformer-sass": "^2.0.0",
"autoprefixer": "^10.4.0",
"parcel": "^2.0.0",
"postcss": "^8.3.11",
"postcss-import": "^14.0.2",
"postcss-nested": "^5.0.6",
"tailwindcss": "^1.9.6"
}
Am I missing something? I tried installing #tailwindcss/nesting, but the nesting module is supposed to be a part of the core tailwindcss module.
Because I'm using Tailwind version 1.9 (to support Internet Explorer due to client needs) I can't use tailwindcss/nesting, according to the 1.9 documentation you have to use postcss-nested.

How to (successfully) bundle css for dynamic multi-page app using Webpack 5

I am trying to use Webpack 5 to bundle assets for a dynamic multi-page Django application. Using WebpackManifestPlugin and django-manifest-loader. I have this working fine for JavaScript, but I've tried every tip I can find and have not been able to make it work for css.
I have created a css file to use as an entry point and (for proof of concept) imported 1 of the application's css files into that. The output file that is produced from that is effectively empty. If I add any rules directly to the entry .css file, then those rules show up in the output file, but the #import … is gone and the rules from the imported file are not present.
Incidentally, if I purposefully mis-name the file in the import, then bundling fails, so I think the imported css is being correctly recognized and processed, then omitted. Based on some of the reading I have done, I added sideEffects: true (see django/webpack.config.js contents below) but that did not change the results.
Any advice? I've been tearing my hair out for almost 2 days on this.
django/ui/src/index.css
#import 'css/components/navigation/notifications.css';
Resulting django/dist/main.512f6e37f2c08258132d.css
/*!******************************************************************************************************!*\
!*** css ./node_modules/css-loader/dist/cjs.js!./ui/src/css/components/navigation/notifications.css ***!
\******************************************************************************************************/
/*!***********************************************************************************************************!*\
!*** css ./node_modules/css-loader/dist/cjs.js!./node_modules/sass-loader/dist/cjs.js!./ui/src/index.css ***!
\***********************************************************************************************************/
Here's what I have in my django/webpack.config.js file:
/*global __dirname, module, require*/
const path = require('path');
const {CleanWebpackPlugin} = require('clean-webpack-plugin');
const {WebpackManifestPlugin} = require('webpack-manifest-plugin');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
entry: {
main: ['./ui/src/index.js', './ui/src/index.css'],
},
devtool: 'inline-source-map',
plugins: [
// Remove outdated assets from the output dir
new CleanWebpackPlugin(),
// Generate the required manifest.json file
new WebpackManifestPlugin(),
new MiniCssExtractPlugin({
filename: '[name].[contenthash].css',
}),
],
module: {
rules: [
{
test: /\.(sa|sc|c)ss$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader",
"sass-loader",
],
sideEffects: true,
},
{
test: require.resolve('vue'),
loader: 'expose-loader',
options: {
exposes: ['Vue'],
},
},
],
},
output: {
// Rename files from example.js to example.8f77someHash8adfa.js
filename: '[name].[contenthash].js',
path: path.resolve(__dirname, 'dist'),
// https://webpack.js.org/migrate/5/
// > * 404 errors pointing to URLs containing auto
// > - Not all ecosystem tooling is ready for the new default
// > automatic publicPath via output.publicPath: "auto"
// > - Use a static output.publicPath: "" instead.
publicPath: '',
},
resolve: {
alias: {
// If using the runtime only build
vue$: 'vue/dist/vue.runtime.esm.js', // 'vue/dist/vue.runtime.common.js' for webpack 1
// Or if using full build of Vue (runtime + compiler)
// vue$: 'vue/dist/vue.esm.js' // 'vue/dist/vue.common.js' for webpack 1
},
},
};
In case it's helpful, here's what is in my django/package.json:
{
"name": "hub-ui",
"version": "0.0.1",
"description": "",
"main": "index.js",
"scripts": {
"start": "webpack --watch --mode=development",
"build": "webpack --mode=production",
"dev": "webpack --mode=development"
},
"keywords": [],
"author": "Cliosoft",
"devDependencies": {
"clean-webpack-plugin": "^3.0.0",
"css-loader": "^6.3.0",
"eslint": "^7.32.0",
"eslint-plugin-vue": "^7.18.0",
"expose-loader": "^3.0.0",
"mini-css-extract-plugin": "^2.3.0",
"node-sass": "^6.0.1",
"sass-loader": "^12.1.0",
"style-loader": "^3.2.1",
"webpack": "^5.0.0",
"webpack-cli": "^4.8.0",
"webpack-manifest-plugin": "^4.0.2"
},
"dependencies": {
"bootstrap": "^5.1.1",
"bootstrap-vue": "^2.21.2",
"vue": "^2.6.14"
},
"engines": {
"node": "~16.9",
"npm": "~7.23"
}
}
This turned out to be a "did you turn it on?" kind of problem.
The css file I was using as the test case was supposedly a copy of a css file from its previous location, but it was actually an empty file of the same name. Doh!
Once I actually copied the styles into the .css file, everything started to work correctly.
Hopefully, this will be of some help to someone in the future. If you spend many days trying to figure out what's wrong with your package.json, webpack.config.js, etc. and can't find anything wrong with them, then maybe the problem is somewhere else like not having the content in your source files that you think you have.

vue ssr application styling breaks when upgrade to css-loader 4.0.0

Issue
I have a Vue SSR application which is rendering the styling perfectly OK when using css-loader version 3.6.0 but when i update my application to css-loader 4.0.0 i no longer get any styling in my application.
With css-loader 3.6.0, when i view the html page for my application i see the "style" tag in the "head" tag of my HTML document.
With css-loader 4.0.0, when i view the html page for my application the "style" tag is missing
NOTE: Vue CLI was NOT used to create this project as i am doing Server Side rendering
Does anyone know of any changes I have to make to my application to upgrade to the latest css-loader
Styling
My application uses inline styles in each component, i am not using any css files. Below is a sample of what one of my components look like.
<template>
....
</template>
<script>
....
</script>
<style scoped>
header {
css added here
}
other styles added here
</script>
Dependencies
The following are my working dependencies
"dependencies": {
"core-js": "~3.6.5",
"dotenv": "~8.2.0",
"express": "~4.17.1",
"regenerator-runtime": "~0.13.7",
"vue": "~2.6.12",
"vue-router": "~3.4.7",
"vue-server-renderer": "~2.6.12",
"vuex": "~3.5.1",
"vuex-router-sync": "~5.0.0"
},
"devDependencies": {
"#babel/cli": "~7.12.1",
"#babel/core": "~7.12.3",
"#babel/preset-env": "~7.12.1",
"babel-loader": "~8.1.0",
"copy-webpack-plugin": "~6.2.1",
"cross-env": "~7.0.2",
"css-loader": "~1.0.1",
"file-loader": "~6.0.0",
"nodemon": "~2.0.6",
"npm-run-all": "~4.1.5",
"vue-loader": "~15.9.5",
"vue-template-compiler": "~2.6.12",
"webpack": "~4.44.2",
"webpack-cli": "~3.3.12",
"webpack-dev-server": "~3.11.0",
"webpack-merge": "~4.2.2",
"webpack-node-externals": "~2.5.2"
},
Webpack configs
I have 3 config webpack files, 1 base, 1 to create the client bundle and 1 to create the server bundle. In the base config i have the following regarding css/vue loaders
const VueLoaderPlugin = require('vue-loader/lib/plugin');
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
},
},
},
{
test: /\.css$/,
use: [
'vue-style-loader',
'css-loader',
],
},
// other loaders
],
},
plugins: [
new VueLoaderPlugin(),
// other plugins
}
Discussion and workaround for SSR apps: https://github.com/vuejs/vue-style-loader/issues/46#issuecomment-670624576
This also works for non-SSR apps, but in that case vue-style loader can simply be replaced with style-loader: https://github.com/vuejs/vue-style-loader/issues/42#issuecomment-678586075

Nuxt & Firebase - IE 11 (Object doesn't support property or method 'values')

I'm having trouble getting Nuxt and babel when trying to polyfill firebase for IE11. I'm not sure what I am missing.
useBuiltIns: "usage" IE11 returns an error of Object doesn't support property or method 'values'
When useBuiltIns: "entry" IE11 returns an error of Object doesn't support property or method 'assign'
nuxt.config.js
babel: {
presets({ envName }) {
const envTargets = {
client: {
browsers: ["last 2 versions"],
ie: 11
},
server: {
node: "current"
},
}
return [
[
"#nuxt/babel-preset-app",
{
useBuiltIns: "usage",
polyfills: ['es6.array.iterator', 'es6.promise', 'es6.object.assign', 'es7.object.values', 'es7.promise.finally'],
targets: envTargets[envName]
}
]
]
},
package.json
"dependencies": {
"#babel/plugin-transform-runtime": "^7.10.1",
"#babel/polyfill": "^7.10.1",
"#babel/runtime-corejs2": "^7.10.2",
"#vue/babel-preset-app": "^4.4.1",
"bootstrap": "^4.5.0",
"bootstrap-vue": "^2.15.0",
"core-js": "2.6.11",
"firebase": "^7.15.0",
"node-sass": "^4.14.1",
"nuxt": "^2.12.2",
"sass-loader": "^8.0.2",
"vue-select": "^3.10.3"
},
Firebase has its own polyfill package included in the sdk.
You need to import that package by:
Creating /plugins/polyfills.js containing:
import '#firebase/polyfill';
You can, instead, import in that file the polyfills you think you need individually, so the final bundle will be smaller. Example:
import '#firebase/polyfill/node_modules/core-js/features/object/values';
Add to your nuxt.config.js:
plugins: [
{ src: '~plugins/polyfills', mode: 'client' },
],

Vuejs 2.5+ Webpack 4+ not loading CSS files

Currently I'm trying to setup a basic Vue project with webpack 4 enabled. The vue skeleton is based on the Microsoft SPA templates dotnet core. It seems to be that everything is running fine, except that external CSS files somehow are not loaded into the project and it is now bugging me for quite some time with the question why are those CSS files not loading.
What I basically did is 'dotnet new vue' (you need the Microsoft SPA templates installed) and after the creation of the project I started with updating the packages. Currently I have the following package.json file:
{
"name": "Dashboard",
"private": true,
"version": "0.0.1",
"scripts": {
"build:development": "webpack"
},
"devDependencies": {
"#types/webpack-env": "^1.13.6",
"ajv": "^6.5.2",
"aspnet-webpack": "^3.0.0",
"awesome-typescript-loader": "^5.2.0",
"bootstrap": "^4.1.1",
"coa": "^2.0.1",
"css-loader": "^1.0.0",
"event-source-polyfill": "^0.0.12",
"extract-text-webpack-plugin": "^4.0.0-beta.0",
"file-loader": "^1.1.11",
"isomorphic-fetch": "^2.2.1",
"jquery": "^3.3.1",
"mini-css-extract-plugin": "^0.4.1",
"popper.js": "^1.14.3",
"style-loader": "^0.21.0",
"typescript": "^2.9.2",
"url-loader": "^1.0.1",
"vue": "^2.5.16",
"vue-loader": "^15.2.4",
"vue-property-decorator": "^7.0.0",
"vue-router": "^3.0.1",
"vue-style-loader": "^4.1.0",
"vue-template-compiler": "^2.5.16",
"webpack": "^4.16.0",
"webpack-cli": "^3.0.8",
"webpack-dev-middleware": "^3.1.3",
"webpack-hot-middleware": "^2.22.2",
"webpack-merge": "^4.1.3",
"webpack-node-externals": "^1.7.2"
},
"dependencies": {}
}
And this is my webpack.config.file:
const path = require('path');
const webpack = require('webpack');
const CheckerPlugin = require('awesome-typescript-loader').CheckerPlugin;
const bundleOutputDir = './wwwroot/dist';
const VueLoaderPlugin = require('vue-loader/lib/plugin');
module.exports = {
mode: 'development',
stats: {
modules: false
},
context: __dirname,
resolve: {
extensions: [ '.js', '.ts' ]
},
entry: {
'main': './ClientApp/boot.ts'
},
module: {
rules: [
{
test: /\.vue\.html$/,
include: /ClientApp/,
loader: 'vue-loader',
options: { loaders: { js: 'awesome-typescript-loader?silent=true' } }
},
{
test: /\.ts$/,
include: /ClientApp/,
use: 'awesome-typescript-loader?silent=true'
},
{
test: /\.css$/,
use: ['vue-style-loader', 'css-loader']
},
{
test: /\.(png|jpg|jpeg|gif|svg)$/,
use: 'url-loader?limit=25000'
}
]
},
output: {
path: path.join(__dirname, bundleOutputDir),
filename: '[name].js',
publicPath: 'dist/'
},
plugins: [
new VueLoaderPlugin(),
new CheckerPlugin(),
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"development"'
}
}),
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./wwwroot/dist/vendor-manifest.json')
}),
new webpack.SourceMapDevToolPlugin({
filename: '[file].map',
moduleFilenameTemplate: path.relative(bundleOutputDir, '[resourcePath]')
})
]
};
And I have included the CSS file in the following ways:
In app.ts (I added them both just to test):
import '../navmenu/navmenu.css';
require('../navmenu/navmenu.css');
In boot.ts
import './components/navmenu/navmenu.css';
require('./components/navmenu/navmenu.css');
Or in the original file (navmenu.vue.html) (when a default SPA skeleton has been generated):
<style src="./navmenu.css" />
On all these locations the css file is not included/used in the frontend. I've also tried different approaches in the webpack.config file such as using the extract-text-webpack-plugin.
The basic idea behind is that the SPA template of Microsoft is using Webpack 2 (and other old versions of different packages) and I'm trying to update these to the latest versions.
Hopefully someone can help me out :-)
I've figured it out. Somehow webpack 4 is not picking up the CSS files by itself. You need to install the following plugin first:
MiniCssExtractPlugin
After that in the webpack config add the following configuration:
{
test: /\.(s*)[a|c]ss$/,
use: [
"vue-style-loader",
MiniCssExtractPlugin.loader,
"css-loader",
"sass-loader"
]
}
And add the mini css extract plugin also to the plugins section:
new MiniCssExtractPlugin({
filename: "[name].css"
})
And you should be good to go!
On your main.vue or any vue page inside style add #import "path"
<style>
#import "https://stackpath.bootstrapcdn.com/bootstrap/4.1.2/css/bootstrap.min.css";
#import "../assests/css/style.css"
</style>

Resources