Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DRAFT] Use postcss-drop-empty-css-vars to remove empty CSS variables #36738

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

julien-deramond
Copy link
Member

@julien-deramond julien-deramond commented Jul 14, 2022

Warning
Heavily draft

Linked to the discussion in #36597 and potentially addresses #36595.
I've tried here to create a very simple PostCSS plugin to remove empty CSS vars.

Plugin repo: https://github.com/julien-deramond/postcss-drop-empty-css-vars
Plugin code (very basic just to test the idea): https://github.com/julien-deramond/postcss-drop-empty-css-vars/blob/main/index.js

The plugin is deployed in 0.0.0 version

Running npm run css with and without this plugin gives this diff:

2801d2800
<   --bs-btn-font-family: ;
3506d3504
<   --bs-dropdown-box-shadow: ;
3620d3617
<   --bs-nav-link-font-weight: ;
3794d3790
<   --bs-nav-link-font-weight: ;
4168d4163
<   --bs-card-box-shadow: ;
4173,4175d4167
<   --bs-card-cap-color: ;
<   --bs-card-height: ;
<   --bs-card-color: ;
4482,4483d4473
<   --bs-breadcrumb-bg: ;
<   --bs-breadcrumb-border-radius: ;
5191d5180
<   --bs-toast-color: ;
5257d5245
<   --bs-modal-color: ;
5271d5258
<   --bs-modal-footer-bg: ;
5549d5535
<   --bs-tooltip-margin: ;
6094d6079
<   --bs-offcanvas-color: ;

/CC @mdo for thoughts

@ffoodd
Copy link
Member

ffoodd commented Jul 15, 2022

A simple sidenote here: automating this would prevent us from using advanced usages based on the space toggle technique.

I don't think Bootstrap will ever use this, but that's to be mentionned on your PostCSS plugin's Doc at least 😉

@XhmikosR
Copy link
Member

