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

Non-standardized PostCSS config file doesn't support require statements #10117

Closed
jplhomer opened this issue Jan 15, 2020 · 22 comments
Closed

Non-standardized PostCSS config file doesn't support require statements #10117

jplhomer opened this issue Jan 15, 2020 · 22 comments
Milestone

Comments

@jplhomer
Copy link
Contributor

Bug report

Describe the bug

With the introduction of the marvelous Built-in CSS Support, a new non-standard PostCSS Config plugin syntax was introduced.

This syntax requires that plugins listed in postcss.config.js be strings rather than require statements. This breaks backwards compatibility and differs from the standard set by existing PostCSS documentation.

Additionally, this makes it tough (or impossible) to share a common PostCSS configuration with additional tools like Storybook.js.

To Reproduce

Steps to reproduce the behavior, please provide code snippets or a repository:

  1. yarn add -D tailwindcss autoprefixer
  2. Add the following postcss.config.js:
module.exports = {
  plugins: [
    require("tailwindcss"),
    require("autoprefixer")
  ]
};
  1. yarn next build

Expected behavior

  • The build succeeds, and either plugins imported with require() are supported
  • Or the build fails, and a more descriptive error is shown in the build log.

Screenshots

The following is shown when running next build:

Error: An unknown PostCSS plugin was provided (function creator() {
--
02:32:09 PM | var transformer = initializer.apply(void 0, arguments);
02:32:09 PM | transformer.postcssPlugin = name;
02:32:09 PM | transformer.postcssVersion = new _processor.default().version;
02:32:09 PM | return transformer;
02:32:09 PM | }).
02:32:09 PM | > Build error occurred

System information

  • OS: macOS
  • Version of Next.js: 9.2

Additional context

This work was likely done to be able to identify, dedupe, and acknowledge Next's default PostCSS plugins — and it's likely the solution to this issue is nothing more than better documentation.

Here are a couple proposed solutions:

1. Support require() statements in PostCSS config

I'd rely on @Timer's knowledge here, as there are likely other consequences (notably: not being able to inspect and dedupe plugins).

2. Display a warning/error that indicates deprecated behavior

This would be a simple check in packages/next/build/webpack/config/blocks/css/plugins.ts to see if the plugin is a function:

else if (typeof plugin === 'function') {
  console.error(
    `${chalk.red.bold(
      'Error'
    )}: A PostCSS Plugin must be provided as a ${chalk.bold(
      'string'
    )}. Instead, we got a function imported with require().`
  )
}

I'm happy to submit PRs for either of these solutions! But looking for guidance from the core team.

@shrugs
Copy link

shrugs commented Jan 15, 2020

the workaround, for searchers finding this issue: my postcss.config.js previously looked like

module.exports = {
  plugins: [
    require('postcss-import'),
    require('tailwindcss'),
    require('postcss-preset-env')({ stage: 2 }),
  ],
};

but now looks like

module.exports = {
  plugins: {
    'postcss-import': {},
    tailwindcss: {},
    'postcss-preset-env': { stage: 2 },
  },
};

following the format from https://github.com/postcss/postcss-loader

@Timer
Copy link
Member

Timer commented Jan 15, 2020

The big motivator behind this restriction is because self-requireing code makes it impossible for us to cache CSS transformations.

In other words, we'd have to re-transform the CSS every time the application was edited—this is slow/suboptimal.

We have not yet documented PostCSS customization, but it's coming soon!


re: sharing config

We do support a subset of postcss.config.js, as you posted above:

module.exports = {
  plugins: {
    'postcss-import': {},
    tailwindcss: {},
    'postcss-preset-env': { stage: 2 },
  },
};

@Timer
Copy link
Member

Timer commented Jan 15, 2020

The action items we want to take are:

  1. Fully document how to customize PostCSS, both in an interoperable format and our "proprietary format" (identical to Babel)
  2. Add a special case for typeof ... === 'function' that explains to not require the plugin.

Feel free to send PRs!

@jplhomer
Copy link
Contributor Author

Thanks @Timer — that's really illuminating! And @shrugs's syntax suggestion worked great for me 👍

@crswll
Copy link

crswll commented Jan 16, 2020

I love the update! Running into a snag though. I can't seem to use purgecss in my postcss.config.js file. It was working with next-css. No errors or warning.

const plugins = {
  'postcss-import': {},
  'tailwindcss': {},
  'postcss-preset-env': { stage: 0 },
}

// This branch definitly runs...
if (process.env.NODE_ENV === 'production') {
  // This doesn't seem to work. None of the css is purged...
  plugins['@fullhuman/postcss-purgecss'] = {
    content: [
      'pages/**/*.js',
      'containers/**/*.js',
      'components/**/*.js',
      'views/**/*.js',
    ],
    defaultExtractor: content => content.match(/[A-Za-z0-9-_:/]+/g) || [],
  }

  // Doubt I need this but leaving it here just in case...
  plugins['cssnano'] = {
    preset: ['default', {
      discardComments: {
        removeAll: true,
      },
    }],
  }
}

