我在Makefile
:
node_modules: yarn.lock
yarn install --production=false
touch node_modules
yarn.lock: package.json
yarn install --production=false
touch yarn.lock
基本上,如果缺少node_modules
目录(或者有人通过添加/删除文件篡改了它),或者yarn.lock
已更新,那么它应该运行yarn install
来重建/ integrity检查node_modules
目录。
但是,如果缺少yarn.lock
,可以从package.json
重建,或者如果更新package.json
,则应安装并重建锁定文件。
问题是当node_modules
和 yarn.lock
都缺失时,相同的命令会运行两次。
我该如何防止这种情况?
我可以通过将指令包装在条件中来几乎让它工作:
ifneq ("$(wildcard yarn.lock)","")
node_modules: yarn.lock
@yarn install --production=false
touch node_modules
yarn.lock: package.json
touch yarn.lock
else # yarn.lock does not exist
node_modules: yarn.lock
touch node_modules
yarn.lock: package.json
@yarn install --production=false
endif
现在,如果您touch package.json
然后make node_modules
和yarn.lock
存在,那么随后touch yarn.lock
会导致node_modules
重建,就像我一样想。
但是,如果您touch package.json
然后make yarn.lock
,从技术上讲,它应该尝试yarn install
,但不会,因为我从此指令中删除了命令:
yarn.lock: package.json
touch yarn.lock
防止它在前一个场景中运行两次。
答案 0 :(得分:6)
首先,考虑这里所示的方法:
Makefile(1)
.PHONY: all clean
all: yarn.lock
yarn.lock: node_modules package.json
$(MAKE clean)
yarn install --production=false
node_modules:
mkdir -p $@
clean:
rm -fr node_modules yarn.lock
这绝不会冗余地运行yarn install
,而且有些更多
比您考虑的强大解决方案。我会解释一下。
问题中的一个源项是package.json
。它是唯一的
其他一切的逻辑先决条件本身并不构建。
yarn.lock
是一个构建人工制品,其生产意味着这一点
yarn install
已成功完成快照
完成时存在的package.json
。 yarn install
会
随后认为只要yarn.lock
安装是最新的
存在并且具有"同意"按标准package.json
在yarn install
中以算法方式体现。
因此,简单地看一下,这个构建的任务就是使yarn.lock
关于package.json
:
yarn.lock: package.json
yarn install --production=false
但它实际上更复杂。 yarn.lock
是构建目标但是
它不是唯一的构建工艺品,它甚至不是其中一个的人工制品
主要价值。当然,这些都是人工制品的填充物
运行node-modules
后的yarn install
。
因此主要的构建工件显示为此构建的副作用,
而实际目标yarn.lock
仅对我们来说只是作为令牌
无论它们是什么,主要的文物都是最新的
使用package.json
。
这是一个虚弱的标记。机构可以搞乱内容
node_modules
- 添加不应该存在的文件,删除或
修改那些应该 - 而yarn install
不会做任何事情的人
只要 认为yarn.lock
与package.json
保持同步,就可以纠正它,
按照自己的标准。
在解释建议的食谱时,你对这种脆弱性做了广告:
node_modules: yarn.lock
yarn install --production=false
touch node_modules
如果缺少node_modules目录(或者有人篡改过它 添加/删除文件),或已更新yarn.lock,然后它应该运行yarn 安装以重建/完整性检查node_modules目录。
但是 规则是错误的方式被这种篡改触发。该
篡改 - 如果你很幸运 - 将更新node_modules
的修改时间。
但这会使它更年轻,而不是yarn.lock
,并且不会发生火灾
食谱。该配方仅适用于node_modules
不存在的情况。
配方减轻了这种弱点:
yarn.lock: node_modules package.json
$(MAKE) clean
yarn install --production=false
如果yarn.lock
不存在,或者已经过时 node_modules
或者package_json
,我们将从头开始重新制作所有的构建文物。
那更好,但带来了一个引导带问题,当时两者都没有
人工制品yarn.lock
或node_modules
存在,但node_modules
- 就是
被填充为按产品制作yarn.lock
- 也是yarn.lock
的必需。
yarn.lock
的先决条件仅仅是存在
在node_modules
和yarn.lock
之前,node_modules
是令人满意的
node_modules:
mkdir -p $@
的内容,最新 - 只需添加食谱:
node_modules
有了这个,如果yarn.lock
不存在,它将被创建为
yarn.lock
的先决条件,使其比yarn.lock
更新,并且要求
yarn install
以及要制作的主要构建文件。
<强>可是... 强>
这个解决方案表达了基本上正确的依赖关系 - 作为
结果 - 显示node_modules
永远不需要冗余运行。和
它纠正了篡改检测逻辑中错误的错误。
但仍未达到强大篡改检测。
我们获得的篡改检测机制是: yarn.lock
中发生的事情
目录,其修改日期晚于 node_modules
。那
将检测到一些篡改,但不是所有的篡改。
作为文件系统对象,修改目录 - 并更新其修改时间
- 当且仅当添加,删除或重命名直接子对象时。所以
篡改检测机制对任何子目录中的所有事件都是盲目的
node_modules
以及对现有文件或子目录的任何修改
除了重命名之外,node_modules
。这留下了充裕的空间
yarn.lock: package.json
yarn install --production=false
。
从这个角度来看,你可能决定: -
<强>棒强>
脆弱的篡改检测优于无。我不想使用任何一个 比这更贵。
但你可能不会。更可能的替代方案:
<强>折叠强>
篡改检测这种脆弱并不比没有好,所以我会回到:
make clean
我认为不正确的篡改是我构建的超出范围。如果它发生,某些东西会破裂,
我会注意到它, yarn install
然后重试。
提高赌注
我想要强大的篡改检测。
强大的篡改检测使得提升相当重 - 但不会多更重。
您需要强制清除node_modules
,否则取决于结果
node_modules
内容完整清单之间的旧与新比较 -
足够清楚地表明任何重大差异都会显现出来。
详细说明每个文件的路径名和修改时间的清单
make
是最佳人选。此清单将包含RM := rm -fr
MANIFEST_DIR := .manifest
LAST_MANIFEST := $(MANIFEST_DIR)/node_modules.last
NEW_MANIFEST := $(MANIFEST_DIR)/node_modules.peek
GEN_MANIFEST := find node_modules/ -exec stat -c '%n %y' {} \;
$(shell mkdir -p $(MANIFEST_DIR) node_modules)
$(if $(wildcard $(LAST_MANIFEST)),,$(shell touch $(LAST_MANIFEST)))
$(shell $(GEN_MANIFEST) > $(NEW_MANIFEST))
$(shell cmp -s $(LAST_MANIFEST) $(NEW_MANIFEST) || touch node_modules)
.PHONY: all clean
all: $(LAST_MANIFEST)
yarn.lock: node_modules package.json
$(RM) yarn.lock node_modules
yarn install --production=false
$(LAST_MANIFEST): yarn.lock
$(GEN_MANIFEST) > $@
clean:
$(RM) yarn.lock node_modules $(MANIFEST_DIR)
的信息
如果难以捉摸的主要文物,我们需要知道,并且会从文件系统中获取
这个版本可以拼写出来,并且相关的信息会发生变化
它最后记录的状态是重制一切的可靠触发器。因此:
Makefile(2)
node_modules
这主要用无条件执行的设备开发 Makefile(1) 在顶部,其中: -
.manifest
目录开始,即使是空的。node_modules
)开始工作
并坚持.deps
的最新表现。 (类似于
隐藏的find node_modules/ -exec stat -c '%n %y' {} \;
目录,通常用于持久化自动依赖文件
在C / C ++中)。<filename> <modification_time>
,
为node_modules
下的每个项目写node_modules
。
此快照适用于node_modules
,因为它是,但不一定是真的
find -L ...
,因为应该是。 (它应该遵循符号链接吗? - make
?
不会。因为node_modules
不会遵循目标或先决条件的符号链接。)node_modules
。这相当于将更新修改的构建前导码
强篡改检测测试的yarn.lock
时间。然后
构建与以前一样,除了它的目标不再存在
$(LAST_MANIFEST)
,但是新的持久化清单yarn-install
,始终是一个
立即发布 - yarn.lock
快照,因此依赖于
{
"name": "node-js-sample",
"version": "0.2.0",
"description": "A sample Node.js app using Express 4",
"main": "index.js",
"scripts": {
"start": "node index.js"
},
"dependencies": {
"express": "^4.13.3"
},
"engines": {
"node": "4.0.0"
},
"repository": {
"type": "git",
"url": "https://github.com/heroku/node-js-sample"
},
"keywords": [
"node",
"heroku",
"express"
],
"author": "Mark Pundsack",
"contributors": [
"Zeke Sikelianos <zeke@sikelianos.com> (http://zeke.sikelianos.com)"
],
"license": "MIT"
}
。
锻炼Makefile(2)
lab-rat package.json
我将使用:
$ make
rm -fr yarn.lock node_modules
yarn install --production=false
yarn install v0.24.5
info No lockfile found.
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
success Saved lockfile.
Done in 1.17s.
find node_modules/ -exec stat -c '%n %y' {} \; > .manifest/node_modules.last
从头开始
$ make
make: Nothing to be done for 'all'.
不做任何改动并重拍
node_modules
仅触摸$ touch node_modules/
$ make
rm -fr yarn.lock node_modules
yarn install --production=false
yarn install v0.24.5
info No lockfile found.
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
success Saved lockfile.
Done in 1.01s.
find node_modules/ -exec stat -c '%n %y' {} \; > .manifest/node_modules.last
package.json
仅触摸$ touch package.json
imk@imk-ThinkPad-T420:~/develop/so/make_prob$ make
rm -fr yarn.lock node_modules
yarn install --production=false
yarn install v0.24.5
info No lockfile found.
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
success Saved lockfile.
Done in 1.22s.
find node_modules/ -exec stat -c '%n %y' {} \; > .manifest/node_modules.last
node_modules
触摸package.json
和$ touch package.json node_modules/
imk@imk-ThinkPad-T420:~/develop/so/make_prob$ make
rm -fr yarn.lock node_modules
yarn install --production=false
yarn install v0.24.5
info No lockfile found.
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
success Saved lockfile.
Done in 1.05s.
find node_modules/ -exec stat -c '%n %y' {} \; > .manifest/node_modules.last
yarn.lock
触摸$ touch yarn.lock
$ make
find node_modules/ -exec stat -c '%n %y' {} \; > .manifest/node_modules.last
yarn.lock
删除$ rm yarn.lock
$ make
rm -fr yarn.lock node_modules
yarn install --production=false
yarn install v0.24.5
info No lockfile found.
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
success Saved lockfile.
Done in 1.17s.
find node_modules/ -exec stat -c '%n %y' {} \; > .manifest/node_modules.last
package.json
更改$ sed -i 's/4\.13\.3/4.15.3/' package.json
$ make
rm -fr yarn.lock node_modules
yarn install --production=false
yarn install v0.24.5
info No lockfile found.
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
success Saved lockfile.
Done in 1.03s.
find node_modules/ -exec stat -c '%n %y' {} \; > .manifest/node_modules.last
$ sed -i 's/4\.15\.3/4.15.3/' package.json
$ make
rm -fr yarn.lock node_modules
yarn install --production=false
yarn install v0.24.5
info No lockfile found.
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
success Saved lockfile.
Done in 2.35s.
find node_modules/ -exec stat -c '%n %y' {} \; > .manifest/node_modules.last
撤消更改
node_modules
触摸$ ls node_modules/vary/
HISTORY.md index.js LICENSE package.json README.md
$ touch node_modules/vary/README.md
$ make
rm -fr yarn.lock node_modules
yarn install --production=false
yarn install v0.24.5
info No lockfile found.
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
success Saved lockfile.
Done in 1.02s.
find node_modules/ -exec stat -c '%n %y' {} \; > .manifest/node_modules.last
node_modules
将文件添加到$ touch node_modules/vary/interloper
$ make
rm -fr yarn.lock node_modules
yarn install --production=false
yarn install v0.24.5
info No lockfile found.
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
success Saved lockfile.
Done in 1.20s.
find node_modules/ -exec stat -c '%n %y' {} \; > .manifest/node_modules.last
node_modules
从$ rm node_modules/vary/README.md
$ make
rm -fr yarn.lock node_modules
yarn install --production=false
yarn install v0.24.5
info No lockfile found.
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
success Saved lockfile.
Done in 1.16s.
find node_modules/ -exec stat -c '%n %y' {} \; > .manifest/node_modules.last
{{1}}
答案 1 :(得分:0)
借鉴Mike,我认为这足以满足我的需求:
BIN := node_modules/.bin
SRC_FILES := $(shell find src -name '*.js')
DIST_FILES := $(patsubst src/%,dist/%,$(SRC_FILES))
DIST_DIRS := $(sort $(dir $(DIST_FILES)))
# these are not files
.PHONY: all clean nuke
# disable default suffixes
.SUFFIXES:
all: $(DIST_FILES)
dist/%.js: src/%.js yarn.lock .babelrc | $(DIST_DIRS)
$(BIN)/babel $< -o $@
$(DIST_DIRS):
mkdir -p $@
yarn.lock: node_modules package.json
@yarn install --production=false --check-files
@touch -mr $(shell ls -Atd $? | head -1) $@
node_modules:
mkdir -p $@
clean:
rm -rf node_modules dist
nuke: clean
rm -rf yarn.lock
我添加了
@touch -mr $(shell ls -Atd $? | head -1) $@
将yarn.lock
的修改时间更新为较新的node_modules
或package.json
。当触摸这些内容但不会导致锁定文件更改时,这是必要的 - yarn install
无法更新文件,这会导致yarn.lock
永久过时。< / p>
--check-files
会强制yarn install
在node_modules/
内实际重新安装任何丢失的软件包,但它不会进行深度搜索。因此,如果篡改包内的一些文件(而不是仅删除整个包),这种改变就不会被捕获。
巴贝尔的东西只是我如何使用它的一个例子。它将仅重新编译已更改的源文件。现在我只需要在一个刚刚克隆的项目中运行make
,它将使用一个命令使所有内容保持最新。