patternfly / patternfly

This repo contains core (HTML/CSS) implementation for PatternFly. Issues related to CSS/HTML and layout should be filed here.
https://patternfly.org
MIT License
697 stars 95 forks source link

"Global CSS cannot be imported from within node_modules." error in Next.js #4035

Closed vishnupriyavr closed 3 years ago

vishnupriyavr commented 3 years ago

While using NextJS with Patternfly, this error crops up : "Global CSS cannot be imported from within node_modules." for About-Modal CSS file import

NextJS suggests to work with the library community (patternfly in this case) to work around this.

More info here : https://github.com/vercel/next.js/issues/19936

Is there some woraround to make patternfly to work with NextJS (Note : I already tried out https://github.com/vercel/next.js/tree/canary/examples/with-patternfly without much success)

mcoker commented 3 years ago

cc @redallen

redallen commented 3 years ago

There is currently no solution since Next.js dropped support for importing CSS in JS (virtually every other bundler does). Sorry!

dgutride commented 3 years ago

Can we take another look at this @redallen?

redallen commented 3 years ago

I've tried the following next.config.js file to no avail:

module.exports = {
  future: {
    webpack5: true
  },
  webpack(config, { isServer }) {
    // Remove existing css rule
    config.module.rules.pop();

    // SSR doesn't care about CSS
    const cssRule = {
      test: /\.css$/,
      //include: __dirname
    };
    if (isServer) {
      cssRule.use = require.resolve('null-loader')
    }
    else {
      cssRule.use = [
        MiniCssExtractPlugin.loader,
        require.resolve('css-loader')
      ];
      config.plugins.push(
        new MiniCssExtractPlugin()
      );
    }
    // Add our cssRule
    config.module.rules.push(cssRule);

    return config;
  }
}

It gives the following error:

./node_modules/@patternfly/react-styles/css/components/AboutModalBox/about-modal-box.css
ModuleParseError: Module parse failed: Unexpected character '�' (1:0)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
(Source code omitted for this binary file)

> Build error occurred
Error: > Build failed because of webpack errors
    at /home/thesm/src/next-app/node_modules/next/dist/build/index.js:17:924
    at async Span.traceAsyncFn (/home/thesm/src/next-app/node_modules/next/dist/telemetry/trace/trace.js:6:584)

I believe Next.js is further modifying my config despite saying "Warning: Built-in CSS support is being disabled due to custom CSS configuration being detected."

I'll pursue this issue upstream.

redallen commented 3 years ago

Oops, didn't mean to close. Sorry.

fabianishere commented 3 years ago

I managed to get it to work using a patched version of next-transpile-modules in order to enable support for global CSS imports. See the following changes https://github.com/fabianishere/next-transpile-modules/commit/5f61c10fb6cc043f63459c7c69fd79c9f38579ad.

However, at this point, you are deep inside Next.js internals, so I wouldn't consider this an ideal solution. Let's hope this functionality can be integrated into Next.js.

fabianishere commented 3 years ago

@redallen Sorry if this is the incorrect place to ask, but is there a reason as to why patternfly-react uses Global CSS as opposed to CSS modules?

Although we might get Global CSS imports to work natively in Next.js at some point, it cannot benefit from treeshaking: https://github.com/vercel/next.js/blob/96f9945ecb24b3cdcce58e8fb6e4311e93b7a1d2/packages/next/build/webpack/config/blocks/css/index.ts#L190

redallen commented 3 years ago

CSS modules are preferable but:

  1. Didn't have good support when this library started
  2. Aren't supported by every bundler

The initial authors of this library quite liked the idea of import styles from './button.css'; <div className={styles.someClass} /> so we wrote @patternfly/react-styles to generate classNames from CSS files for better interoperability with our CSS authors working in @patternfly/patternfly.

As for tree shaking most components use all of their* provided classes so there isn't much to gain tree-shaking individual CSS files.

wojta commented 3 years ago

I managed to get it to work using a patched version of next-transpile-modules in order to enable support for global CSS imports. See the following changes fabianishere/next-transpile-modules@5f61c10.

@fabianishere Do you have a sample code of using it somewhere?

fabianishere commented 3 years ago

@wojta With the patched version of next-transpile-modules, you should only need the following configuration in next.config.js:

const withTM = require('next-transpile-modules')(['@patternfly/react-core', '@patternfly/react-styles'])

module.exports = withTM({
  future: {
    webpack5: true,
  },
});

I am working now with the author of that package to upstream these changes.

wojta commented 3 years ago

@fabianishere solution seems to be working. Thanks! It's necessary to add all modules that are used with PatternFly otherwise you'll get an error.

fabianishere commented 3 years ago

@wojta For if you haven't seen it yet, the changes have now been integrated into next-transpile-modules: https://github.com/martpie/next-transpile-modules/releases/tag/7.2.0

ghost commented 3 years ago

@fabianishere, in my case the solution you provided does not work. As a result, I had no styles at all: my own and patternfly's. There're no other errors. Using webpack 4 / webpack 5 option in next.config.js changes nothing.

The issue appears on latest nextjs (10.2.2).

fabianishere commented 3 years ago

@altwarg By no styles at all, do you mean the stylesheets are not loaded for the Patternfly component you are importing?

Does this happen in development or production mode?

ghost commented 3 years ago

@fabianishere

By no styles at all, do you mean the stylesheets are not loaded for the Patternfly component you are importing?

After paying some attention I realized that all my styles are not being imported.

I have these styles according to NextJS css modules system: image

But I had something like this: image

Here is my package.json:

{
  "name": "hotel",
  "version": "0.5.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start"
  },
  "dependencies": {
    "@patternfly/react-core": "^4.121.3",
    "@patternfly/react-icons": "^4.10.8",
    "@patternfly/react-styles": "^4.10.8",
    "@patternfly/react-table": "^4.27.9",
    "axios": "^0.21.1",
    "effector": "^21.8.11",
    "effector-react": "^21.3.2",
    "js-cookie": "^2.2.1",
    "moment": "^2.29.1",
    "next": "10.2.2",
    "nprogress": "^0.2.0",
    "react": "17.0.2",
    "react-datasheet": "^1.4.9",
    "react-dom": "17.0.2",
    "react-multi-carousel": "^2.6.3",
    "react-pdf": "^5.3.0",
    "react-quill": "^1.3.5",
    "react-sortablejs": "^6.0.0",
    "sortablejs": "^1.13.0"
  },
  "devDependencies": {
    "@types/js-cookie": "^2.2.6",
    "@types/node": "15.6.0",
    "@types/nprogress": "^0.2.0",
    "@types/react": "17.0.6",
    "@types/react-dom": "^17.0.5",
    "@types/react-pdf": "^5.0.2",
    "@types/sortablejs": "^1.10.6",
    "next-transpile-modules": "7.2.0",
    "typescript": "^4.2.4"
  }
}

