Why do I have to restart server on every style change?

180 Views Asked by At

I'm working on a NextJS application with PurgeCSS. I have to restart the server every single time I change the classname of a component.

Here are my postcss.config.js:

  plugins: [
    [
      '@fullhuman/postcss-purgecss',
      {
        content: [
          './src/pages/**/*.{js,jsx,ts,tsx}',
          './src/pages/*.{js,jsx,ts,tsx}',
          './src/components/**/*.{js,jsx,ts,tsx}',
          './src/containers/**/*.{js,jsx,ts,tsx}',
        ],
        defaultExtractor: (content) => content.match(/[\w-/:]+(?<!:)/g) || [],
        safelist: ['html', 'body'],
        enableDevPurge: false,
      },
    ],
    'postcss-preset-env',
  ],
};

My package.json dependencies:

"dependencies": {
    "date-fns": "^2.29.3",
    "next": "13.1.1",
    "react": "18.2.0",
    "react-dom": "18.2.0",
    "react-icons": "^4.7.1",
    "sass": "^1.57.1"
  },
  "devDependencies": {
    "@fullhuman/postcss-purgecss": "^5.0.0",
    "@types/node": "18.11.18",
    "@types/react": "18.0.26",
    "@types/react-dom": "18.0.10",
    "@typescript-eslint/eslint-plugin": "5.48.0",
    "@typescript-eslint/parser": "5.48.0",
    "autoprefixer": "^10.4.13",
    "eslint": "8.31.0",
    "eslint-config-next": "13.1.1",
    "eslint-config-prettier": "^8.6.0",
    "eslint-plugin-import": "^2.26.0",
    "eslint-plugin-next": "^0.0.0",
    "eslint-plugin-react": "^7.31.11",
    "eslint-plugin-react-hooks": "^4.6.0",
    "husky": "^8.0.3",
    "lint-staged": "13.1.0",
    "next-purge-css-modules": "1.1.0",
    "postcss": "^8.4.20",
    "postcss-flexbugs-fixes": "^5.0.2",
    "postcss-preset-env": "^7.8.3",
    "prettier": "^2.8.1",
    "typescript": "4.9.4"
  }

I'm using global styles, not module styles, and scss instead of css.

This is my _app.tsx:

import '../styles/Global.scss';
import type { AppProps } from 'next/app';

function MyApp({ Component, pageProps }: AppProps) {
  return <Component {...pageProps} />;
}

export default MyApp;

Say I have these two styles:

.bg-blue { background-color: blue; }
.bg-red { background-color: red; }

If I had bg-blue used on a div's className, and I change it to bg-red, its ruleset is missing from the stylesheet.

I'm assuming purgecss doesn't update the stylesheet and does only one purge on server start.

It's definitely not ideal, but I don't care if I can just disable the whole purge functionality. However, can't find a way for that either.

Any tips?

1

There are 1 best solutions below

0
Bekzhan Satarov On

I hope this helps anyone who is here looking for a solution to Next.js and PostCSS related issues.

I had a similar problem using Next.js 14, Panda-CSS, and PostCSS. I fixed it by writing a special script for development. This script checks for any changes in my .ts and .tsx files. When it finds a change, it makes a small update to my globals.css file (in your case, it will be styles/Global.scss).

This small change tells Next.js that the styles have changed. Next.js then creates new CSS based on these changes. This solution worked well for me and kept my styles updated.

const chokidar = require("chokidar");
const fs = require("fs");
const path = require("path");

const cssFilePath = path.join(
  __dirname,
  "../../packages/app/src/app/globals.css"
);

function updateCssCounter() {
  let content = fs.readFileSync(cssFilePath, "utf8");
  let match = content.match(/\/\*\s*(\d+)\s*\*\//);
  let counter = match ? parseInt(match[1]) + 1 : 1;

  if (match) {
    content = content.replace(/\/\*\s*\d+\s*\*\//, `/* ${counter} */`);
  } else {
    content += `\n/* ${counter} */`;
  }

  fs.writeFileSync(cssFilePath, content, "utf8");
}

const watcher = chokidar.watch(
  [
    "../../packages/app/src/**/*.ts",
    "../../packages/app/src/**/*.tsx",
    "../../packages/design-system/src/**/*.ts",
    "../../packages/design-system/src/**/*.tsx",
  ],
  {
    ignored: /node_modules/,
    persistent: true,
  }
);

watcher.on("change", (path) => {
  console.log(`CHANGED: ${path}`);
  updateCssCounter();
});

console.log("Watching for file changes...");