webpack-contrib / postcss-loader

PostCSS loader for webpack
MIT License
2.86k stars 212 forks source link

Function config does not work in webpack 2 with postcss-loader 1.0.0 #114

Closed Jessidhia closed 7 years ago

Jessidhia commented 8 years ago

To use a function config, parseOptions expects the typeof of the options to be a 'function', but that is not allowed by the webpack 2 schema.

https://github.com/postcss/postcss-loader/blob/master/index.js#L8-L11

WebpackOptionsValidationError: Invalid configuration object. Webpack has been initialised using a configuration object that does not match the API schema.
 - configuration.module.rules[4].use[2].options should be one of these:
   object | string
 - configuration.module.rules[4].use[2] should be one of these:
   string | object { loader?, options?, query? }
ai commented 8 years ago

We suggests only plugins to be a function, not options:

          {
            loader: 'postcss-loader',
            options: {
              plugins: function () {
                return [
                  require('precss'),
                  require('autoprefixer')
                ];
              }
            }
          }
michael-ciniawsky commented 8 years ago

Can you show the config you used please :) ?

module: {
  rules: [
      ...,
     {loader: 'postcss-loader', options: { plugins: () => [ require('postcss-plugin') ] }}
     // With PostCSS Options, e.g custom parser
     {
       loader: 'postcss-loader', 
       options: {
         parser: 'sugarss', 
         plugins: () => [ require('postcss-plugin') ] 
       }
     }
     ...,
  ]
}

loader.options must be a {String} or {Object}, but loader.options.prop can be 'everything'

Jessidhia commented 8 years ago

(on the phone, but) I need the syntax option to also be configurable, which is why I didn't make only plugins be a function.

ai commented 8 years ago

Hm. Very strange, I testes with latest webpack 2 and its accepts function. What exactly version of webpack do you use?

ai commented 8 years ago

If you need configurable syntax option, you should use PostCSS config (also it is better way, than put plugins to webpack config)

Jessidhia commented 8 years ago
function postcss () {
  return makePostcssConfig(__DEV__, this.resourcePath.endsWith('.sss') ? sugarss : null)
}

makePostcssConfig returns an object with { plugins, parser }.

There is a way to configure postcss other than the loader options?

ai commented 8 years ago

What is makePostcssConfig? :D

Here is a docs about common PostCSS config: https://github.com/postcss/postcss-loader#postcss-config

And here is a example how to use config https://github.com/michael-ciniawsky/postcss-load-config#examples

michael-ciniawsky commented 8 years ago

@Kovensky yep, postcss-load-config

postcss.config.js (located in root directory)

module.exports = (ctx) => {
   parser: ctx.resourcePath.endsWith('.sss') ? 'sugarss' : false,
   plugins: { 
     'postcss-plugin': {}
  }
}
michael-ciniawsky commented 8 years ago

But test for .cssand .sss extname in your webpack.config.js separately, like in the example @postcss-load-config to enable/disable the custom parser :)

michael-ciniawsky commented 8 years ago
const webpack = require('webpack')

module: {
  rules: [
    {
      test: /\.(sss|css)$/,
      use: [
        ...,
        {
          loader: 'postcss-loader', 
          options: {
            parser: webpack.resourcePath.endsWith('.sss') ? 'sugarss' : false, 
            plugins: () => [ require('postcss-plugin') ] 
          }
        }
      ]
    }
  ]
}

Not tested, but it should work like that in webpack.config.js

ai commented 8 years ago

For my /\.(sss|css)$/ case is too complicated. I think you should use power of webpack’s test and have separated loaders:

module: {
  rules: [
    {
      test: /\.sss$/,
      use: [
        ...,
        {
          loader: 'postcss-loader', 
          options: {
            parser:  'sugarss'
          }
        }
      ]
    },

    {
      test: /\.css$/,
      use: [
        ...,
        {
          loader: 'postcss-loader'
        }
      ]
    }
  ]
}
Jessidhia commented 8 years ago