And my next.config.js:

const withTM = require('next-transpile-modules')([
  '@patternfly/react-core',
  '@patternfly/react-table',
  '@patternfly/react-icons',
  '@patternfly/react-styles',
]);

module.exports = withTM({
  future: {
    webpack5: true,
  },
});

Does this happen in development or production mode?

This happen in development (next dev) and production mode (next start after next build).

fabianishere commented 3 years ago

I cannot reproduce the issue. Could you check whether the following example works: https://github.com/fabianishere/next.js/tree/examples/patternfly-4/examples/with-patternfly

ghost commented 3 years ago

@fabianishere, I checked this example from the examples/patternfly-4 branch and noticed the same thing. Custom styles don't work.

What I've done:

  1. I've added the property canJumpTo: false to every Wizard step:

image

This option sets that we can change the steps in the Wizard only when we click the Next or Back buttons. Otherwise we could click on the step itself to move to it.

  1. canJumpTo: false option causes to disable every step button (and they are looks gray). I want to set the same styles as for canJumpTo: true. In this case I created styles directory and index.module.css file with these styles:

image

  1. After importing the styles directly in index component I expect them to be applied but they are not:

image

No idea how to fix this.

fabianishere commented 3 years ago

This is because you are using CSS modules, which will transform the selectors to something different to prevent name clashes with global CSS.

To get this to work, you can do the following:

.customWizard :global(.pf-c-wizard__nav-link.pf-m-current:disabled)::before {
    background-color: rgb(0, 102, 204) !important;;
    color: rgb(255, 255, 255) !important;;
}

.customWizard :global(.pf-c-wizard__nav-link:disabled)::before {
    background-color: rgb(240, 240, 240) !important;
}

.customWizard :global(button.pf-c-wizard__nav-link.pf-m-current.pf-m-disabled) {
    color: rgb(0, 102, 204) !important;
}
import { customWizard } from './index.module.css'
import { useState } from 'react'
import { Button, Wizard } from '@patternfly/react-core'
import { CogIcon } from '@patternfly/react-icons'

