What causes the absence of CSS classes in production while utilizing Tailwind and next.js?

Tailwind version: v9.3.5

PostCSS Configuration:

// postcss.config.js

module.exports = {
   plugins: {
      tailwindcss: {},
      autoprefixer: {},
      ...(process.env.NODE_ENV === 'production'
         ? {
              '@fullhuman/postcss-purgecss': {
                 content: ['./components/**/*.js', './pages/**/*.js'],
                 defaultExtractor: content =>
                    content.match(/[\w-/:]+(?<!:)/g) || [],
              },
           }
         : {}),
   },
}

Tailwind Style Configuration:

// tailwind.config.js

module.exports = {
   theme: {
      extend: {
         colors: {
            tint: 'rgba(0,0,0,0.3)',
         },
      },
   },
   variants: {},
   plugins: [],
}

The styles are functioning correctly during development, however, in production only some styles are being applied. After examining the CSS file in the build folder, it appears that certain CSS classes are not being extracted or possibly purged, resulting in incomplete styling of the application.

Answer №1

UPDATE: The latest PurgeCSS version 3.0 introduces a safelist option, replacing the previously used whitelist.

I encountered a similar issue when dynamically injecting class names into my HTML template.
As I am using nuxt.js/tailwindcss, it is important to refer to the documentation for solutions.

Issue

