Change: Drop Rails FE and use only Vue with SSR for FE Rendering
Change pattern proposal: Using both Rails and Vue for FE Rendering to only Vue with SSR
Old Pattern
Currently we have frontend code distributed between Rails haml
files and Vue asset files. Many newer Frontends are Vue apps that are rendered client side only.
New Pattern
This RFC proposes to introduce two refactors:
- Move GitLab's Frontend entirely to Vue
- Introduce a Server-Side-Rendering (SSR) Framework (suggesting nuxt.js, but open to alternatives)
Advantages of switching patterns
There are multiple strong reasons supporting this effort.
1. Performance and Responsiveness
Implementing this proposal would be the single biggest step to achieve a better site performance and –responsiveness. See below for reasons why.
1.1 Better performance for FE Hydration
Currently, Frontends written in Vue are not server-rendered. The Vue app's DOM is rendered on the client's device after downloading the page, that is served by Rails. While historically grown to be this way, it's the most inefficient way to render a page, especially for pages where Vue is responsible for all meaningful content: We use Rails to render an (effectively) empty page, have the client download that empty page and then have a second render step for the same page using the clients resources to build the actual DOM. Wherever you're positioned on the axis "server-rendered static HTML" vs "client-only SPA" — This is the worst of both worlds!
This proposal would allow us to skip Rails having to generate a DOM that isn't being used anyway.
1.2 Rendering on Edge
Utilising a Javascript Framework to generate HTML server-side allows us to perform that rendering on Cloudflare Workers (without the need to compile to wasm). This allows the rendering to happen on edge, as close to the client as possible. So even un-cached pages would benefit from a very low latency. At the same time it's easy to provide a nodejs build from the same source for self-hosted instances that would feel no different to our current setup. Optionally, a Docker-based deployment could be used to deploy the FE to multiple regions and recreate an architecture similar to an edge network.
1.3 Better App Performance during navigation
Most in-app navigation paths cause a new Server request. Moving to a 100% Vue App would allow:
- atomic DOM redraws
- instant FCP
- using local cache to hydrate the page with data that has previously been fetched, saving tons of api requests
A performance like this is what users are familiar with by using newer applications and likely expect from GitLab as well. I think this is an crucial step towards making our user experience more lovable.
2. Reduce Developer complexity
This proposal would reduce the need for GitLab FE contributors having to work in two unrelated languages. Components and Abstractions currently have to be maintained in both Rails and Vue. The constant context switching puts an enormous strain on engineers. This is especially true for community contributors.
2.1 Working in two languages
FE developers have to be familiar with and work with two unrelated languages at the same time. This isn't a huge deal per se, but it does effectively mean that every dev will end up with one language in which they're more effective than the other, while regularly having to switch to the one they're less comfortable with. This means that learned development patterns can't easily be re-used, MR reviews aren't as effective because a Vue-focused reviewer might miss bad patterns in a Rails MR, etc.
2.2 Two test regimes
The same goes for two different test regimes. Currently the FE is tested with either rspec
or jest
. Test patterns can't easily be transferred from one to the other. Both FE test frameworks need to be maintained, both frameworks need up-to-date helpers. This causes twice the effort for something that should be unique.
2.3 Searchability / SSOT
There currently is no clear guidance as to where to find components. They could be part of the Rails app. They could be a Vue app. This makes components and pages difficult to find. Again, this makes it especially hard for community contributors to onboard.
3. Simplify Component sharing
Currently, components and abstractions have to exist both in Rails and in Vue, or they'e only available to one of realms. It'd difficult and hacky to share components between those realms. The architecture follows different philosophies. Switching to a Vue-only frontend would allow for a stronger and more flexible design system that takes full advantage of reactivity and transitions.
4. Reduce the number of unique Vue app instances
This proposal would ultimately reduce the number of unique Vue apps on a page to one. Currently we have up to 30 individual Vue app instances on a single page (exactly 30 on the MR page). Reducing them would not only make it significantly easier to debug issues, but also allowing to easier share state between the involved components.
5. Dogfood the Jamstack
With many frameworks like next.js, Nuxt, SvelteKit and Remix gaining in popularity, many recently developed applications are following the proposed architectural pattern. Following the same route would help us understand the problems developers are facing and improving our own product to support those usecases, especially with regards to large enterprise apps - a market that is currently underserved as opposed to startups.
Going SSR would allow us to dogfood Jamstack features developed by the Jamstack Incubation SEG: Support for Server-Side-Rendering could be validated using our own application and strengthened for the most complex usecase.
Disadvantages of switching patterns
-
If Backend Engineers have to make a frontend change, they will have to do so an unfamiliar language. Two counter points:
- currently the inverse is the case: FE engineers have to use
haml
and understand the Rails structure even when working in their own domain. - currently there is no guarantee that BE engineers don't have to touch Vue code anyway. If the feature they are working on happens to already have a Vue frontend, they will have to work on that.
- currently the inverse is the case: FE engineers have to use
-
By using a SSR Engine like nuxt.js, we'd be adding one more process / port to GitLab Omnibus, adding an attack vector.
-
The need to create APIs to communicate between Rails and Vue requires more communication within the team (especially as we mostly have separate BE and FE engineers)
-
APIs need to be maintained properly as they are publicly available
-
It's a technology overhead.
What is the impact on our existing codebase?
-
This proposal suggests to first make a requirement that all new FE pages are written in Vue, similar to how we require new APIs to be GraphQL first.
-
Subsequently, all existing
.html.haml
files would eventually have to be refactored to Vue. -
The third step is then to introduce a SSR Framework on top of Vue. In comparison to the other efforts, I believe this to be the simplest task. Nuxt.js can be wrapped around an existing Vue codebase. Major areas of change would be cases where
window
objects are used as well as the folder structure.
Reference implementation
Work in Progress, contributions welcome