postcss / autoprefixer

Parse CSS and add vendor prefixes to rules by Can I Use
https://twitter.com/autoprefixer
MIT License
21.66k stars 1.26k forks source link

browserslist loaded from wrong package.json in monorepo #1367

Closed WillsonHaw closed 3 years ago

WillsonHaw commented 3 years ago

Hello!

Our application currently is set up as a monorepo in this way:

- packages/
  - app/
  - etc...
- platforms/
  - platformA
  - platformB
  - etc...

Here, packages/app contains all the code for the application. The platforms/platformX folders each have its own set of webpack configurations, package.json files, etc. This is necessary because our platforms are widely different, and have very different browser support and deployments.

Each package.json in the platforms folder has their own browserslist. This works fine with babel, but for autoprefixer (via webpack + postcss-loader), none of the css is prefixed properly.

I've narrowed this down to the fact that the browserslist configuration is being loaded from the package.json that's found relative to the file being processed, rather than from process.cwd(). That means it's trying to find packages/app/package.json which doesn't have a browserslist configuration, and then to the monorepo's root folder which also doesn't have a browserslist confuration. This causes the default set of browsers to be used (which doesn't work for some of our platforms that are super old browsers).

As a workaround, I've had to manually grab the browserslist configuration from the platform's package.json and then pass it into autoprefixer via the overrideBrowserslist option, but this feels kind of hacky.

Am I missing something that can be configured to make this work with our project structure, or is the overrideBrowserslist option my only choice?

ai commented 3 years ago

Yeap, this is our normal behavior. Browserslist is looking for the closest config to the source. process.cwd() is thing that can’t be trusted, deveoper could forget that they moved to another folder.

You can use BROWSERSLIST_CONFIG (but maybe it will need some fixed in Browserslist).

WillsonHaw commented 3 years ago

BROWSERSLIST_CONFIG seems to work for my case. Thanks!

artola commented 3 years ago

@WillsonHaw I had same issue that you reported, as I am using webpack and postcss-loader, I am thinking to use the following:

{
    loader: 'postcss-loader',
    options: {
        sourceMap: true,
        postcssOptions: {
        plugins: [
            [
            'postcss-preset-env',
            {
                browsers: require('browserslist')(),
            },
            ],
        ],
        },
    },
}
artola commented 3 years ago

@ai Could you please reopen this issue and/or see if possible to enhance this plugin adding the possibility to pass options.from (similar as done for options.env)?

https://github.com/postcss/autoprefixer/blob/d46eb26a39fdafa6639caab9b2e9fb74b2410d2d/lib/autoprefixer.js#L118

Something like this will allow us to pass {from: process.cwd()} and not use the file path as search starting point:

    prepare (result) {
      let prefixes = loadPrefixes({
        from: options.from || result.opts.from,
        env: options.env
      })
ai commented 3 years ago

@artola you should use BROWSERSLIST environment variable in this case.

Changing path in one tool will not change browsers in other tools, which could lead to painful bugs.

artola commented 3 years ago

@ai I understand, but looking at postcss-preset-env (3 millon downloads, see) and mentioned from postcss-loader (7 millon downloads, see) it seems that if we pass browsers then it is enough (because the validation is somehow done within this plugin).

Do you think that as handled by postcss-preset-env other plugins could fail?

postcssPresetEnv({ browsers: 'last 2 versions' })

PostCSS Preset Env includes autoprefixer and browsers option will be passed to it automatically.
ai commented 3 years ago

@artola postcss-preset-env uses Browserslist. If you will set BROWSERSLIST environment variable, postcss-preset-env (and all Browserslist-based tools like Autoprefixer and Babel) will use the same set of browsers.