module.exports = {
  plugins,
}

@timneutkens
Copy link
Member

Here's an example for purgecss: https://github.com/zeit/next.js/blob/canary/examples/with-tailwindcss/postcss.config.js

cssnano is not needed (applied already by next).

@crswll
Copy link

crswll commented Jan 16, 2020

Thank you! That's interesting. Any reason why we need to configure it that way over the above way? Should we always use ['plugin-name', options] over { 'plugin-name': options } or is this something specific to this plugin?

A "wait for the docs" is perfectly fine as well.

@crswll
Copy link

crswll commented Jan 16, 2020

This doesn't appear to work with my project either. The with-tailwindcss example works fine though. I wonder if postcss-import is messing with something.

@timneutkens
Copy link
Member

You can drop postcss-import afaik. cc @Timer

@Timer
Copy link
Member

Timer commented Jan 16, 2020

postcss-import has different behavior characteristics, but I'd advise dropping it. It should be compatible to keep, what do you see it messing with?

@crswll
Copy link

crswll commented Jan 16, 2020

I tracked it down. Totally nothing to do with postcss-import. I'm sorry to have wasted your time. A copy and paste left me with a /* purgecss start ignore */ and no /* purgecss end ignore */.

I need to make my comments a lot brighter in my IDE.

@shrugs
Copy link

shrugs commented Jan 16, 2020

it seems like you can use either format—adding purgecss to my config works just fine like so, following the config options from https://github.com/zeit/next.js/blob/canary/examples/with-tailwindcss/postcss.config.js

module.exports = {
  plugins: {
    'postcss-import': {},
    tailwindcss: {},
    ...(process.env.NODE_ENV === 'production'
      ? {
          '@fullhuman/postcss-purgecss': {
            content: ['./pages/**/*.{js,jsx,ts,tsx}', './components/**/*.{js,jsx,ts,tsx}'],
            defaultExtractor: content => content.match(/[A-Za-z0-9-_:/]+/g) || [],
          },
        }
      : {}),
    'postcss-preset-env': { stage: 2 },
  },
};

noting, in the case of tailwind, to ignore the base import

/* purgecss start ignore */
@import 'tailwindcss/base';
/* purgecss end ignore */

@import 'tailwindcss/components';

@import './my_styles.css';

@import 'tailwindcss/utilities';

@crswll
Copy link

crswll commented Jan 16, 2020

Yeah. I very obliviously had the purgecss start ignore comment towards the end of my_styles.css without an end comment so all of utilities were left unpurged. It's all good now. Only reason I moved that was due to the pure css errors I started getting.

@HosseinAgha
Copy link

@Timer Could you throw a more meaningful error? I think "An unknown PostCSS plugin was provided" is not enough. For example, you can check if the provided plugin is a function and ask the user to only use plugin name or the object form configuration instead (or even link to this issue).

@timneutkens
Copy link
Member

Try next@canary, the message was updated there

@Timer
Copy link
Member

Timer commented Jan 23, 2020

Now explained in Next.js canaries with read more links.

@Timer Timer closed this as completed Jan 23, 2020
tumidi added a commit to innodoc/innodoc-webapp that referenced this issue Jan 28, 2020
New Next.js built-in CSS support doesn't work with PostCSS plugins as Array of
required modules. Instead it needs it as an Object
(vercel/next.js#10117).
@simonsmith
Copy link

I have a local postcss plugin that I've written for my own needs. How does one use that in this scenario without using require?

@Timer
Copy link
Member

Timer commented Jan 30, 2020

@simonsmith you should be able to use the resolved file path as the plugin name:

// postcss.config.js or .postcssrc.js
module.exports = {
  plugins: [
    require.resolve('../my-plugin.js')
  ]
};

// or

module.exports = {
  plugins: [
    [require.resolve('../my-plugin.js'), { ... }]
  ]
};

@zephraph
Copy link
Contributor

zephraph commented Feb 1, 2020

@Timer I just ran across this too. There's an error message that's searchable which will lead here, but is it possible to add a more descriptive error message or something that leads the user to documentation?

I'm sure there will be a migration guide when 9.2.* comes out, but having an error message that links off to documentation (or tells you how to fix it directly) would be lovely.

@timneutkens
Copy link
Member

That’s already added, try upgrading to next@canary to see it.

@aganglada
Copy link
Contributor

Here's an example for purgecss: https://github.com/zeit/next.js/blob/canary/examples/with-tailwindcss/postcss.config.js

cssnano is not needed (applied already by next).

Hey @timneutkens what if I wan't to configure the options to say { normalizeUrl: { removeTrailingSlash: false } }, how can I do that?

depsimon added a commit to depsimon/tailwindcss.com that referenced this issue Jun 16, 2021
Add `-D` flag for dev dependencies.
Prevent error with `require()` in `postcss.config.js` cfr [this issue](vercel/next.js#10117)
@balazsorban44
Copy link
Member

This issue has been automatically locked due to no recent activity. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.

@vercel vercel locked as resolved and limited conversation to collaborators Jan 28, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants