Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CSS Modules and multiple layouts/themes?

In my application, I have multiple theme styles (you can think of them as different, separate CSS styles files). I would like to start using the CSS modules, but I don't know even how to import my first file.

Lets assume the following (simple) directory structure:

layouts/
    themeA/
        myComponent.css
    themeB/
        myComponent.css
    themeC/
        myComponent.css
components/
    myComponent.js

Depending on the user settings, I would like to pick a different CSS. That's easy to do in the browser (or on the server). But how can I include myComponent.css into myComponent.js?

According to CSS modules, I should import the file I'm using. So import styles from 'theme/myComponent.css. The problem is that I don't have one true theme, but 3 different, parallel themes.

import styles from '' // <<<< from what?

return `<div class=${styles.caption></div>`

Is it even possible to work with multiple layouts/themes when using CSS modules?

like image 356
dotintegral Avatar asked Jul 08 '16 15:07

dotintegral


People also ask

What are the CSS modules?

A CSS Module is a CSS file that defines class and animation names that are scoped locally by default.

Are CSS modules worth it?

CSS Modules let you write styles in CSS files but consume them as JavaScript objects for additional processing and safety. CSS Modules are very popular because they automatically make class and animation names unique so you don't have to worry about selector name collisions.

What are CSS modules in react?

A CSS Module is simply a . css file, where classes act similarly to local variables in Javascript. It is a tool that makes every class unique by including a hash in their name.


1 Answers

If you bundle all 3 themes in one file. You can easily pick one of them and render component with it. You must have the same schema for all .css themes, for example:

.wrapper {
  // example content
}

.image {
  // example content
} 

In myComponent.js you will import all themes and assign to object (it will be easier to pick one of them):

import themeA from './themeA.css';
import themeB from './themeB.css';
import themeC from './themeC.css';

const themes = {
  light: themeA,
  dark: themeB,
  pink: themeC
}

Your themes will look something like this:

{ 
    light: {
        wrapper: "themeA---wrapper---2IVWH",
        image: "themeA---image---3omJ7"
    },
    dark: {
        wrapper: "themeB---wrapper---fHfAZ",
        image: "themeB---image---17erf"
    },
    pink: {
        wrapper: "themeC---wrapper---2i9L2",
        image: "themeC---image---3OKIG"
    }
}

Since css-modules are simple object with pointer to new class names you can dynamically pick one of them:

const render = themeName => {
  const theme = themes[themeName];
  return $(`
    <div class="${theme.wrapper}">
      <img 
          class="${theme.image}"
          src="http://exmoorpet.com/wp-content/uploads/2012/08/cat.png" 
      />

      <p>Lorem ipsum </p>
    </div>
  `);
};

I used jQuery only for simplicity of mockups. You can see all working code here: webpackbin


Load styles asynchronously in runtime (edit)

If you use require.ensure (great explanation here) you can download style in runtime. Change myComponent.js to async require:

import $ from 'jquery';

const render = (wrapper, theme) => {
  const template = $(`
    <div class="${theme.wrapper}">
      <img 
          class="${theme.image}"
          src="http://exmoorpet.com/wp-content/uploads/2012/08/cat.png" 
      />

      <p>Lorem ipsum </p> 
    </div>
  `);
  wrapper.html(template);
};

export default (wrapper, themeName) => {
  switch(themeName) { // this will produce 3 chunks with styles
    case 'light':
      require.ensure([], () => {
        render(wrapper, require('./themeA.css'));
      });
      break;
    case 'dark':
      require.ensure([], () => {
        render(wrapper, require('./themeB.css'));
      });
      break;
    case 'pink':
      require.ensure([], () => {
        render(wrapper, require('./themeC.css'));
      });
      break;
  }
};

Webpack will produce this chunks (1 main and 3 with styles):

chunk    {0} main.js (main) 267 kB [rendered]
    [0] ./src/main.js 827 bytes {0} [built]
    [1] ./~/jquery/dist/jquery.js 264 kB {0} [built]
    [2] ./src/select.js 440 bytes {0} [built]
    [3] ./src/myComponent.js 1.82 kB {0} [built]
chunk    {1} 1.1.js 10.2 kB {0} [rendered]
    [4] ./src/themeA.css 1.08 kB {1} [built]
    [5] ./~/css-loader?modules&localIdentName=[name]---[local]---[hash:base64:5]!./src/themeA.css 428 bytes {1} [built]
    [6] ./~/css-loader/lib/css-base.js 1.51 kB {1} {2} {3} [built]
    [7] ./~/style-loader/addStyles.js 7.21 kB {1} {2} {3} [built]
chunk    {2} 2.2.js 10.2 kB {0} [rendered]
    [6] ./~/css-loader/lib/css-base.js 1.51 kB {1} {2} {3} [built]
    [7] ./~/style-loader/addStyles.js 7.21 kB {1} {2} {3} [built]
    [8] ./src/themeB.css 1.08 kB {2} [built]
    [9] ./~/css-loader?modules&localIdentName=[name]---[local]---[hash:base64:5]!./src/themeB.css 429 bytes {2} [built]
chunk    {3} 3.3.js 10.2 kB {0} [rendered]
    [6] ./~/css-loader/lib/css-base.js 1.51 kB {1} {2} {3} [built]
    [7] ./~/style-loader/addStyles.js 7.21 kB {1} {2} {3} [built]
   [10] ./src/themeC.css 1.08 kB {3} [built]
   [11] ./~/css-loader?modules&localIdentName=[name]---[local]---[hash:base64:5]!./src/themeC.css 432 bytes {3} [built]

I will prove that 3 chunks with styles contain your theme styles. For example chunk 1 contains this code inside (I'm showing only important part of it):

/***/ },
/* 5 */
/***/ function(module, exports, __webpack_require__) {

    exports = module.exports = __webpack_require__(6)();
    // imports


    // module
    exports.push([module.id, ".themeA---wrapper---shnYu {\n  background-color: #eee;\n  color: #333;\n  padding: 20px;\n}\n\n.themeA---image---18Mgb {\n  float: left;\n  height: 100px;\n  margin: 20px;\n}\n", ""]);

    // exports
    exports.locals = {
        "wrapper": "themeA---wrapper---shnYu",
        "image": "themeA---image---18Mgb"
    };

How it looks in runtime

styles in runtime example

Here you can check new code it will even show ajax download chunks - you can try in console.

like image 121
Everettss Avatar answered Sep 21 '22 14:09

Everettss