The Frontend at GitLab is getting better and better every day. Today we did two big things, and I'd like to share them with you and our big plans for the future.
- If you use the GDK, then make sure you update it! If you have no idea what I am talking about, then just keep reading.
- Please see the documentation for instructions on updating your GDK.
- Please see our troubleshooting guide for any issues when updating your GDK.
- Feel free to report any additional issues you find.
Our big Frontend plan
Vue is awesome. I wrote an article a while ago that showed GitLab's love for Vue. Today's article is a way to show our plan over the long term to make GitLab as fast and performant as possible with Vue and webpack. We want to make GitLab the easiest to develop for Frontend Developers.
One of the lessons I live by is "It's not always about the tools you use, but how you use them." Saying "we chose Vue", does not imply success. This also means that we could be using Angular or React and have just as awesome of a product. Vue is simply the way there.
How do we plan to use Vue over the long run to make GitLab better, faster, easier and more awesome?
The plan below is a work in progress and very ambitious, but I believe that it will result in a much better frontend for development and performance. This document is also a reference to myself of the things we plan to do here at GitLab's Frontend.
A healthier Frontend
When I started at GitLab, our stack was (oversimplifying here) Rails with jQuery. It hasn't changed much big picture wise except for Vue. Smaller picture, we've added many linters, better code coverage, and many other great things.
1. Rewrite only what you need to
We are not rewriting GitLab's frontend entirely in Vue. That would be a very bad idea. It's not a bad idea for everyone, but it's a bad idea for a startup. It would cost a tremendous amount of time and money. The existing jQuery code (although some say is uncool) has been tested and works very well. There is no need to rewrite functionality that works well, unless there is going to be a major gain.
We also aren't writing every new thing in Vue. You do not need to do this either. But, it would be hard to find some part of the UI that would not benefit from even the simplest parts of Vue.
Examples of this are:
The issue page (which shows an individual issue), has a lot of jQuery on it. We won't rewrite now, because it works well. We will rewrite small parts in Vue once we make certain features more real-time. We are currently making the title and description real time.
The current issue page loads all comments at once and adds lots of event listeners to the page. This page could benefit from Vue for performance reasons. We could make the comment section a Vue app and make the comments a component with the emoji picker as components as well, etc. While we're in there, we'll amp up the UX by allowing you to see the comment you linked to immediately without waiting. There are better ways to show massive amounts of comments so we have to potentially rethink that.
The pipelines page rewritten in vue for the arrival of real time updating.
The environments was written in Vue.
There are many other places where we will be using Vue in the future and where we are already using Vue. Too many to list here.
As you can see, we won't just slap Vue on everything.
2. Add in webpack
Rails has this awesome system of grabbing your Ruby libraries and bundling them into your app.
bundle install will install all the stuff you need from your
Gemfile. So why does Frontend have to stick all their libraries in the
npm install and advanced code bundling tools that we can take advantage of.
By introducing webpack into the equation (merged and ready for action!) we gain multiple benefits.
- When code is shared between files, we can make sure we don't load lodash twice, for example. If both files load lodash, we should only load the code for lodash once. Not only will lodash not be included twice, but with tree shaking only the components of lodash that we use will be included rather than the whole library.
- We can add hot module replacement to make our Vue development quicker. This is a development bonus, as our current development takes loads of time to refresh the page while developing GitLab. Spicy!
- SVGs are going to be huge.
- Right now, SVGs live in a specific directory in Rails. We use Rails helpers to pull in SVGs. With webpack we can pull in SVGs one at a time because webpack precompiles assets.
- We won't have to fetch SVGs with an HTTP request.
- We don't have to do tricky HTML hidden elements which is technical debt.
- We don't have to mess around with SVGs in CSS. You cannot change the color of SVGs in CSS.
- Using webpack's CommonsChunkPlugin we split all of our common vendor libraries into their own separate file. Since these change very infrequently, they can stay cached for a much longer period of time.
- With webpack's code splitting feature you can load just the JS you need to boot. Then you do a
System.import(). With this, we can tell webpack to request only exact JS you need. It keeps the size of the file really small. For example if you have
modal.jsfor modals. If someone never uses the modals the code never loads. As soon as someone opens a modal, the JS gets loaded on demand.
- We can now properly manage our global scope. We can now do a
import x from yinstead of having our scripts pollute the global scope and pass classes around on
- We can slim down the our Vue bundles because we can precompile templates and omit the template compiler from our production code. Evan You (the creator of VueJS) explains this in the feature overview for Vue 2.0:
There will be two different builds:
- Standalone build: includes both the compiler and the runtime. ...
- Runtime only build: since it doesn't include the compiler, you need to either pre-compiled templates in a compile step, or manually written render functions.
3. Remove Turbolinks
What does Turbolinks achieve?
With TurboLinks, clicking a link won't navigate to a new page in the default browser
GET request way. Instead, Turbolinks will replace the
The problem we need to solve
When your JS is loaded one time for multiple pages, events become a major problem. If you are using
gem 'jquery-turbolinks' as we are, then the
Any external links do load faster so, we need to be careful about performance.
If you aren't careful, your events will get loaded multiple times and thus fire multiple times. For example, take the following code:
That click event will be loaded on every page and thus fire multiple times every time
.some-element is clicked.
There are a few remedies to this problem. Some are good and some are bad.
Don't create events in
Use the following stinky solution:
$(document) .off('click', '.some-element') .on('click'...
I call this the
die livemethod. Old jQuery code people use to write
die().live()everywhere. That's the old school jQuery
Write an event manager to be a delegate for all added events.
Remove Turbolinks and make sure you load only the code you need on each page.
I am opting for option 4, in order to make our development lives easier and get multiple performance gains.
After we remove Turbolinks we can do something really cool. We can have each page live on its own. Then, certain pages can be their own Vue apps. For example, we can make the file browser its own Vue application. The merge request page can be its own application. The code for the file viewer won't need to be loaded on any other page and the same goes for other pages. This is not anything new, this is just basic web development. This is also not a new paradigm, and we would not be the first.
This is just one small step for GitLab and one giant leap for the frontend team. In the future you will see many new cool things coming from our team. This move was one step in that direction.
Questions, suggestions, ideas? Please leave a comment below or tweet at us @GitLab!