The problem with having separate loader configs is how css-loader handles @import or composes: x from 'y'.

css-loader will basically invoke its current chain but starting importLoaders loaders before itself. This prevents having .sss files import .css files, and vice-versa, as they would run the same postcss-loader with the same hardcoded parser as was used to load itself.

I am still doing some refactoring to try out the the postcss.config.js method. I actually had my config in a file named postcss.config.js that I required in the webpack config, so at best I should only need to change the export format and the file location...

Jessidhia commented 8 years ago

The postcss.config.js method (via postcss-load-config) does not work for me.

Firstly, it looks like the lookup for postcss.config.js is relative to the CWD, and not to the resourcePath (like .eslintrc or .babelrc are). If I put the postcss.config.js in src/postcss.config.js but invoke webpack outside src, the postcss.config.js is not even visited.

Secondly, the exported function (module.exports = function () { console.log(this, arguments) }, for testing) only receives an object with cwd and env keys, so I have no access to the resourcePath to conditionally load sugarss. this is also undefined. The value cwd is also the cwd of the webpack process, and the env value is undefined.

Thirdly, postcss-load-plugins refuses my generated config, even though it works through the postcss API used by postcss-loader 0.13.0.

It refuses the object returned by require('doiuse')({}), which looks like { info: [Function: info], postcss: [Function: postcss] }. It also refuses require('postcss-cssnext')({}), as it returns an instance of Processor.

I have not checked this, but it's also possible that the use of a postcss.config.js might interfere with the postcss used internally by css-loader for its implementation of css modules.

ai commented 8 years ago

@michael-ciniawsky oops, we forget about resourcePath. How I can set current file path in postcss-load-config?

ai commented 8 years ago

@Kovensky

Thirdly, postcss-load-plugins refuses my generated config, even though it works through the postcss API used by postcss-loader 0.13.0.

What config exactly? postcss-load-plugins loads special new config. It is not a webpack config, it is common PostCSS config. So postcss-loader 0.13 had no this config.

ai commented 8 years ago

@Kovensky

The problem with having separate loader configs is how css-loader handles @import or composes: x from 'y'.

I think it is css-loader issue. We could make some hacks in postcss-loader to handle resourcePath sss hack, you wrote. But new users will not be so smart as you.

css-loader should handle it out-of-box. Adding more hacks is not a user friendly way :(.

If you need some solution right now. Maybe you should try postcss-modules? I am really not happy, how hacky CSS Modules are in css-loader. So postcss-loader is a simpler way.

michael-ciniawsky commented 8 years ago

oops, we forget about resourcePath. How I can set current file path in postcss-load-config?

@ai I did not forget :), but first the config must work in general, for each build tool integration there must be a good default context found 😛 and discussed when it gets to complicated and error prone again, starting to put the config in the root ('as standard') for the beginning was the best solution imo, but yep agreed search from this.resourcePath is the better solution for webpack usage long-term.

postcss-load-config accepts the following arguments

postcssrc(ctx, path, options).then(...)

But the path param currently refers to dir search only, cosmiconfig separates dir / file search

cosmiconfig('postcss', options).load(dirpath, filepath) 

so maybe this.resourcePath as absolute path does not worka atm, but fixing this is trivial ;)

postcss-loader/index.js

...
  return config(pack, loader.resourcePath) 
  // pack === ctx ? :) => var ctx = assign{{}, pack, loader}
  // return config(ctx, loader.resourcePath) 
  // Why pack in general, it's for plugins packs only I thought?
...

postcss.config.js

module.exports = (ctx) => {
   parser: ctx.resourcePath.endsWith('.sss') // etc.
   plugins: {}
}

But maybe find some sane context defaults specific to postcss-loader first and add them to README.md, e.g like ctx.env works atm.

ctx.file === loader.resourcePath
ctx.ext() === loader.resourcePath.endWith()
ctx.add === loader.addDependencyTo

