Branding applications is a common design requirement. The
concept is simple. We have an application with functional core components, but
based on the partner or client, we need to change the theme or look of the design
elements to match that of the client’s brand. Some of these design elements may
include images, content, fonts, and theme changes. There are different
strategies to support an app branding process, either in the build process or at runtime. In
this article, we discuss how we can support a branding strategy using a code
repository branching strategy and GitHub build actions.
Branching Strategy
A code repository enables us to store the source code for
software solutions. Different branches are mostly used for feature development and
production management purposes. In the case of branding applications, we want
to be able to use branches for two purposes. The first is to be able to import
the assets that are specific to the target brand. The second is to associate
the branch to build actions which are used to build and deploy the branded
application.
To help us visualize how this process works, let’s work on a typical branding use case. Think of an app for which there is a requirement to
support two different brands, call them brand-a and brand-b. With this in mind,
we should think about the design elements that need to be branded. For our
simple case, those elements include the app title, logo, text, or messaging in
JSON files, fonts, and the color theme or skin.
We now need to think of the build and deployment requirements
for these two brands. We understand that each brand must be deployed to a
different hosting resource with different URLs, let’s say those sites are
hosted at brand-a.ozkary.com and brand-b.ozkary.com, These could be Static Web
App or CDN hosting resources.
With the understanding that the application needs to be branded
with different assets and must be built and deployed to different hosting sites,
we can conclude that a solution will be to create different branches which can
help us implement the design changes to the app and at the same time, enable us
to deploy them correctly by associating a GitHub build action to each branch.
GitHub Actions
GitHub Actions makes it easy to automate Continuous
Integration / Continuous Delivery (CI/CD) pipelines. It is essentially a workflow that executes commands
from a YML file to run actions like unit test, NPM build or any other commands
that can be executed on the CLI to build the application.
A GitHub Action or workflow is triggered when there is a pull
request (PR) on a branch. This is basically a code merge into the target
branch. The workflow executes all the actions that are defined by the script.
The typical build actions would be to pull the current code, move the files to
a staging environment, run the build and unit test commands, and finally push
the built assets into the target hosting location.
A GitHub Action is the great automation tool to meet the
branding requirements because it enables us to customize the build with the
corresponding brand assets prior to building the application. There is however
some additional planning, so before we can work on the build, we need to define
the implementation strategy to support a branding configuration.
Implementation Strategy
When coding a Web application with JavaScript frameworks, a
common pattern is to import components and design elements into the container
or pages of the application from their folder/path location. This works by either
dynamically loading those files at runtime or loading them a design/build time.
The problem with loading dynamic content at runtime is that
this requires that all the different brand assets be included in the build.
This often leads to a big and slow build process as all those files need to be included.
The design time approach is more effective as the build process would only
include those specific features into the build, making the build process smaller
and faster.
Using the design time approach does require a strategy. Even
though, we could make specific file changes on the branch, to add the brand-a files
as an example, and commit them, this is a manual process that is error prompt.
We instead need an approach that is managed by the build process. For this
process to work, we need to think of a folder structure within our project to better
support it. Let’s review an approach.
After reviewing the image of the folder structure, we should
notice that the component files import the resources from the same specific
folder location, content. This off course is not enough to support branding,
but by looking carefully, we should see that we have brand resources outside
the src folder of the project in the brands' folder. There are also additional folders
for each brand with the necessary assets.
This way this works is that only the files within the src and public folders are used for the build process. Files outside the src folder should not be included in the build, but they are still within source control. The plan is to be able to copy the brand files into the src/content folder before the build action takes place. This is where we leverage a custom action on the GitHub workflow.
Custom Action
GitHub Actions enable us to run commands or actions during
the build process. These actions are defined as a step within the build job, so
a step to meet the branding requirements can be inserted into the job, which
can handle copying the corresponding files to the content folders. Let’s look
at a default workflow file that is associated to a branch, so we can see
clearly how it works.
By default, the workflow has two steps, it first checks out
or pull all the files from the code repo. It then executes the build commands
that are defined in the package.json file. This is the steps that generates the
build output, which is deployed to the hosting location. The logical step here
is to insert a step or multiple steps to copy the files from all the brand
subfolders. After making this suggested change, the workflow file should look as follows:
The new steps just copy files from the target brand folder
into the src and public folders. This
should enable the build process to find those brand specific files and build
the application with the new logo, fonts, and theme. The step to copy the fonts
does some extra work. The reason is that the font files have different font family
names, so we want to be able to find all the files and delete them first. We
can then move forward and copy the new files.
It is important to notice that the SASS files, SCSS
extension, are key players on this process. Those are the files that provide variable
and font information to support the new color theme, styles, and fonts. When
using SASS, the rest of the components only import those files and use the
variables for their corresponding styles. This approach minimizes the number of
files that need to be customized. The _font.scss file, for example, handles the
font file names for the different brands, as those files are named differently.
For cases where SASS is
not used, it is OK to instead copy over the main CSS files that defines the
color theme and style for the app, but the point should be to minimize the
changes by centralizing the customization just by defining variables instead of
changing all the style files as this can become hard to manage.
Conclusion
Branding applications is a common design requirement which can become difficult to manage without the right approach. By using a branching strategy and GitHub custom action, we can manage this requirement and prevent build problems by distributing the branded assets in different directory to keep the build process small. This approach also helps eliminate the need to have developers make code commits just to make import reference changes.
Thanks for reading.