The following code generates missing classes in production:

 computed: {
    axeY() {
      return this.y < 0 ? `-translate-y${this.y}` + ' ' : `translate-y-1` + ' '
    },
    axeX() {
      return this.x < 0 ? `-translate-x${this.x}` : `translate-x-${this.x}`
    },

PostCSS analyzes all files within the content table (defined in the configuration file), however, my files do not contain classes with the translate prefix.
It is evident that the missing classes are: [translate-x-1,-translate-x-1, translate-y-1, -translate-y-1] ... where the number 1 represents a variable.

Resolution

  • To prevent deletion of these classes, add them to the whitelist in PurgeCSS configuration
  • Alternatively, include them in your files, such as by creating an unless file analyzed by PostCSS

Specify content to be analyzed by PurgeCSS with an array of filenames

  • Update your TailWindCSS config file by specifying all core plugins used
  • In complex scenarios, utilize regular expressions in the config file.
    In my case, I directly configure purge in the TailWindCSS config file, passing the whitelist in the options variable. Here is a snippet of my config file when implementing the first solution:
/*
 ** TailwindCSS Configuration File
 **
 ** Docs: https://tailwindcss.com/docs/configuration
 ** Default: https://github.com/tailwindcss/tailwindcss/blob/master/stubs/defaultConfig.stub.js
 */
const num = [1, 2, 3, 4, 5, 6, 8, 10, 12]
const whitelist = []
num.map((x) => {
  whitelist.push('translate-x-' + x)
  whitelist.push('-translate-x-' + x)
  whitelist.push('translate-y-' + x)
  whitelist.push('-translate-y-' + x)
})
module.exports = {
  future: {
    removeDeprecatedGapUtilities: true,
  },
  theme: {},
  variants: {
    backgroundColor: ['hover', 'focus', 'active'],
  },
  plugins: [],
  purge: {
    // Learn more on https://tailwindcss.com/docs/controlling-file-size/#removing-unused-css
    enabled: process.env.NODE_ENV === 'production',
    content: [
      'components/**/*.vue',
      'layouts/**/*.vue',
      'pages/**/*.vue',
      'plugins/**/*.js',
      'nuxt.config.js',
    ],
    options: {
      whitelist,
    },
  },
}

Answer №2

After some investigation, I discovered the root cause of the issue. The postcss config was missing the sections folder in the content array. Additionally, since my JavaScript files contained jsx, it was necessary to include that as well.

// postcss.config.js

module.exports = {
   plugins: {
      tailwindcss: {},
      autoprefixer: {},
      ...(process.env.NODE_ENV === 'production'
         ? {
              '@fullhuman/postcss-purgecss': {
                 // added sections folder and changed extension to jsx
                 content: ['./components/**/*.jsx', './pages/**/*.js', './sections/**/**/*.jsx'],
                 defaultExtractor: content =>
                    content.match(/[\w-/:]+(?<!:)/g) || [],
              },
           }
         : {}),
   },
}

Answer №3

This particular issue gave me quite a challenge. Tailwind has the ability to remove classes that are generated through string concatenation.

One workaround is to store class names as variables.

const className = 'row-start-2';

className={className}

In my situation, using variables was not an option. Therefore, I opted for the safelist greedy approach.

In the Tailwind config file:


module.exports = {
  purge: {
    content: ["./src/**/*.{js,jsx}", "./public/index.html"],
    options: {
      safelist: {
        greedy: ["/safe$/"],
      },
    },
  },

Afterwards, I included the "safe" class in all elements where I needed to generate classes through string concatenation.

className={`safe sm:grid-cols-${smCols} sm:grid-rows-${smRows} md:grid-cols-${mdCols} md:grid-rows-${mdRows}`}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Lost in a sea of confusion with ember-cli-postcss and autoprefixer

I'm currently working on an ember build that incorporates autoprefixer. My issue arises from the fact that the output location for 'assets/application-name.css' has shifted from its normal path to 'app/styles/app.css', and I would ...

In the realm of HTML Canvas, polygons intricately intertwine with one another

Currently, I am attempting to create multiple polygons from a large JSON file. Instead of being separate, the polygons seem to be connected in some way. The project is being developed in next.js. Below are the relevant code snippets: Canvas.tsx // ../co ...

The Swiper JS component is experiencing flickering and is not functioning properly within the Next JS 13 app router

I'm currently facing some challenges with integrating a simple swiper into my Next.js website (v13 with app router). Initially, I attempted to import the swiper as usual by copying the code from a demo on their official website. While the swiper show ...

The sub menu in IE 8 does not stay open while hovering over it

My website has a navigation menu with a sub-menu that appears when hovering over the parent element. While this works smoothly on modern browsers, Internet Explorer 8 presents an issue. When hovering over the parent li element in IE 8, the sub-menu is disp ...

The React developer tools display a blank state, meanwhile the console reveals the data

Encountering a peculiar state issue in my React app. Initialized state as an empty array, retrieved data from Firebase in the componentDidMount() method, formatted JSON objects into a new array, and called setState() with the new array. However, the state ...

Guide on changing the content type of a Response header in a Next.js API route

I am currently working on a Next.js 14 app router and have a requirement to dynamically create an XML file when the API route is called and send it in response. Below is my code snippet: export async function GET(req: NextApiRequest, res: NextApiResponse) ...

issues stemming from the css of leaflets

This is my first time using leaflet and I am encountering a CSS issue. I'm not sure if there is another CSS file for leaflet, but whenever I try to adjust its position, it changes unexpectedly. I have a floating nav bar that should appear when scroll ...

How can I assign a unique identifier to an object in Next JS?

I'm having trouble assigning a unique id to my object using Math.random. Whenever I try, I encounter the error shown below. Changing Math.random to an integer like 4 resolves the error, but I really need each id to be unique. Unhandled Runtime Error ...

Struggling to successfully upload a file using express and fileupload, but I am having trouble getting it to function properly

This is my first attempt at uploading files to the server, following a tutorial to build both frontend and backend in React. Unfortunately, I'm facing some difficulties getting it to work properly. I've made adjustments to my backend and tested ...

Unable to adjust metadata titles while utilizing the 'use client' function in Next.js

I have a /demo route in my Next.js 13 application, and it is using the App Router. However, I am facing an issue with changing the title of the page (currently displaying as localhost:3000/demo). The code snippet for this issue is shown below: /demo/page ...

Clicking on an element in React Material UI Autocomplete will bring it

I'm currently working with a material-ui autocomplete element <Autocomplete id="combo-box-demo" autoHighlight openOnFocus autoComplete options={this.state.products} getOptionLabel={option => option.productName} style={{ width: 300 ...

Tips for maintaining sequential numbering in Mediawiki sections

Looking to enhance the formatting of numbered lists by adding section headers and restarting numbering? The old Mediawiki format supported this, but it no longer works in version 1.24. For example: ==First Header2== # # ==Second Header2== # Desired output ...

Developing an interactive web interface with HTML

I've been attempting to design a flexible HTML page that replicates the layout of a Java applet clock, but I'm unsure if my current approach is correct. Below is an example of the three-clock image set that I am currently working on. My method i ...

The Proper Way to Position _app.tsx in a Next.js Setup for Personalized App Configuration

I've been working on a Next.js project and I'm currently trying to implement custom app configuration following the guidelines in the Next.js documentation regarding _app.tsx. However, I'm encountering some confusion and issues regarding the ...

JavaScript accordions failing to open

I've encountered an issue with my website that includes JS accordions. Strangely, they are not opening on the live site, but they function properly on Codepen. I checked the console in Chrome and found no error messages, however, when I looked at the ...

Can you identify the specific name of the IE CSS bug affecting double vertical padding?

(Just when I thought I've encountered all the strange IE CSS bugs, here comes another one. Is there a name for this double-vertical-padding bug?) After creating a simple test case that worked perfectly in browsers like FF and Opera, I was surprised t ...

What measures can I take to protect the use of React components that may not be present?

For my project, I am planning to receive icons/svgs as react components from a folder created by the backend. Additionally, there will be a WAMP (bonefish/autobahn) solution where I will be provided with the name of an icon to use (even though this may see ...

Despite having the Express CORS package, I am still encountering the "cross-origin request blocked" error

Here is the code for my App: import express, {Express, Request, Response, Router} from 'express'; import dotenv from 'dotenv'; import ArtistRouter from './routes/artist_routes'; import infoRouter from './routes/info_route ...

What is the reason for using a callback as a condition in the ternary operator for the Material UI Dialog component?

I am in the process of reconstructing the Material UI Customized Dialog component based on the instructions provided in this particular section of the documentation. However, I am unable to grasp the purpose behind using a callback function onClose conditi ...

The concept of `object()` does not function properly in the context of utilizing redux

Reactjs error: TypeError - Object(...) is not a function when integrating Firebase Here is the tutorial video I followed but encountered an error. Screenshot of browser showing the error Code snippet: import React from 'react'; import Rea ...