postcss.config.js

module.exports = (ctx) => {
   parser: ctx.ext('.sss') ? 'sugarss' : false
   plugins: {}
}

in the next postcss-load-config release, when process.env.NODE_ENV === undefined, config sets it 'development', I was uncertain at the beginning if setting the env should be the business of build tools etc. but seems fine in the first battle tests :D. I take a look at it today/tomorrow (as soon as possible) with new config release, but testing CLI usage atm/before release 😛

cli

ai commented 8 years ago

@michael-ciniawsky my path concern is not relevant for ctx. I told about:

postcss.config.js
scr/
  index.css
  legacy/
    postcss.config.js
    index.css

So src/legacy/index.css will have different plugins.

Are we ready for it? I hust need to set path to second argument?

ai commented 8 years ago

@michael-ciniawsky of couse, we could set ctx in 1.1 too. Right now a (how some strange reason, I think it is a mistake) calls loadConfig(pack) (pack is a plugins pack name).

I should replace it to loadConfig(loader, loader.resourcePath)?

michael-ciniawsky commented 8 years ago

@ai yep, but needs to be tested, if the path param works with this.resourcePath out-of-the-box, since it's the absolute path not the just the directory. Asap solution would be either with

return config(pack, loader.resourcePath)
return config(pack, path.dirname(loader.resourcePath))

for now, guessing the latter ;)

michael-ciniawsky commented 8 years ago

What is pack refering to when loading the config ?

ai commented 8 years ago

@michael-ciniawsky pack is a mistake, I will replace it to loader.

michael-ciniawsky commented 8 years ago

:+1: yep, gotcha saw the comment popping up after writing :)

michael-ciniawsky commented 8 years ago

Plugins Packs / Presets is coming soon to postcss-load-config

michael-ciniawsky commented 8 years ago

after discussion about it of course, but I have something in mind :)

ai commented 8 years ago

@michael-ciniawsky everything is fine here? 7152ad63a8816e74626345d5b37589f6

I set webpack instance to ctx.webpack (because you merge ctx with default context, so all webpack instance functions could be missed).

If everything is fine, I will release 1.1.

michael-ciniawsky commented 8 years ago

@ai 👍 tested it locally and your changes work fine, but can you wait maybe 1/2 days before release next minor ? :) final postcss-load-config needs onyl a few small fixes (mostly done) and testing for

if (plugin.default && typeof plugin.default === 'function')  plugin = plugin.default

e.g for postcss-sprites

The fixes and adding the above is really easy but I'm again busy requesting church asylum for someone, it's always extremely time consuming and when there is progress you need to be responsive quickly, it's really damaging to the 'flow' currently, but bla bla bla 😛 , the issue for autoprefixer/css-loader docs refactoring is also pending and I would also like to find and experiment with aliases for ctx.webpack. But the latter could also be part of next minor and load-config is a patch anyways, so in case you don't want to wait, go ahead 😎

ai commented 8 years ago

@michael-ciniawsky :+1: sure, ping when when you will release it

ai commented 8 years ago

@michael-ciniawsky any updates or it is bog task?

michael-ciniawsky commented 8 years ago

@ai headinf home right no and ill ten finally ork on it, I'm done or now with social work :). Bit more patience please 👀 😛

michael-ciniawsky commented 7 years ago

@ai finally done 😛

ai commented 7 years ago

postcss-loader 1.1 is now released

Jessidhia commented 7 years ago

While trying to adapt my codebase to use 1.1, I found a few problems that I am working around / fixing with https://github.com/michael-ciniawsky/postcss-load-plugins/pull/17 and https://github.com/michael-ciniawsky/postcss-load-options/pull/18.

However, I hit a snag because one of the files I am trying to process is a symlink that points outside the tree with the postcss.config.js, so postcss-load-options can't find it. I could work around it by reversing the symlink, though, but it could be good to have another alternative.