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

Support configuration of style rules, not just rule and loader options #223

Closed
insin opened this issue Jan 12, 2017 · 3 comments
Closed

Comments

@insin
Copy link
Owner

insin commented Jan 12, 2017

The default style rule configured to handle an app's own stylesheets applies to everything by excluding node_modules/ - it's not possible, for example, to use CSS modules for some stylesheets (e.g. just those in src/components/) and global CSS for everything else.

By default we also create a separate a vendor- version of each style rule which handles all imports from node_modules/ the same way.

Equivalents of these two rules are also created for each style preprocessor plugin you use, using the plugin's id (e.g. sass) instead of `css.

We should provide a way to configure this.

Having configurable style rules would also allow you to set up special snowflakes for dependencies which want you do to preprocessing in a specific way.

A way to represent the current setup might be the following - createRules() in createWebpackConfig.js is effectively doing an unrolled version of this for CSS and for any style preprocessors being used:

let styleRuleConfig = [
  {exclude: /node_modules/} // No prefix
  {prefix: 'vendor', include: /node_modules/}
}

What might it look like for a dependency which wants you to use a preprocessor with a specific config?

{
  include: /node_modules[\\/]some-dependency/,
  preprocessor: 'sass',
  prefix // HOLD IT!

The purpose of using a prefix is to ensure every loader has unique id associated with it to allow configuration via webpack.rules[id] - what if this configuration allowed you to provide loader option overrides by loader (in the chain) id?

e.g. enabling CSS modules for a specific path:

{
  include: path.resolve('src/components'),
  rules: { // This container could be omitted
    css: {
      modules: true,
      // ...
    }
  }
}

TBC

@insin insin changed the title Support configuration of multiple CSS loading rules Support configuration of style rules, not just rule and loader options Feb 1, 2017
@insin
Copy link
Owner Author

insin commented Feb 7, 2017

Making Style Rules Configurable

Webpack style processing rules created by nwb chain together style-loader, css-loader, postcss-loader (configured with Autoprefixer by default) and an optional style preprocessor loader provided by an nwb plugin.

These are configured appropriately for development serving and for builds (using ExtractTextPlugin), while also allowing each loader's options to be configured

Current

By default, one rule is created for CSS in your app (exclude: /node_modules/) and one is created for CSS imported from node_modules/ (include: /node_modules/). You also get 2 rules for every style preprocessor plugin being used, with the same include/exclude config.

These are configurable using a naming convention in webpack.rules config which allows you to uniquely target each loader in each default rule.

e.g. css-loader can be configured differently in each rule using css, vendor-css, sass-css, vendor-sass-css, etc.

Next

For nwb v0.16 we would like to make it possible to configure your own style rule setup and provide configuration for the individual loaders chained by the rule at the same time.

Example use case: use CSS modules for CSS from a particular directory but use global CSS for everything else.

Example use case: providing the specific rule setup a dependency from node_modules/ needs, such as react-toolbox.

Backwards Compatibility

Option 1: Same by default. If you don't define webpack.styles (placeholder name), you will get the same default config as nwb <= v0.15 with the usual ability to configure the rules and loaders using unique id props in webpack.rules. This is consistent with the approach nwb normally uses in that upgrading shouldn't break things by default, but should work and log deprecation warnings.

Option 2: Break, with new defaults. If you don't define webpack.styles (placeholder name) you will get a default style pipeline which treats all imported CSS/Sass/Less/Stylus files the same. If not in v0.16, it should become the new default in v0.17.

You should also be able to configure something like styles: 'back-compat' (placeholder name and value) for a couple of releases to explicitly enable the old default config with a deprecation warning.

Style Rule Config

What should the object configuring a single style rule look like?

We need the following values to create rules:

// Style processing configuration object format
// One of these maps to creation of a single Webpack rule
let styleConfig = {
  // Either 'css' or the the id of a style preprocessing plugin
  // e.g. 'sass' if you're using nwb-sass
  type: 'css',

  // Loaders chained in the style rule can have their configuration tweaked
  // using an object under a prop matching their name.
  loaders: {
    style: { /*...*/ }
    css: { /*...*/ }
    postcss: { /*...*/ }
    // When using a preprocessor, its loader can also be configured
    // sass: configure sass-loader, including plugins (type: 'sass', using nwb-sass)
    // less: configure less-loader, including plugins (type: 'less', using nwb-less)
    // stylus: configure stylus-loader, including plugins (type: 'stylus', using nwb-stylus)
    sass: { /*...*/ }
  },

  // For convenience, we will take 'style', 'css', 'postcss' and preprocessor
  // loader config and move it into the `loaders` format above when processing
  // user config if a `loaders` prop doesn't exist.

  // Example of configuring css-loader to use CSS modules
  css: {
    modules: true,
    localIdentName: (
      process.env.NODE_ENV === 'production'
        ? '[path][name]-[local]-[hash:base64:5]'
        : '[hash:base64:5]'
    )
  }

  // All other properties passed will be added to the Webpack rule, so
  // all top-level rule config can be provided here - see module.rules in
  // https://webpack.js.org/configuration/ for all possibilities.
  include: path.resolve('src/components'),

  // Support for custom rules? Maybe next release.
  // What if a use: prop could be used to configure additional loaders?
  // Passing the names of loaders managed by nwb could be detected to allow
  // mixing them with custom loaders, similar to what we do for reusing Karma
  // plugins managed by nwb when creating Karma config.
}

Speculative Example Configs

CSS modules for one directory, global CSS everywhere else

module.exports = {
  webpack: {
    styles: [
      {
        type: 'css',
        include: path.resolve('src/components'),
        css: {
          modules: true,
          localIdentName: (
            process.env.NODE_ENV === 'production'
              ? '[path][name]-[local]-[hash:base64:5]'
              : '[hash:base64:5]'
          )
        }
      },
      {
        type: 'css',
        exclude: path.resolve('src/components')
      }
    ]
  }
}

Variant: an object is provided and its properties are the type, rule configs under it can be an object or a list of objects.

module.exports = {
  webpack: {
    styles: {
      css: [
        {
          include: path.resolve('src/components'),
          css: {
            modules: true,
            localIdentName: (
              process.env.NODE_ENV === 'production'
                ? '[path][name]-[local]-[hash:base64:5]'
                : '[hash:base64:5]'
            )
          }
        },
        {
          exclude: path.resolve('src/components')
        }
      ]
    ]
  }
}

TODO: react-toolbox example

@TimonVS
Copy link

TimonVS commented Feb 7, 2017

It's really focused on styling, but how would I configure the loaders used for JavaScript? Or SVG?

I'm not a huge fan of the custom schema, I'd prefer to stay as close to the Webpack schema as possible.

@insin insin mentioned this issue Feb 9, 2017
4 tasks
@insin
Copy link
Owner Author

insin commented Jun 1, 2017

Implemented in v0.16.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants