Hosting AngularDart SPA on GitLab with single repository

alt-text Factory Worker illustrated by elsearts

This is one of the many ways to host AngularDart SPA on the internet, one of the better way (it is free too).

tl;dr Whenever changes are pushed to origin/master, GitLab's CI/CD kicks in, build the production codes and host it in the project's page.

One repository is better than Two

To host an AngularDart application on the internet, one just needs to host all the output files (HTML/CSS/JS), like any static website. The problem is, how should you treat the source (Dart file) and the output (generated files).

Why 2?

Normally, also sanely, I always want my code repository to be clean and lean. Having a folder with only generated files in the source code repository are bad. They provide no information, just hoard more space and clutter your check in history.

So, to host just the output files, I gonna need repository #2. That's how I rolled for awhile, dual repository, one for my working files, another one generated files. But it felt wrong.

Single Repository with Continuos Integration & Deployment is how it should be

Since I am doing a webdev build in my working directory to generate the output files, why not some automated online process do that with my remote git repository, and copy the output file (they called it artifacts) to a place and host them? CI/CD is the exact answer.

This may sound very obvious to many of the web developer. Even I knew this is the correct way of doing thing before I start doing web development on my own, I just didn't know it can be done with quite little effort and experience by myself.

Doing all these with GitLab

Step 1: The project repository

Bring your project into GitLab. Just all the necessary file, ignore the generated file, and don't bother to build it before submission.

Step 2: Setup the CI/CD with .gitlab-ci.yml

Add a new file into your root directory: .gitlab-ci.yml and put these in:

  image: google/dart:latest
  stage: build
  - pub global activate webdev
  - pub get
  - pub global run webdev build -o web:public
    - public
  - master

  image: alpine:latest
  stage: deploy
  - echo 'Nothing to do...'
    - public
  - master

This file defined 2 stages in the CI/CD process. There's a build stage which used google/dart:latest docker and run the build scripts in it. Define the public/ folder as artifacts.

The second stage is the deployment stage. Nothing fancy here, just host everything in the artifacts (which is the public/ folder from the previous step) in the GitLab project's page.

Commit this file and push it to your origin/master.

Step 3: Wait for it

Check out your GitLab project's page, you should see a new pipeline is pending or in progress. If it's pending, the pipeline is waiting for an idle free shared runner. All user get 2k minutes of CI/CD each month. An empty AngularDart sample project took around 3:20 minutes (majority of the time spent in downloading webdev and pub get). Building is fast.

Step 4: Done

Once this pipeline is done, with a green tick, your page is up! If you not sure what's the URL to your project's page. Check them out at Settings > Pages. If this is your first deployment, give it some times for the pages to host correctly on the internet. Grab yourself a drink or flex your shoulder, it's been a long day.

There's a small catch: <base href>

During local development, everyone has used to visit localhost:8080/ for their application. This becomes a problem when you host the application in one of the project's page. Which usually has a form of https://<username><project-name>/, which break all the asset reference. There are 3 ways to fix this.

  1. You add a <base href="<project-name>" /> to your index.html's <head>. This will break your local development build though.
  2. You use a custom domain or convert the project to a User page a.k.a https://<username>
  3. You add these line into index.html's <head>
    // WARNING: DO NOT set the <base href> like this in production!
    // This is to get around a bad base href for GitLab project based pages.
    (function () {
    document.write('<base href="' + document.location.pathname + '" />');

The third method is useful during development and getting up a live website up quickly. e.g. for testing, client review. For production, I would recommend use the second method.


I created a bare minimum project in GitLab. The working site is here. You can clone it and sprinkle your own codes onto it and see your AngularDart web application live in the internet. Maybe one day I will ask GitLab's people to consider making this repo into their GitLab Pages sample code.

With the new cool kid Flutter Web. I suspect it can be host just like this too. I haven't had time to play with that, maybe you should?


Kota Kinabalu, Malaysia
Email me

Usually types codes. A decade in games development, now trying to learn web.