— GitHub Actions — 1 min read
GitHub Actions is great. Adding caching makes it even better. By caching the right resources your workflows will run faster and you'll:
The obvious candidate for caching in a typical NodeJS project is node_modules
. npm install
-ing dependencies can easily cost 1-3 minutes. But by restoring from a cache we can cut this to seconds.
In this tutorial we'll go over how to:
node_modules
npm install
when a cached version is availableGitHub Actions comes with a built-in action for caching: actions/cache@v2
. This action will automatically cache a given file/folder at the end of a successful workflow, and restore the same at the start.
To do this the action requires 2 parameters:
path
: the file/folder to cachekey
: the key to use when (re)storing the cacheOur path
is obviously node_modules
(as this is the folder we want to cache). But our key is slightly more complicated. In our case, we only want to restore our node_modules
from the cache when our dependencies haven't changed. Accordingly, we need to associate our cache with a key that changes with our dependencies, and for this we can use a hash of our package-lock.json
. This way, whenever our lockfile changes, our key will change and our cache will be effectively invalidated.
All together our caching step will look like this:
1- name: Cache Node Modules2 id: node-cache3 uses: actions/cache@v24 with:5 path: node_modules6 key: node-modules-${{ hashFiles('package-lock.json') }}
Caching node_modules
won't save time on its own. For this we'll need to skip npm install
. But we can only do this when we were actually able to restore a copy of node_modules
from the cache.
Luckily, this is simple in GitHub Actions. We can access the outcome of our caching step through steps.{{id}}.outputs.cache-hit
(where {{id}}
is the id given to our caching step). We can then use an if
property to conditionally skip installation where the cache has been hit.
All together, our installation step will look like this.
1- name: Install Dependencies2 if: steps.node-cache.outputs.cache-hit != 'true'3 run: npm install
All together in a simple unit test workflow, the completed workflow should look something like this:
1name: Unit Tests2on: [pull_request]3jobs:4 build:5 runs-on: ubuntu-latest67 steps:8 - uses: actions/checkout@v2910 - name: Setup Node11 uses: actions/setup-node@v112 with:13 node-version: 12.x1415 - name: Cache Node Modules16 id: cache-node-modules17 uses: actions/cache@v218 with:19 path: node_modules20 key: node-modules-${{ hashFiles('package-lock.json') }}2122 - name: Install Dependencies23 if: steps.cache.outputs.cache-hit != 'true'24 run: npm install2526 - name: Run Tests27 run: npm test
GitHub Actions is great. Caching is simple. CACHE EVERYTHING!