Might be worth opening an issue upstream in clean-css (if there isn't any already). Maybe they could implement this there too.

@julien-deramond
Copy link
Member Author

julien-deramond commented Jul 20, 2022

Might be worth opening an issue upstream in clean-css (if there isn't any already). Maybe they could implement this there too.

Yes good idea, I need to dig into their repo. clean-css/clean-css#1180 might give some clues (+ clean-css/clean-css@a6da53a)

@jaradc
Copy link

jaradc commented May 1, 2023

I love the idea of this. I attempted to implement in Webpack but after building (npm run build), I still see the empty variables in the outputted CSS. The empty variables I see are:

bs-btn-font-family
bs-dropdown-box-shadow
bs-nav-link-font-weight
bs-nav-link-font-weight
bs-card-box-shadow
bs-card-cap-color
bs-card-height
bs-card-color
bs-breadcrumb-bg
bs-breadcrumb-border-radius
bs-toast-color
bs-modal-color
bs-modal-footer-bg
bs-tooltip-margin
bs-popover-header-color
bs-offcanvas-color

PyCharm shows red squigglies saying "Term expected".

My webpack.config.js:

const Path = require('path');
// const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyPlugin = require("copy-webpack-plugin");
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

var dev_config = {
	cache: false,
	mode: 'development',
	devtool: 'source-map',
	devServer: {
		static: Path.resolve(__dirname, 'dist'),
		port: 8080,
		hot: true
	},
	entry: {
		app: Path.resolve(__dirname, 'src/app.js'),
	},
	output: {
		path: Path.join(__dirname, 'dist'),
		filename: 'js/[name].js',
		clean: true,
	},
	optimization: {
		splitChunks: {
			chunks: 'all',
			name: false,
		},
	},
	plugins: [
		new MiniCssExtractPlugin({filename: 'css/app.css'}),
		new CopyPlugin({
			patterns: [
				{from: "src/index.html", to: "index.html"},
			],
		}),
		// new HtmlWebpackPlugin({
		// 	title: "Generated by Webpack",
		// 	filename: 'index.html',
		// 	inject: 'body',
		// }),
	],
	module: {
		rules: [
			{
				test: /\.js$/,
				include: Path.resolve(__dirname, '../src'),
				loader: 'babel-loader',
			},
			{
				test: /\.(scss)$/,
				use: [{
					// inject CSS to page
					// loader: 'style-loader'
					loader: MiniCssExtractPlugin.loader
				},
				{
					// translates CSS into CommonJS modules
					loader: 'css-loader'
				},
				{
					// Run postcss actions
					loader: 'postcss-loader',
					options: {
						// `postcssOptions` is needed for postcss 8.x;
						// if you use postcss 7.x skip the key
						postcssOptions: {
							// postcss plugins, can be exported to postcss.config.js
							plugins: function () {
								return [
									require('postcss-drop-empty-css-vars'),
									require('autoprefixer'),
								];
							}
						}
					}
				},
				{
					// compiles Sass to CSS
					loader: 'sass-loader'
				}]
			},
			{
				test: /\.(ico|jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2)(\?.*)?$/,
				type: 'asset'
			},
		],
	},
};

module.exports = dev_config;

// console.log(JSON.stringify(dev_config, null, 2));

My package.json

{
  "name": "bootstrap-missing-variables",
  "scripts": {
    "serve": "webpack serve --mode development",
    "build": "webpack --config webpack.config.js",
    "nodemon": "nodemon --watch webpack.config.js --delay 500ms --exec npm run build"
  },
  "devDependencies": {
    "autoprefixer": "^10.4.14",
    "babel-loader": "^9.1.2",
    "copy-webpack-plugin": "^11.0.0",
    "css-loader": "^6.7.3",
    "html-webpack-plugin": "^5.5.1",
    "mini-css-extract-plugin": "^2.7.1",
    "nodemon": "^2.0.22",
    "postcss": "^8.4.23",
    "postcss-drop-empty-css-vars": "^0.0.0",
    "postcss-loader": "^7.3.0",
    "sass": "^1.62.1",
    "sass-loader": "^13.2.2",
    "style-loader": "^3.3.2",
    "webpack": "^5.81.0",
    "webpack-cli": "^5.0.2",
    "webpack-dev-server": "^4.13.3"
  },
  "dependencies": {
    "@popperjs/core": "^2.11.7",
    "bootstrap": "^5.2.3",
    "jquery": "^3.6.4"
  }
}

Wondering if I am doing something wrong. Apologies if this is something "a work in progress" and not yet ready to use. It seems to be exactly what I need.

@julien-deramond
Copy link
Member Author

julien-deramond commented May 3, 2023

@jaradc Indeed it's something WIP, the postcss-drop-empty-css-vars package was released as a 0.0.0 as a test (IDK yet if we're going to use this package in Bootstrap, but if needed I can release a 0.1.0).

However, if you still want to test it out with Webpack and Bootstrap, the following seems to work: https://stackblitz.com/edit/github-t4mv5h.

To build it, I followed this path:

  1. Start from https://github.com/twbs/examples/tree/main/webpack/
  2. Add "postcss-drop-empty-css-vars": "^0.0.0", as a dep dependency in the package.json
  3. In webpack.config.js
  • Comment the const autoprefixer = require('autoprefixer'); import
  • Change the postcss-loader approach to have the following:
{
  // Loader for webpack to process CSS with PostCSS
  loader: 'postcss-loader',
  options: {
    postcssOptions: {
      plugins: [
        ['postcss-drop-empty-css-vars', {}],
        ['autoprefixer', {}],
      ],
    },
  },
},

When you run the project, click on "Toggle offcanvas" and use the dev tools to check the CSS of the offcanvas, there's no empty --bs-offcanvas-color.

@jaradc
Copy link

jaradc commented May 22, 2023

Thank you Julien-Deramond for such a clear response. I did everything you said and did a text compare before/after to confirm that all 16 empty CSS variables were in-fact removed from the Webpack build. Worked for me!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants