next.jspurgecss-purge

NextJS with global CSS import fail in production mode


I'm using Next.JS with a few other modules. One of them, Megadraft, comes with its own CSS. I don't know if this is relevant, but I also use PurgeCSS.

Everything works fine on development mode, but the CSS seems to break in production mode. To be a little more explicit, all of the classes of Megadraft, seem to have no definition in production mode. The HTML nodes in the inspector still show that the classes are here, but they have just no definition.

Here's how I import the said CSS files in my pages/_app.js file:

// pages/_app.js
import "css/tailwind.css";
import "megadraft/dist/css/megadraft.css";

And this is my postcss.config.js:

// postcss.config.js
const purgecss = [
    "@fullhuman/postcss-purgecss",
    {
        content: [
            "./components/**/*.js",
            "./Layout/**/*.js",
            "./pages/**/*.js",
            "./node_modules/next/dist/pages/**/*.js",
            "./node_modules/next/dist/Layout/**/*.js",
            "./node_modules/next/dist/components/**/*.js"
        ],
        defaultExtractor: (content) => content.match(/[A-Za-z0-9-_:/]+/g) || [],
    },
];
module.exports = {
    plugins: [
        "postcss-import",
        "tailwindcss",
        "autoprefixer",
        ...(process.env.NODE_ENV === "production" ? [purgecss] : []),
    ],
};

I'm using next ^9.4.4. It may be worth noticing that TailwindCSS seems to work just fine (both in dev and prod), but I think it may be because it is used as a plugin in postcss...

Just in case also, I integrated webpack to my project to solve an error I had where the code was telling that I needed a loader:

// next.config.js
module.exports = {
    cssModules: true,
    webpack: (config, options) => {
        config.node = {
            fs: "empty",
        };
        config.module.rules.push({
            test: /\.(png|woff|woff2|eot|ttf|svg)$/,
            use: [
                options.defaultLoaders.babel,
                {
                    loader: "url-loader?limit=100000",
                },
                {
                    loader: "file-loader",
                },
            ],
        });
        return config;
    },
};

Anyway, if someone has an idea of why this works in development mode and not in production, it could be of great help.


Solution

  • Option 1: use Tailwind CSS built-in PurgeCSS

    // tailwind.config.css
    module.exports = {
      purge: ["./components/**/*.js", "./pages/**/*.js"],
      theme: {
        extend: {}
      },
      variants: {},
      plugins: []
    };
    
    // postcss.config.js
    module.exports = {
      plugins: ["tailwindcss", "postcss-preset-env"]
    };
    

    Be sure to add postcss-preset-env to the package's dev dependencies with npm i --save-dev postcss-preset-env or yarn add -D postcss-preset-env.

    Option 2: Manually setup purge and add "./node_modules/megadraft/dist/**/*.css" to purgecss whitelisting content array:

    // tailwind.config.css
    module.exports = {
      theme: {
        extend: {}
      },
      variants: {},
      plugins: []
    };
    
    // postcss.config.js
    const purgecss = ['@fullhuman/postcss-purgecss',{
      content: ["./node_modules/megadraft/dist/**/*.css", "./components/**/*.js", "./pages/**/*.js"],
    
      defaultExtractor: content => {
        const broadMatches = content.match(/[^<>"'`\s]*[^<>"'`\s:]/g) || []
        const innerMatches = content.match(/[^<>"'`\s.()]*[^<>"'`\s.():]/g) || []
        return broadMatches.concat(innerMatches)
      }
    }]
    
    module.exports = {
      plugins: [
        'tailwindcss',
        'autoprefixer',
        ...process.env.NODE_ENV === 'production'
          ? [purgecss]
          : []
      ]
    }
    

    There may be better solutions but these two are what I can think of.