How to properly cache the node_modules directory in GitlabCI?
22 February 2023 | Eric
Below is an example of a proper strategy to cache the node_modules
folder in GitlabCI.
It is vastly inspired by the Gitlab documentation.
It uses the package-lock.json
as the cache key, which allows us to rebuild the cache whenever the file is modified.
Alternatively, you could use the package.json
as the cache key, depending on your specific needs and workflow.
The code below is self-explanatory and contains helpful comments. However, it is important to note it creates the
node_modules
folder including the devDependencies! To avoid this, you can either add the --production
parameter to the npm ci
command or set your NODE_ENV
to production
.
# Global settings that is applied to every job
cache:
# Create a key using the package-lock
- key: &global_cache_node_mods
files:
- package-lock.json
paths:
- node_modules/
# Prevent subsequent jobs from modifying cache
policy: pull
install:
# .pre stage mean it's executed before everything else
stage: .pre
cache:
# Mimic &global_cache_node_mods config but override policy
# to allow this job to update the cache at the end of the job
# and only update if it was a successful job
- key:
files:
- package-lock.json
paths:
- node_modules/
when: on_success
policy: pull-push # update the cache
# store npm cache for all branches (stores download pkg.tar.gz's)
# will not be necessary for any other job because we don't install at every step
- key: ${CI_JOB_NAME}
# must be inside $CI_PROJECT_DIR for gitlab-runner caching (#3)
paths:
- .npm/
when: on_success
policy: pull-push
script:
# Change the cache directory so it's in $CI_PROJECT_DIR instead of ~/.npm
# Make sure you use the --production parameter or set your NODE_ENV to
# `production` if you don't want the devDependencies to be installed
- npm ci --cache .npm --prefer-offline
only:
changes:
- package-lock.json
refs:
- merge_requests
- main
- develop
# Linting our code
lint:
stage: test
script:
- if ! [ -d node_modules ]; then npm ci --cache .npm --prefer-offline; fi
- npm run lint
only:
changes:
- package-lock.json
- src/**/*
- test/**/*
refs:
- merge_requests
- main
- develop
# Example of running test with coverage using Vitest
vitest:
stage: test
script:
- if ! [ -d node_modules ]; then npm ci --cache .npm --prefer-offline; fi
- npm run coverage
artifacts:
name: "coverage-$CI_COMMIT_SHA"
paths:
- coverage
expire_in: 1h
only:
changes:
- package-lock.json
- src/**/*
- test/**/*
refs:
- merge_requests
- main
- develop