I've got these two make targets:
NPM_OUT = node_modules/npm.sfv
NPM_BIN = $(shell command -v npm || command -v /usr/bin/npm || echo "npm")
HASH_CMD = $(shell command -v md5 || command -v md5sum)
$(NPM_OUT): npm-shrinkwrap.json
$(NPM_BIN) install --loglevel=error
@$(HASH_CMD) npm-shrinkwrap.json > $(NPM_OUT)
npm-shrinkwrap.json:
$(NPM_BIN) install --loglevel=error
$(NPM_BIN) prune
$(NPM_BIN) dedupe
$(NPM_BIN) shrinkwrap --dev
NPM_OUT is basically a bogus file I use just to determine if npm install has been ran yet. I don't know how to do this without a bogus file because that one command generates many output files, not just one object file like you'd see in c/c++.
The problem I'm having is that if npm-shrinkwrap.json doesn't exist then npm install --loglevel=error gets ran twice.
As you can see, it exists in both targets. If npm-shrinkwrap.json doesn't exist, then I need to run npm install before I can create the shrinkwrap file. But if I do that, then I don't need to run it again for $(NPM_OUT). The reason it's in $(NPM_OUT) is because I need to run it every time npm-shrinkwrap.json changes.
I thought maybe I could create a 3rd target for npm install which the other 2 targets could depend on, but unless I specify a dependency file for that too, then it will always run.
How can I handle this?
Say the npm install is up-to-date is the state of affairs you want to
proxy with the NPM_OUT.
You want the npm install is up-to-date to be dependent on npm-shrinkwrap.json,
if and only if npm-shrinkwrap.json exists. If you manually edit npm-shrinkwrap.json,
for instance, then that means the npm install is no longer up to up-to-date and
must be made so, using npm-shrinkwrap.json.
But if npm-shrinkwrap.json doesn't exist then in fact the dependency is the
other way round, because you need to make the npm install up-to-date in
order to make npm-shrinkwrap.json, ab initio.
So you have different dependencies depending on whether or not npm-shrinkwrap.json
exists:
NPM_BIRTH_CERT = node_modules/.npm_installed.timestamp
NPM_BIN = $(shell command -v npm || command -v /usr/bin/npm || echo "npm")
NPM_SHRINKWRAP := $(wildcard npm-shrinkwrap.json)
.PHONY: all clean really-clean
all: npm-shrinkwrap.json $(NPM_BIRTH_CERT)
$(NPM_BIRTH_CERT): $(NPM_SHRINKWRAP)
$(NPM_BIN) install --loglevel=error
touch $@
ifndef NPM_SHRINKWRAP
npm-shrinkwrap.json: $(NPM_BIRTH_CERT)
$(NPM_BIN) prune
$(NPM_BIN) dedupe
$(NPM_BIN) shrinkwrap --dev
touch $<
endif
clean:
rm -fr node_modules
really-clean: clean
rm -f npm-shrinkwrap.json
Here the rule:
$(NPM_BIRTH_CERT): $(NPM_SHRINKWRAP)
is:
$(NPM_BIRTH_CERT): npm-shrinkwrap.json
if npm-shrinkwrap.json exists and otherwise just:
$(NPM_BIRTH_CERT):
And whenever npm-shrinkwrap.json exists it's not a target at all.
I don't see the need make $(NPM_BIRTH_CERT) resolve to an MD5
hash of the npm-shrinkwrap.json, rather than just a file that
bears the timestamp of npm installs last completion or
npm-shrinkwrap.jsons last generation from an npm install, whichever is latest.
Using the ideas from Mike's answer, I think I can get this to behave the way I want:
NPM_SHRINKWRAP := $(wildcard npm-shrinkwrap.json)
ifdef NPM_SHRINKWRAP
$(NPM_OUT): npm-shrinkwrap.json
$(NPM_BIN) install --loglevel=error
touch $(NPM_OUT)
else
$(NPM_OUT): npm-shrinkwrap.json
endif
npm-shrinkwrap.json: package.json
$(NPM_BIN) install --loglevel=error --no-shrinkwrap
$(NPM_BIN) prune
$(NPM_BIN) dedupe
$(NPM_BIN) shrinkwrap --dev
touch $(NPM_OUT)
Basically, if the shrinkwrap file exists, then make $(NPM_OUT) will run npm install iff the shrinkwrap file has been updated.
If the shrinkwrap file doesn't exist, and since npm-shrinkwrap.json is still a dependency, the npm-shrinkwrap.json target will do the installation instead.
However, I introduced a new problem here: if npm-shrinkwrap.json does exist and package.json (wasn't in original question) has been updated, then the double-install will happen again. I don't know if that can be fixed, or if it's even worth fixing.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With