How to use JavaScript in GitHub Actions without committing node_modules
I was creating my first GitHub Action (it is now working, which you can check out here). I am familiar with JavaScript, so I chose to create a JavaScript action. According to the official documentation, I need to do one of the following to make my JavaScript code correctly import 3rd-party modules:
- commit the
node_modules
to the repo, or - use @vercel/ncc to bundle everything into a single script.
I think both of these methods are not good practices. Especially, for my case, the way with @vercel/ncc is not feasible because some package uses require
.
The best way to handle this is to make GitHub cache and install all the dependencies for the user every time the action is run. This can be made possible by creating a composite action. Here is a snippet in action.yml
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
runs:
using: composite
steps:
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Get cache key and path
id: lock
run: |
cd $GITHUB_ACTION_PATH
node <<'JAVASCRIPT'
const fs = require('fs');
const os = require('os');
const sha256 = require('crypto').createHash('sha256');
const hash = sha256.update(fs.readFileSync('package-lock.json')).digest('hex');
fs.appendFileSync(process.env.GITHUB_OUTPUT, `key=${os.platform()}-${os.arch()}-grs-modules-${hash}\n`);
JAVASCRIPT
modules=$(pwd)/node_modules
command -v cygpath &> /dev/null && modules=$(cygpath -w $modules)
echo "modules=$modules" >> $GITHUB_OUTPUT
cat $GITHUB_OUTPUT
cd $GITHUB_WORKSPACE
shell: bash
- name: Restore cache
uses: actions/cache/restore@v4
id: cache-restore
with:
path: ${{ steps.lock.outputs.modules }}
key: ${{ steps.lock.outputs.key }}
- name: CI
if: steps.cache-restore.outputs.cache-hit != 'true'
run: |
cd $GITHUB_ACTION_PATH
npm ci
cd $GITHUB_WORKSPACE
shell: bash
- name: Save cache
if: steps.cache-restore.outputs.cache-hit != 'true'
uses: actions/cache/save@v4
with:
path: ${{ steps.lock.outputs.modules }}
key: ${{ steps.lock.outputs.key }}
- name: Run
run: node $GITHUB_ACTION_PATH/index.js
shell: bash
|
I manually use actions/cache
to cache the node_modules
directory although actions/setup-node
has caching functionality. This is because it is not good yet. Also, because github.action_path
ends with /./
, it can cause some problem due to the relative pathing. My workflow here works around those problems.