Conditional Babel Configuration: Introducing Babel env
We recently got stuck on an issue with Babel configuration inside an isomorphic React application. Our app includes some styles directly from JavaScript:
require('./MyComponent.scss');
export default ({ props }) => (/* ... */);
Using a module bundler such as Webpack, this code is perfectly working. The module bundler would convert the SCSS into plain JavaScript, and eventually inject it in a style
element. However, we are working on an isomorphic application. And, as Node only understands JavaScript, executing our transpiled file without the SCSS to JS translation step, our code would result in following error:
/home/jpetitcolas/dev/my-project/MyComponent.scss:1
(function (exports, require, module, __filename, __dirname) { .my-component {
^
SyntaxError: Unexpected token .
at exports.runInThisContext (vm.js:53:16)
at Module._compile (module.js:387:25)
at Object.Module._extensions..js (module.js:422:10)
[...]
Fortunately, the babel-plugin-transform-require-ignore
plugin allows to ignore some require
statements based on the extensions. Hence, to ignore all SCSS files from our transpilation, we just add the following to our .babelrc
file:
{
"plugins": [
[
"transform-require-ignore",
{
"extensions": [".scss"]
}
]
]
}
If we try to execute our transpiled file again, it should not raise any error anymore. Success? Not exactly: executing this code client-side now displays our component without any CSS. Indeed, the .babelrc
configuration file is global to our project. Our module bundler also uses it, hence ignoring all style-related require
.
My first thought was to find a way to override Babel configuration directly in CLI using the --plugins
option:
./node_modules/.bin/babel --plugins transform-require-ignore MyComponent.js
However, I didn't find how to pass an argument using CLI. It seems it is currently not supported. Diving deeper into Babel documentation, I noticed an interesting feature: the Babel env property.
You can use the env option to set specific options when in a certain environment. Options specific to a certain environment are merged into and overwrite non-env specific options.
So, we can apply a different configuration within a single .babelrc
file simply using a BABEL_ENV
environment variable. Looks like the perfect solution. And indeed, adding the following lines to our .babelrc
file solved our issue:
{
"env": {
"node": {
"plugins": [
["transform-require-ignore", {
"extensions": [".scss"]
}]
]
}
},
"presets": [/* ... */],
"plugins": [/* ... */],
}
Now, by prefixing our transpilation command by BABEL_ENV=node
, we were able to transpile our files without CSS for the server only. And since Webpack doesn't use the BABEL_ENV
variable, styles remain included for client-side.