
Global business
Software localization
While this works great at first, you will notice that it will become harder and harder to maintain updates of your assets across your projects. Every time someone decides to use a different font or to adjust some frequently used colours from your palette you will find yourself grepping through your entire codebase, hoping you at least named your colour variables consistently so you won’t miss any of them.
And although you think you worked extra carefully, you will eventually find something like this:
[caption id="attachment_2556" align="alignnone" width="300"] colors.scss from Project A[/caption]
[caption id="attachment_2557" align="alignnone" width="300"] colors.scss from Project B[/caption]
At Phrase, we found ourselves in exactly that position. Our documentation and landing pages are separated from our main application. But of course they all share at least some base assets:
After looking at the slight chaos creeping in over the past years, we evaluated possible solutions to clean things up.
Enter the world of Rails engines. Rails engines have been around for a long time and are the best way to provide reusable components for Rails applications as they can provide shared models, controllers, business logic - and assets.
You can consume assets found in a Rails engine seamlessly in your main application via the asset pipeline. This makes Rails engines the perfect utility to share assets across multiple Rails projects. You can organise a Rails engine just like any other gem. This will from now on be the single source of truth for all important assets.
Getting started with Rails engines is easy:
First, create a new Rails engine:
$ rails plugin new mycompany-ui -T
You are now the proud creator of a new gem named mycompany-ui, which contains a Rails engine (that is not very useful, yet).
Now the important work starts. Put all relevant assets into the engine, simply by moving them from your main application to your gem and into mycompany-ui/lib/assets. We found it to be a good first step to start with the main colour definition file and take it from there.
It is also a good idea to define an entry point for importing the assets into your app. So if your color definition file is located at /mycompany/ui/assets/stylesheets/mycompany/_colors.scss, you might want to also add an entry point like this:
@import "mycompany/_colors"; @import "mycompany/_reset"; @import "mycompany/_typo"; // etc.
To now add the gem to your main app, simply add it to your Gemfile:
gem "mycompany-ui", path: "/path/to/engine"
and install it via bundler
$ bundle install
We’ll talk about deployment strategies later, but when starting out you might want to reference it from your local workspace in order to iterate quickly.
Now, simply reference the stylesheet entry point in your main application stylesheet file as you would with any other gem:
@import "mycompany"; // your remaining styles go here
You can share JavaScripts and all other assets that are handled via the Asset pipeline the same way.
To make the gem available for deployment, you basically have these options:
While our asset library does not contain any sensitive information, we still decided not to make it public, simply because it is irrelevant for other developers. That’s why we went with option three and host it in a private repository on GitHub.
Voilá - you can now share your most important assets across multiple Rails applications!
However, most larger teams do not only use Rails and the asset pipeline, but also other technologies such as Node.js with various frontend architectures and frameworks.
For example, although our documentation center is built with nanoc (a static site generator written in Ruby), its JavaScripts and stylesheets are managed via webpack so it first seemed we won’t be able to benefit from having our base assets in a Rails engine.
Luckily, we can make the Rails engine also available as an npm module to make it consumable via webpack:
First, add a package.json to the root of the Rails engine in order to declare the gem as an npm module:
{ "name": "mycompany-ui", "version": "1.0.0", "description": "My Company UI & Styles", "main": "index.js", "private": true, "scripts": {}, "repository": { "type": "git", "url": "git+https://github.com/mycompany/mycompany-ui.git" }, "author": "Manuel Boy", "license": "ISC", "bugs": { "url": "https://github.com/mycompany/mycompany-ui/issues" }, "homepage": "https://github.com/mycompany/mycompany-ui#readme", "dependencies": {} }
The Rails engine that contains your base assets, is now also installable via npm (respectively yarn).
To add the Rails engine (which is now also an NPM module) to your application, simply add it to the package.json of your project:
{ "name": "mycompany-some-project", ... "dependencies": { "phraseapp-ui": "file:/path/to/mycompany-ui" } }
And run:
$ npm install
Again, we found it useful to start with local file references, since your new asset library is likely to grow.
You can now simply reference the assets from the Rails engine slash npm module like this:
@import "~mycompany-ui/lib/assets/stylesheets/mycompany/_colors"; @import "~mycompany-ui/lib/assets/stylesheets/mycompany/_reset"; @import "~mycompany-ui/lib/assets/stylesheets/mycompany/_typo"; // etc.
Just like the Ruby gem, you must make the module accessible in order to deploy your application. While you can use private modules via npm registry, we found it sufficient to reference it directly from GitHub:
{ "dependencies": { ... "phraseapp-ui": "git+https://github.com/phrase/phraseapp-ui.git", ... } }
Once you have started sharing assets between projects, you can start refactoring some frontend code like your stylesheets and move base resources like colours, typography declarations and many more to the central asset library. You will find it deliberating to remove duplication between different projects.
Whenever you need to change things like a font or your colour palette, you simply need to update it in your new central asset library, re-deploy every app and you’re done. Having this library will also improve the overall quality of your stylesheets since you are now forced to think twice about which resources need to go into the core library and which are just project-specific.
We found this way of sharing assets across applications a great way to reuse frontend code and ensure consistent looks when working with separate projects. But although it is fairly easy to set up, don’t fool yourself: In a large application landscape, finding and extracting the right code and restructuring it properly, takes time. On the other hand: if you want to stay productive in an ever-growing code base, steps like these are inevitable.
How do you structure your assets and frontend code? We’re eager to learn about your experiences and strategies. And if you’re interested in working with us: we’re hiring.
Last updated on October 27, 2022.