const steps = [
  { name: 'Step 1', component: <p>Step 1</p>, canJumpTo: false },
  { name: 'Step 2', component: <p>Step 2</p>, canJumpTo: false },
  { name: 'Step 3', component: <p>Step 3</p>, canJumpTo: false },
  { name: 'Step 4', component: <p>Step 4</p>, canJumpTo: false },
  { name: 'Review', component: <p>Review Step</p>, nextButtonText: 'Finish', canJumpTo: false },
]

export default function Home() {
  const [isOpen, setIsOpen] = useState(false)
  return (
    <>
      <Button
        variant="primary"
        onClick={() => setIsOpen(true)}
        style={{ margin: 20 }}
        icon={<CogIcon />}
      >
        Show Wizard
      </Button>
      {isOpen && (
        <Wizard
          className={customWizard}
          isOpen={isOpen}
          onClose={() => setIsOpen(false)}
          title="Simple Wizard"
          description="Simple Wizard Description"
          steps={steps}
        />
      )}
    </>
  )
}
ghost commented 3 years ago

@fabianishere, your approach can be applied to customize standard patternfly styles. But my own for my own components don't work as well.

fabianishere commented 3 years ago

There is another way to do it in Next.js at the moment: https://nextjs.org/docs/messages/css-global I don't think it is an issue with the example or next-transpile-modules itself.

ghost commented 3 years ago

@fabianishere, well, global css can be applied, but to be honest: I found no performance improvements or behavior differences using approach you mentioned vs the approach I mentioned in https://github.com/patternfly/patternfly-react/issues/5756.

Node process still requires ~1-1.2 GB of RAM and from 30-40% of CPU usage to work in development (in production mode everything is fine). No idea how to deal with it but it is really annoying.

fabianishere commented 3 years ago

@altwarg Does this only happen once you start using next-transpile-modules? I haven't noticed a large difference in behavior between a stock Next.js application and one that uses next-transpile-modules myself.

Of course, some additional CPU/RAM usage is expected as it needs to transpile additional source files, but those results should be cached, so it should not happen on every re-render.

ghost commented 3 years ago

@fabianishere, I've used next-transpile-modules (but older version) before so I believe that my comments are not so relevant.

Now I understand why does additional CPU/RAM usage is expected. Your approach is better and requires fewer packages to be installed. Thank you!

jaywcjlove commented 3 years ago

I created a nextjs package next-remove-imports to solve the problem. Best solution :) @fabianishere @altwarg

Example: https://codesandbox.io/s/nextjs-example-react-md-editor-qjhn7?file=/pages/index.js

stale[bot] commented 3 years ago

This issue has been automatically marked as stale because it has not had activity in the last 60 days. It will be closed in 30 days if no further activity occurs.

snigdha920 commented 1 year ago

I'm also facing the "Global CSS cannot be imported from within node_modules." error in Next.js.

When I do,

const withTM = require('next-transpile-modules')([
  '@patternfly/react-core',
  '@patternfly/react-styles',
  '@patternfly/react-log-viewer',
]);

module.exports = withTM({});

I can render the component successfully, however no CSS styles are applied.

Any idea on how to fix this? I'm aware I can import global CSS from a package in the experimental app directory in Next JS (ref: https://github.com/vercel/next.js/discussions/27953#discussioncomment-3978605) but my team hasn't taken the decision to migrate to the experimental feature.

Happy to provide more details if needed, please let me know!

snigdha920 commented 1 year ago

I'm also facing the "Global CSS cannot be imported from within node_modules." error in Next.js.

When I do,

const withTM = require('next-transpile-modules')([
  '@patternfly/react-core',
  '@patternfly/react-styles',
  '@patternfly/react-log-viewer',
]);

module.exports = withTM({});

I can render the component successfully, however no CSS styles are applied.

Any idea on how to fix this? I'm aware I can import global CSS from a package in the experimental app directory in Next JS (ref: vercel/next.js#27953 (comment)) but my team hasn't taken the decision to migrate to the experimental feature.

Happy to provide more details if needed, please let me know!

I was able to solve the issue by adding the following imports to my _app.tsx file. I'm using the LogViewer component hence I've imported the log viewer css along with the base css.

import '@patternfly/react-core/dist/styles/base.css';
import '@patternfly/react-styles/css/components/LogViewer/log-viewer.css';