Creating Meteor Packages — capsulecat:react-bem

This article was originally published on January 26, 2016 on The Capsule Cat Blog. For archive purposes, we moved it here!


The goal with creating the React BEM package is to take the work at cuzzo/react-bem and integrate it into Meteor. By using this code, we are able to use automatically generated BEM class names in our React components. So we can use SCSS and still write BEM code without having to waste time actually adding the BEM class names to our React components.

So, before I even made the a package repo or started writing my real package code. I needed to get a proof of concept working in Meteor. The first question was: can I just add this code somewhere to a project that uses React, and start using it?

Prototyping React BEM

I took the built file from cuzzo/react-bem and added it to a simple project that had React and a single React component. The component looked something like this after I added the mixins:

Todo = React.createClass({
mixins: [ReactBEM],
bem_blocks: ["widget"],
bem_block_modifiers: ["test"],
bem_render: function () {
return (
<div role="introduction">
<p>Hello</p>
</div>
);
}
});

I ran the app, and… it didn’t work. The approach that cuzzo had taken in his original approach now didn’t work thanks to changes that Facebook made to the React API. Alright, couldn’t be that hard to fix, right?

Well, it took a lot or rewriting, and a completely different approach than the original code, but issued a pull request to get the software to work with the latest version of React!

After the changes, I ran the app, and it worked! Time to make the package!

Getting Started

Let’s start with the package.js file. We need to use ecmascript, react, and we are going to include add two files and export the variable ReactBEM for other developers to use.

Package.describe({
name: 'capsulecat:react-bem',
version: '1.0.0',
summary: 'BEM class names are systematic. So why write them yourself?',
git: 'https://github.com/CapsuleCat/MeteorReactBEM',
documentation: 'README.md'
});
function includeFiles(api) {
api.use('ecmascript');
api.use('react@0.14.3');
api.addFiles('src/ClassBuilder.js');
api.addFiles('src/ReactBEM.js');
}
Package.onUse(function(api) {
api.versionsFrom('1.2.1');
includeFiles(api);
api.export('ReactBEM');
});
Package.onTest(function(api) {
//
});

In src/ClassBuilder.js, we are going to write a little utility class that will make it so that our block-element-modifier class name generation is a lot more readable:

ClassBuilder = function () {
var _chainedString = '';
var block = function(b) {
_chainedString += b;
return this;
}
var element = function (e) {
if (e) {
_chainedString += '__' + e;
}
return this;
}
var modifier = function (m) {
if (m) {
_chainedString += '--' + m;
}
return this;
}
var build = function () {
return _chainedString;
}
return {
block: block,
element: element,
modifier: modifier,
build: build
};
}

We won’t go into the bulk of the src/ReactBEM.js code, you can view the full source here.

How it works, is that when render() is called, we take the result of bem_render() and transform it. We iterate through the children recursively, create the BEM classname for the child, and then copy the React element with the new classnames.

We then take the transformed React element and return it.

Testing

Thanks to the work that cuzzo originally provided, there are a multitude of tests ready for us to run. You can see all the tests here on the Github repo.

We need to update our package.js file with the tests to run:

Package.onTest(function(api) {
api.use('mike:mocha-package');
includeFiles(api);
api.addFiles('tests/ReactBEM.test.js', ['client']);
});

You can run the tests by running:

meteor test-packages ./

Deploying

The last step is to deploy our package to Atmosphere!

meteor publish — create

capsulecat:react-bem on Atmosphere

React BEM package on Github


Thanks for reading! If you liked this article, feel free to follow us on Twitter.