Offline generation of Angular CLI projects with Yarn

There are situations when an ability to generate new Angular CLI projects from the locally installed packages is quite useful, for example:

  • You’re running a live workshop at a conference in a hotel and the students have to install project dependencies multiple times. When 20-30 people are installing Angular dependencies at the same time on a hotel’s connection, it can take three minutes or more.
  • You’re on a long flight and want to try something new with Angular.

In this post, I’ll show you how to generate Angular CLI projects in a disconnected mode.

First of all, I don’t use npm. I use Yarn for two main reasons:

  1. Yarn is faster than npm (including npm 5).
  2.  Yarn creates a file yarn.lock that keeps track of the exact version of packages installed.

For example, if package.json has a dependency “@angular/core”: “^5.0.0”, running yarn install today would include the version of 5.1.0 of this package. If you want to make sure that all devs in your team use this version even after 5.2.0 is available, push yarn.lock in the source control repo, and everyone who pulls the code will get 5.1.0. Reproducible builds are guaranteed. While npm 5 also creates a file package-lock.json, it doesn’t guarantee the same versions for all developers.

To configure Yarn as a default package manager for Angular CLI, run the following command:

ng set --global packageManager=yarn

Now let’s see how to create a local directory (a.k.a yarn offline mirror) with cached packages so Yarn can use it without the need to connect to the Internet.

Perform the following steps before boarding the plane while the Internet connection is still available.

1. Configure a directory for locally cached packages by running this command:

yarn config set yarn-offline-mirror ~/npm-packages-offline-cache

This will create a file .yarnrc in the user’s directory on your computer. In my case (I use MAC OS), this command creates the file .yarnrc with the following content

# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1


lastUpdateCheck 1512857190418
yarn-offline-mirror "/Users/yfain11/npm-packages-offline-cache"

2. Generate a new project with Angular CLI without installing dependencies:

ng new hello-cli --skip-install

3. Copy the file .yarnrc into the newly generated directory hello-cli

4. Change directory to hello-cli:

cd hello-cli

5. Install the project dependencies using Yarn:

yarn install

Important: Make sure that there is no file yarn.lock in hello-cli when you run this command for the first time.

This command not only will install dependencies in the node_modules directory but will also create a directory npm-packages-offline-cache in your user’s directory. This directory will contain about a thousand of compressed package files required for the offline installation. These are gzipped files with extension .tgz. This is your Yarn offline mirror with npm packages.

6. Just in case, clear the existing yarn cache to make sure we’ll be using only the files from the mirror:

yarn cache clean

Now let’s board the plane. Turn off the wi-fi or unplug the network wire. Our aircraft is airborne.

In the hello-cli directory, run the following command:

yarn install --offline

Yarn will install all the dependencies from the offline mirror. Now you can create as many Angular CLI projects as you need without being connected:

1. Generate a new project:

ng new hello-cli2 --skip-install 

2. Copy the file .yarnrc into the hello-cli2 directory

3. Change to the project directory

cd hello-cli2

4. Run the offline installation of the project dependencies

yarn install --offline

Have a safe flight!

P.S. If you’re running a workshop, have a flash drive with the yarn offline miror directory and ask the participants to copy it into their user’s directories. Then they’d just need to run a command to create the .yarnrc file as explained in step 1.

Advertisements

Yarn package manager: yarn.lock

Yesterday, I was running yet another Angular workshop. After explaining how to install dependencies using npm, I show how to use Yarn (see this blog), a faster alternative to npm, and suggest that the students should consider using Yarn.

Before the workshop, I give handouts with several projects to the group and then ask the group to open a particular project, install the dependencies and run the app. Usually, everything goes smoothly, but this time many people started to complain about a runtime error. In this app, I was using themes from Angular Material 2, but the app couldn’t find the file “node_modules/@angular/material/core/theming/prebuilt/indigo-pink.css”.

I was strange. I tested all the projects two days before the class. After checking the content of the node_modules directory on Paul’s computer, I couldn’t find even the directory node_modules/@angular/material/core let alone that CSS file.

Then I asked if everyone gets this error? Everyone except Jim got this error. Jim was using Yarn for installing dependencies while everyone else was using npm. After learning this, I guessed what was the problem.

I’ using Yarn too, and all my projects included the file yarn.lock, which is created after the initial install storing all packages and their versions there were installed for the project. When you do the yarn install next time, it checks if the file yarn.lock is present, it installs exactly packages of those versions that were listed in yarn.lock. This file can be checked into the version control repo used by your team to ensure that everyone would have exactly the same dependencies.

Now let me explain what happened in the classroom. The package.json in that project included the dependency

"@angular/material": "^2.0.0-beta.2"

The file yarn.lock in that project had the following:

"@angular/material@^2.0.0-beta.2":
  version "2.0.0-beta.2"
  resolved "https://registry.yarnpkg.com/@angular/material/-/material-2.0.0-beta.2.tgz#65ee8733990347b7518b7f42113e02e069dc109b"

Hence, when Jim ran his Yarn install, he got Angular Material 2 2.0.0-beta.2, which had the file “node_modules/@angular/material/core/theming/prebuilt/indigo-pink.css”

But last week, a new version (Beta.3) of Angular Material 2 has been released with a breaking change – they rearranged the file structure:

So the students who didn’t use Yarn, got the latest version while my project used “the old” location of that CSS file.

Fixing this issue in the app was an easy task, but I wanted you to appreciate that Yarn gives you predictability in the projects that have multiple dependencies. Some library author introduces a breaking change, and your app gives a runtime error.

After fixing the CSS location in the app, I deleted my yarn.lock file and re-ran the install. The newly created yarn.lock has this fragment:

"@angular/material@^2.0.0-beta.2":
  version "2.0.0-beta.3"
  resolved "https://registry.yarnpkg.com/@angular/material/-/material-2.0.0-beta.3.tgz#ec31dee61d7300ece28fee476852db236ded1e13"

The first line indicates the dependency as it was listed in my package.json, and the second line shows the actual version that has been installed. Now my project is working again… until the next breaking change.