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?
A CSS Module is a CSS file that defines class and animation names that are scoped locally by default.
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.
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.
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
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
Here you can check new code it will even show ajax download chunks - you can try in console.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With