February 28, 2018 Darya Talanina 5 min read

As a web developer you may have already worked on a project where you had a single web application that was used by several different clients. The app would use a single code base but then it would need to have several variants, each personalized for a specific client:

you may need to change the look and feel of the app (turquoise color theme background instead of a red one, text aligned on the right instead of left, different fonts and illustrations)

the API calls you are making may vary depending on the client: each client could want to to have his own wording and you would need to fetch different i18n key-values depending on the client.

Imagine you develop a ticket selling platform and you offer a ticket selling app that is integrated in websites of your clients that include theaters, sports organisations and art galleries. You will most likely need to change the design and layout of the app for each of the clients so that it corresponds to the look and feel of their website.

In this article, I will show you how to have several personalized versions of your app while keeping a single code base.

We will begin with a simple ReactJS poll app styled using a styled-components theme. Then we will create a second version of the app by adding another style theme and some structural differences. Lastly we will configure the build so that we are able to switch between the two versions of the app.

To help you easily set up the project there is a companion repository.

Initializing the project and creating a basic app

Start by checking out the project and installing the required packages:

git clone https://github.com/invfo/theming-with-webpack.git cd theming-with-webpack git checkout 514f5fd //checkout the commit pointing to the first version of the app npm install

Then start the development server: npm start and go to http://localhost:8080 in the browser. You should see the following poll with two options and a submit button.

Customizing the app

We will now create a second version of this polling app.

Changing the look and feel

Begin by adding a second theme and a switch between two themes based on a THEME variable (which we will define later):

const advancedTheme = { background : 'linear-gradient(#68C5DB, #E0CA3C)' , button : { border : '3px black dotted' , borderRadius : '23px' , fontSize : '30px' , marginTop : '17px' , padding : '5px 10px' , } , } ; const theme = THEME === 'advanced' ? advancedTheme : basicTheme ;

Pass the new theme to the ThemeProvider :

<ThemeProvider theme={theme}> // index.js

Add a Title component and display it based on the THEME variable :

// index.js const Title = ({children}) => <h1>{children}</h1> class App extends React.Component { render() { return ( <ThemeProvider theme={theme}> <Wrapper> { THEME === 'advanced' && <Title>Make your choice!</Title>} ...

Checkout the corresponding commit in the companion repository to see other minor changes that should be made.

Setting up the THEME variable

To be able to switch between the two app versions we need to define the THEME variable which we will wire to an environment variable of the same name.

Begin by setting the THEME environment variable at build time and making it available in our app.

Add a build command for each app version. These commands will set the THEME environment variable to either red or blue :

// package.json "scripts": { "start:basic": "cross-env THEME=basic webpack-dev-server", "start:advanced": "cross-env THEME=advanced webpack-dev-server" }

You may wonder “'Cross-env'? Why not simply use THEME=red webpack-dev-server ?”. This option would work fine on most OSs, but can be troublesome if you are using Windows.

Cross-env allows you to define environmental variables without worrying about particularities of the platform you are using. Install it: npm install --save-dev cross-env

Finally let's put together everything we did in previous steps: make the THEME environment variable available in the app code

// webpack.config.js plugins: [ new webpack.DefinePlugin({ THEME: JSON.stringify(process.env.THEME), }), ]

DefinePlugin enables you to create global constants that are configured during compilation. Here we’re using it to define a THEME variable that is usable in our app’s code. Its value will be equal to the THEME environment variable set using cross-env.

For more info see the official webpack doc.

Now try out one of the new builds: npm run start:advanced

You should see the new version of the app:

To view the old version, run npm run start:simple

You can always get the latest app code version from the companion repository.

To sum up

So far we have learned how to:

Define your app’s style and manage several CSS themes using styled-components and its ThemeProvider (check out the official docs for more information)

Set up environment variables for the build using cross-env

Make previously set environment variables available in your app’s code using webpack’s DefinePlugin

Modify app’s content based on an environment variable value (on the example of )

Using the above concepts you can personalize your ReactJS app and have several builds, each of them generating an app with a specific look.

The proposed method is suitable when the personalization you need to make:

concerns style or

basic html structure (like changing input types or adding / hiding certain elements).

As with any other concept, you should not blindly apply it on your project but rather ask yourself if this is the most suitable solution. The proposed way of personnalizing can be used when different app variants are quite similar. But if your app versions are totally different, having many if in your code will make it hard to maintain. In this case opt for another solution, for example having a separate "main" file for each version.

Have you already worked on a ReactJS app with several themes? How did you implement it?

Share your experience in the comments below or simply let me know if you have any questions or remarks!