The best way I have found so far is to use Docker containers with a docker file that does the installation of node_modules before running other steps.
I make sure all jobs of this multi branch pipeline run on the same node and keep the latest docker image for EACH branch on this node locally. That way unless the dependencies in packages.json change, then docker will use the cache to build the new image (or just generate the artifact you want to create and transfer it to the local workspace). If all branches have the same dependencies, they will all use the same cached image, if not they will just create a new one.
Example:
## CHOSE YOUR LOCAL BASE IMAGE
FROM debian:10.0
### ADD YOUR DEPENDENCIES
ADD packages.json build-deps.sh
### INSTALL DEPENDENCIES (we use a custom script)
RUN build-deps.sh
### ADD THE REST OF YOUR CODE
### This will break the cache assuming your code changes each time,
### but previous docker build commands will be cached
### (if your dependencies didn't change)
ADD my-code.tar.gz .
### RUN YOUR COMMANDS
RUN run-your-scripts.sh
After building you image with docker build, you can then do soemthing like this to extract the artifact
docker run --name SOME-NAME YOUR-REPO:YOUR-TAG
sudo docker cp SOME-NAME:/path/to/artifact/artifact.tar.gz ${WORKSPACE}
I hope this helps