I have a job writing a custom "resolver":
const ThemeResolver = { apply: function(resolver) { resolver.plugin('file', function(req, cb) { if (req.request.indexOf('[theme]') == -1) { return cb(); } const defaultFile = req.request.replace('[theme]', 'Default'); const themedFile = req.request.replace('[theme]', process.env.THEME); req.request = themedFile; this.doResolve(['file'], req, (err) => { if (!err) { return cb(); } req.request = defaultFile; this.doResolve(['file'], req, cb); }) }); } }; module.exports = {
It tries to resolve a file with [theme] in its path to a path with a theme defined as an environment variable. If it fails, it will replace the default file instead. Thus, I can require a theme file as follows:
import Presentation from './button-[theme]'
The main component turned out to be a little different than in my question, but I'm actually quite pleased with it:
import React from 'react'; import Presentation from './button-[theme]'; export default class Button extends React.Component { onClick = (e) => console.log('some logic'); render() { return <Presentation onClick={ this.onClick } />; } }
The logic of this button component can be inside button.core.jsx , while the presentation will be processed by one of these components:
THEME=theme-a npm start // button-[theme] resolves to button-theme-a.jsx THEME=theme-c npm start // button-[theme] resolves to button-default.jsx
Disclaimer: I have not used this in a large-scale or production environment, but it seems to work in a small POC. Please let me know if I am doing something unreasonably!
Jpunt source share