1

I have support for 11 languages in my Angular app and I'm using Angular's built-in internationalization(XLF files). It takes forever to do a release(since it builds the app 11 times!). How can I run the build tasks in parallel(I have a 4-core CPU)?

Wildhammer
  • 2,017
  • 1
  • 27
  • 33
  • You can create a npm script inside your package.json and combine those builds with an ```|``` or the npm-run-all module which should then run all the builds in parallel. Have a look here: https://stackoverflow.com/questions/30950032/how-can-i-run-multiple-npm-scripts-in-parallel. – Erbsenkoenig Jun 05 '19 at 14:51
  • This works but rather not having 11 pipes in one task. Besides for every newly added language, there's gonna be code change, I'm more interested in a devops level solution – Wildhammer Jun 05 '19 at 15:02
  • 1
    It appears what you're asking for is an open [issue 6789](https://github.com/angular/angular-cli/issues/6789) that the Angular team is working on fixing. Apparently they are running into this issue themselves at Google, so hopefully they will produce a solution in the near future. – Narm Jun 05 '19 at 15:03

2 Answers2

3

Since I didn't want to have code change for adding a new language in future(DevOps friendly approach I guess!) I ended up writing a shell script(which DevOps will use):

for arg; do \
    echo "Building for $arg"
    ng build --output-path $PROJECT_ROOT/public/$arg \
         --aot \
         --prod \
         --base-href /$arg/ \
         --i18n-file $LANGUAGE_ASSETS_DIR/i18n/$arg.xlf \
         --i18n-format xlf \
         --i18n-locale $arg & \
done
wait

then added i18n npm task:

"build:i18n": "bash $PROJECT_ROOT/i18n.sh $LANGS",

and:

LANGS= en de fr ...

the ampersand at the end of ng build command is forking new processes which is what making it parallel. I was able to gain a 60 percent build time improvement.

This way all DevOps needs to do for adding support for a new language is to add the translation xlf file to the assets(which is hosted separately in AWS S3 bucket in our case) then update the LANGS environment variable with the new locale(s) and finally trigger the build task(no code change).

EDIT:

Also need to add "wait" command at the end of for loop to wait for all the tasks to finish.

Wildhammer
  • 2,017
  • 1
  • 27
  • 33
0

For documentation: my approach of above in a Jenkins pipeline

def knownLocales = ["en-CH","en-US","en-GB","de-CH","de-DE"]
def ngAotBuildMap = [:]

steps {
    script {
        for (aot_locale in knownLocales) {
            // beware of how Groovy creates closures in loops
            String aotLocaleClosure = "${aot_locale}"

            ngAotBuildMap[aot_locale] = {
                sh """
                    echo "Building locale ${aotLocaleClosure}"
                    cd $WORKSPACE/webclient
                    rm -R -f $WORKSPACE/webclient/dist/${aotLocaleClosure}/
                    ng build --no-progress --configuration=${params.PARAM_SPRING_PROFILE}-${aotLocaleClosure}
                """
            }
        }

        // https://stackoverflow.com/questions/37333796/using-failfast-with-closure-map-breaks-parallel-step/37356318
        ngAotBuildMap.failFast = true
        parallel ngAotBuildMap
    }
}

However: with sequential build, 1 AOT build took 3min 30s, total of about 18min for 5 locales. With above script, 1 AOT build takes 15min 30s, total time is pretty much unchanged. I'm guessing in my case the server resources are already maxed out in sequential build, so parallel build doesn't add much.

Simon
  • 2,994
  • 3
  • 28
  • 37
  • Yeah, it totally depends on your CI/CD instance type and size. We have actually migrated our platform to Kubernetes ever since I wrote this and we now support 18 languages. What I use now is a docker image for building (taking in locale as input, bundle as output) and just spread individual locale build jobs across our machines. With this approach depending on the number of machines you have available in your cluster, the 18 builds can theoretically be as fast as one build. – Wildhammer Feb 19 '20 at 16:42