CSS Modules for Meteor (without Webpack)

Four months ago, I released my CSS modules build plugin for Meteor, but never got around to announcing it here on the forums. Now that I’m busy working on an updated version for Meteor 1.3, I decided to spread the word.

If you haven’t heard of CSS modules, the concept is simple: classes are scoped locally (by file) instead of globally. This frees you from global scope concerns and allows you to use simple descriptive class names such as .button, .post, etc. It fits perfectly with components (manuel:viewmodel , React, etc). Classes can be composed of other classes via composition.
A more detailed introduction can be found on Glen Maddern’s site.

Please check out the package (and the sample app) and let me know your feedback!

Features

  • Sass preprocessing
  • React Toolbox support
  • Postcss Plugins support
  • Global variables (for colors, themes, etc)
  • Server-side Rendering

Here’s a sample module:

.purple {
  color: purple;
}

.message {
  composes: purple;

  font-weight: bold;
  font-size: 50px;
}
import styles from './hello-meteor.m.css';

Template.helloMeteor.helpers({
  styles
});
<template name="helloMeteor">
  <h1 class="{{styles.message}}">Hello Meteor!</h1>
</template>

Rendered output:

<h1 class="_client__hello_meteor__message _client__hello_meteor__purple">Hello Meteor!</h1>

The generated class name is a combination of the file path (client/hello-meteor.mss) and the class name.

17 Likes

This is so cool! Thanks for this!

Though, I haven’t used CSS modules before but this is interesting, there’s a running heated thread [here] (Styling - a big challenge these days) regarding the challenge on styling. You might want to check that out.

1 Like

Have you tried with standard .css files? CSS Modules is a feature which is missing for me in Meteor 1.3 and this is the last thing for me which might provide ‘real’ Meteor modules. But I don’t like .mss extension much :confused: Have you heard about https://github.com/michalkvasnicak/babel-plugin-css-modules-transform ? Maybe there is a way to create babel-compiler which will use this plugin (or maybe there will be a way to just add the plugin, I think for now this is impossible because .babelrc is disabled) There will be also needed PostCSS plugin which will transform class names. Just brain storming here. I whish someone from MDG could chime in with their ideas here, this is really cool stuff. Anyway, thanks for your work :slight_smile:

1 Like

I wish I could use .css (I don’t like the .mss extension either) but that’s a no-go:

While determining active plugins:
error: conflict: two packages included in nathantreid:css-modules (meteor and nathantreid:css-modules) are both
trying to handle *.css

Part of the in-progress sass support includes making the file extension configurable, so you can set it to whatever you want, except for .css. :expressionless:

It would be awesome if I could register a .css compiler before whatever Meteor does to.css files but after all other extensions have processed, then I could scrap the sass support and just rely on fourseven:scss.

Yeah, this is the same as with my postcss package. I needed to use minifiers instead build plugins :confused:

I’ve played with babel-compiler and mentioned css modules plugin which uses css modules require hook and I was able to imort .css files in the format:

@import styles from './main.css';
console.log(styles.myClass) // result: {myClass: 'some-weird-class-name-string'}

but it was really hacky, there is also a problem with Node version, I needed to use some polyfills and some path changes so I gave up :confused:

I hope this will land in Meteor someday

1 Like

A quick test revealed that simply commenting out Meteor’s CSS compiler registration is all it takes to get my plugin working on the .css extension, so hopefully MDG will break the CSS compiler out into a separate plugin soon.

Meteor’s CSS compiler is pretty much the simplest compiler ever, all it does it call addStylesheet() for each CSS file, so there’s no worries about missing functionality either.

2 Likes

Would this make the use of react toolbox possible? Is their anyway to import files from npm packages?

you should still be able to overload the extension with
’styles.m.css’ registering your compiler on ‘.m.css’ or ‘.module.css’

Not confusing IDEs anymore.

I think that this works. Would be great.

2 Likes

So has anyone successfully used react toolbox with meteor 1.3?

My just-released latest beta (nathantreid:css-modules@1.0.0-beta.9) adds support for react toolbox / SASS compilation.
As long as you’re not on a Mac, you can use it now through Atmosphere (Meteor’s OS X build machines have been uncooperative for the past hour or so, so Mac users currently have to check out the repository).

I’ve put up a Meteor version of React Toolbox’s example app; the README also contains instructions on how to integrate React Toolbox into an app of your own.

3 Likes

I like this - I’m going to include the .m.css extension as a default extension in my next update.

I was wondering where the CssModules namespace comes from when you’re doing alternative syntax? That’s a build plugin pickup? does it work in jsx for 1.2?

In the 0.x version, as the MSS files are processed I store their output in an object, where the keys are the file paths and the values are object containing the local -> global class mappings. At the end of processing, I add a JavaScript file that exposes that information to the browser:

var tokens = ${JSON.stringify(tokens)};
window.CssModules = {
	'import': function importStyles(path) {
		return tokens[path];
	}
};

Since Meteor 1.2 lacks support for import statements, I overrode the Babel compiler so that it replaces all import yourVariable from 'yourFile.mss' statements with var yourVariable = CssModules.import('yourFile.mss');, so in the 0.x version of the plugin, all of your statements end up using the CssModules namespace.
The CssModules namespace is no longer available in the 1.x beta, although I’m considering adding it back in.

To answer your last question, yes, it can work in .jsx in 1.2, but doesn’t out-of-the-box. I should be able to push an update soon that enables .jsx processing for the 0.x series.

@nathantreid thanks for the thorough response. I’m
Gonna post an issue and how about you tell me how you want it solved and I’ll give you a PR

How does this not have more likes?? This is brilliant!

Have you thought about instead of doing the substitution via a build plugin, doing it with a babel plugin? That way I can still use ecmascript-hot and you won’t have to worry about constantly bumping versions :slight_smile:

I found some examples that could be used / adapted :slight_smile:

1 Like

I’ve started thinking about babel plugins, but that’s about it. :slight_smile:
It’s definitely on my list of things to check into for the future!

@nathantreid , any update on supporting Mac? I noticed the meteor-1.3 branch was deleted and I’d really love to try this out. Thank you!!

Yes! The Meteor build servers started cooperating, so it’s on Atmosphere now. The latest version is 1.0.3. The Meteor 1.3 branch has become the new master.

Got it working, thank you