Category:

I was honored to work on the Test Tooling Team at Hootsuite since January, and one of the main projects that I actively participated in is the Arbiter Tests Management System, a project that provides a user-friendly way for QAs and Developers to manage the tests to be run on different build pipelines in real time. By allowing the users to directly toggle tests from the UI, Arbiter has significantly reduced the resolution time to tests failures in the organization.

As the program aims to optimize developer’s experience, we focused not only on the practical convenience of the program, but also on the design of the user interface that could create a pleasant visual effect for the developers. With this in mind, we have designed 5 different themes ranging all over the spectrum: dark, light, oreo, tiramisu, and azure.

While React has been the de-facto standard for front-end development at Hootsuite, we have also chosen React as our front-end language to effectively build the visual effects we intended to achieve.

CSS to LESS

When Arbiter was first built, we stored our styles into old-fashioned CSS Stylesheets, where themes are loaded as a stylesheet link element in HTML, and switching stylesheet involves simply changing the link of the style element with a Javascript function.

In February, I completed the process of refactoring CSS Stylesheets into LESS Stylesheets to match the organization standards at Hootsuite. This transition results in a much more efficient integration with React. The stylesheets are now loaded directly into the components they style with less-loader so that we don’t have to work with stylesheets in raw CSS.

BUT, alas, every rose comes with its thorn! Now that stylesheet loading is handled by less-loader, we can no longer explicitly manipulate the stylesheet links to switch themes 🙁

After two days of desperate research, I experienced a lot of frustration with the lack of solutions on this topic online. Through this blog post, I would like to demonstrate this simple process that I came up with so that people in my shoe could save their research time. It is also a testament that sometimes it is not necessary to rely on more advanced packages to solve issues, simple Javascript with some thoughts to it just does the job equally well!

Component Structure

To make things simple, I have separated all the theme-loading related functions into its own React component named ReactThemeLoader. The overall structure of this component involves initially loading all the available themes, disabling all the themes, and re-enabling the current theme.

The mechanism of this system relies the fact that stylesheets loaded onto DOM can be toggled on and off by setting the boolean property “disabled”.This property gives us the flexibility to load multiple themes onto the page at once by enabling the current theme and disabling others, without having them interfering one another.

In componentWillMount, all the themes are loaded and disabled initially. The index of the theme stylesheets are tracked here and recorded as key-value pairs into a dictionary called themes in state.

After the components are mounted, in componentDidMount, the program reads the theme name stored in the cookie and and sets the theme by calling setTheme(). In case the cookie is not present, the theme will be set to default theme (in this case dark), which is handled by the setTheme() method.

In the setTheme method, the stylesheet indexes of the old theme and new theme are simply retrieved from the dictionary themes and toggled by setting the “disabled” property of the stylesheets as shown above.

The UML Diagram for the theme-loading process is shown below:

NPM Package

To make this React Component more reusable, I have published an NPM package: react-theme-loader (http://ow.ly/U9Lt30asuTX) as a ready-to-use open-source React package for you. Below is where the tutorial actually starts

Install the NPM Package

Under your project directory, run:
npm install react-theme-loader –save
 

This command will install this node package to your project and add it to the dependencies in package.json

Import the React Component

In your top-level React components where you want the theme styles to take effect, import the package and render it as a component

When rendering the ThemeLoader, there are certain properties we need to attach to the element; the above is just an example, please read the instructions below on filling in the props and do NOT copy the above exactly.

Required
“ref”: pass in “themeLoader” exactly so that you have access to the functions provided by the component.

“supportedThemes”: pass in an array of strings that represent the names of the theme files (without “.less”).

Example:

“themeDirectory”: pass in the relative path of the directory of the theme files in “supportedThemes”

Optional
“fonts”: pass in the relative path of the fonts file. This file should contain ALL fonts used in the themes, and do NOT import any fonts in the theme files since they mess up the indexes of loaded stylesheets. If “fonts” is not specified, no fonts file will be loaded.

“defaultTheme”: pass in the name(string) of the default theme, which will be loaded initially when no theme cookie is stored. The first theme in “supportedThemes” will be the default if not specified.

“themeCookie”: pass in the name(string) of the cookie where you wish to store the current theme name, so that the browser will remember the selected theme. “CURRENT_THEME” will be used if not specified.

Using react-theme-loader

Switching Themes
In the React component where ThemeLoader is rendered, simply use

to switch themes, where theme is the name(string) of the theme you wish to switch to.

When a theme is loaded, the ThemeLoader will render the following to HTML:

Cookie

Currently the theme information in our system is completely relying on un-encrypted browser cookie, named “CURRENT_THEME” by default. The package gives you an option to pass in the cookie name you wish to have.

Although theme information is not sensitive, it still brings inconvenience and leaves holes for security issues. We are currently looking into other ways of improving this features.

React-Theme-Loader 2.0 !!!

Currently, the react-theme-loader package is still in its rudimentary stage and a lot of customized features can be added to the component. The ones listed below are in progress, please feel free to leave any ideas below in the comments

 

  • Customized way to store current theme information
As mentioned above, the current way of storing theme information in cookie isn’t ideal. In a lot of applications, it is more ideal to store those to a user account. Instead of doing the cookie handling in the component itself, the component will be able to read in a customized function by the user to handle the job.

 

  • More robust import handling
Currently, you would have to store all the imported fonts into a separate fonts file for the component to read the correct indexes of other stylesheets, since importing fonts in a stylesheet causes index problems. In the future, more investigation will be made to ensure that adding “import” statements in .less files will not cause the program to break.

Conclusion

Completing the transition from CSS Stylesheets to LESS Stylesheets is one of the first refactoring process I have worked on during my time at Hootsuite. While I have been through a lot of frustrations and desperation throughout this process, I was forced into discovering more hidden features in the world of programming (leading me to make my first npm pacakge!) Looking back at the process, I would consider it is a tremendously helpful experience in the long run with major improvements made to the system.

About the Author

Sonny Yu was a co-op student on the Test Tooling team for the spring term of 2017. He studies Computer Science and Business Administration at University of Waterloo. Connect with him on LinkedIn!