Skip to content

Allow default options to be overridden globally #132

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

Closed
wants to merge 1 commit into from

Conversation

ekosz
Copy link

@ekosz ekosz commented May 27, 2016

Expose a new variable call globalOptions that, when modified, changes the default options for all react-css-modules Components.

Example code:

import CSSModules from 'react-css-modules';
// Only raise errors in non-production enviroments
CSSModules.globalOptions.errorWhenNotFound = process.env.NODE_ENV !== 'production';
// Allow multiple styleNames for every Component
CSSModules.globalOptions.allowMultiple = true;

Why?:

I few times now I've been cleaning up CSS files, deleted a class I thought wasn't being used anymore, deployed to production, and suddenly get a ton a errors from users that the react app stops working. This is my own fault for not having better tests around my components, but it would still be nice to be able to turn off and on these options globally based on the environment as shown.

What do you think?

Expose a new variable call globalOptions that, when modified, changes the
default options for all react-css-modules Components.
@michaeljacobdavis
Copy link

This would also be helpful for unit testing. Jest doesn't know how to load css, so you normally noop it, but since react-css-modules throws if the class isn't there, you have to bring webpack into the mix.

@gajus
Copy link
Owner

gajus commented Jun 3, 2016

What do you think?

I think that any global settings for third-party library (in this case react-css-modules) introduce an unreasonable factory of predictability, e.g. library is dependency of multiple components in the project with multiple authors working on individual components. Adding global settings could easily break other developer work and cause maintenance nightmare.

I think that this functionality can be achieved using environment variables. Nothing is stopping you from setting the configuration of individual react-css-modules using custom object and default to parameters set in NODE_ENV. This would produce virtually the same result as this PR, except that choice of using globals would be entirely up to the user.

@teameh
Copy link
Contributor

teameh commented Jul 4, 2016

except that choice of using globals would be entirely up to the user.

But you do need an extra import in each file right?

@gajus
Copy link
Owner

gajus commented Jul 4, 2016

But you do need an extra import in each file right?

Or just using global variables (which is what this issue is asking for anyway).

Either that or create a proxy that wraps react-css-modules.

Even better, you can use webpack alias control to overwrite the setting in the entire dependency tree.

@gajus
Copy link
Owner

gajus commented Jul 4, 2016

To clarify the 'proxy' proposal, I am not referring to Proxy. Just a simple abstraction atop CSSModules, e.g.

// ./my-react-css-modules.js
import CSSModules from 'react-css-modules';

export default (component, styles, options = {}) => {
    if (process.env.NODE_ENV !== 'production') {
        options.errorWhenNotFound = true;
    }

    return CSSModules(component, styles, options);
};

and then just re-map using aliases/ or hard-code reference to ./my-react-css-modules (local to your project).

@gajus
Copy link
Owner

gajus commented Jul 4, 2016

Adding any global setting to an external library is a slippery slope, e.g. if you have an app composed of multiple components that have their own dependency tree, then it is likely that you will use deduplication. Any global setting would make the result of deduplication unpredictable.

As such, and considering that there are many ways to implement this in the user land, I am closing this PR.

Thank you for the discussion.

I would appreciate if you'd share with others the end implementation that you have settled for. Might as well add it to the documentation.

@gajus gajus closed this Jul 4, 2016
@ekosz
Copy link
Author

ekosz commented Jul 4, 2016

👍 Good solution to the problem.

@gajus
Copy link
Owner

gajus commented Jul 4, 2016

@ekosz Thank you for the PR.

@teameh
Copy link
Contributor

teameh commented Jul 4, 2016

Nice! That looks neat, thanks.

I'll settled for this, I'm not ready for no mutiple classes yet ;)

// CustomCSSModules.js
import CSSModules from 'react-css-modules';
export default (component, styles) => {
  return CSSModules(component, styles, {
    errorWhenNotFound: process.env.NODE_ENV !== 'production',
    allowMultiple: true
  });
};

Works like charm.

@teameh
Copy link
Contributor

teameh commented Jul 4, 2016

Oh wait, it fails when using ES7 decorator syntax.. I'm getting the ReactElement styleName property defines multiple module names. That might make sense since the decoratorConstructor takes only 2 arguments.. Does something like this make sense?

// CustomCSSModules.js
import CSSModules from 'react-css-modules';
import isFunction from 'lodash.isfunction';

export default (...args) => {
  const options = {
    errorWhenNotFound: process.env.NODE_ENV !== 'production',
    allowMultiple: true
  };

  if (isFunction(args[0])) {
    return CSSModules(args[0], args[1], options);
  } else {
    return CSSModules(args[0], options);
  }
};

or with an Object.assign in case users still want the possibility to override the settings.

if (isFunction(args[0])) {
  return CSSModules(args[0], args[1], Object.assign({}, options, args[2]));
} else {
  return CSSModules(args[0], Object.assign({}, options, args[1]));
}

@gajus
Copy link
Owner

gajus commented Jul 4, 2016

Oh wait, it fails when using ES7 decorator syntax..

Yes, thats why I asked to share with others your implementation. : )

What you shared looks like it could work. (Sorry, I am out of capacity to help with testing at this time.)

Same solution, just different code formatting (consistent with the react-css-modules code base):

import CSSModules from 'react-css-modules';
import _ from 'lodash';

export default (...args) => {
    let options;

    const isComponentFunction = _.isFunction(args[0]);

    options = (isComponentFunction ? args[2] : args[1]) || {};

    if (process.env.NODE_ENV === 'production') {
        options = Object.assign({}, {
            errorWhenNotFound: options.errorWhenNotFound,
            allowMultiple: true
        }, options);
    }

    if (isComponentFunction) {
        return functionConstructor(args[0], args[1], options);
    } else {
        return decoratorConstructor(args[0], options);
    }
};

@teameh
Copy link
Contributor

teameh commented Jul 4, 2016

I think you forgot to replace functionConstructor and decoratorConstructor with CSSModules unless you want to include this in the src ;)

In your snippet you're now overriding the passed in options with allowMultiple: true, I don't think that is what you want.

And errorWhenNotFound: options.errorWhenNotFound does not make a lot of sense, you can just leave it out if this is what you want right?

To be even more explicit:

// CustomCSSModules.js
import CSSModules from 'react-css-modules';
import _ from 'lodash';

const customDefaultCSSModuleOptions = {
  errorWhenNotFound: process.env.NODE_ENV !== 'production',
  allowMultiple: true
};

export default (...args) => {
  let options;

  const isComponentFunction = _.isFunction(args[0]);

  options = (isComponentFunction ? args[2] : args[1]) || {};

  options = Object.assign({}, customDefaultCSSModuleOptions, options);

  if (isComponentFunction) {
    return CSSModules(args[0], args[1], options);
  } else {
    return CSSModules(args[0], options);
  }
};


// Usage
import CustomCSSModules from './../utils/CustomCSSModules';
import styles from './table.css';

class Table extends React.Component { 
    ... 
} 

export default CustomCSSModules(Table, styles);

@gajus
Copy link
Owner

gajus commented Jul 4, 2016

@tiemevanveen Thank you :)

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

Successfully merging this pull request may close these issues.

4 participants