Tim*_*Sch 9 npm gitlab gitlab-ci npm-install
互联网上充斥着关于 Gitlab 不缓存的抱怨,但在我看来,Gitlab CI 确实缓存正确。问题是,无论如何,npm 似乎都会再次安装所有内容。
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- vendor/
- bootstrap/
- node_modules/
build-dependencies:
image: ...
stage: build
script:
- cp .env.gitlab-testing .env
- composer install --no-progress --no-interaction
- php artisan key:generate
- npm install
- npm run prod
- npm run prod
artifacts:
paths:
- vendor/
- bootstrap/
- node_modules/
- .env
- public/mix-manifest.json
tags:
- docker
Run Code Online (Sandbox Code Playgroud)
这是我的 gitlab-ci.yml 文件(好吧..相关部分)。虽然使用了缓存的 Composer 依赖项,但没有使用 node_modules。出于绝望,我什至将所有内容都添加到缓存和工件中。
cod*_*365 85
GitLab@^15.12 & >13)就像收到的评论一样,在原始答案中使用工件并不理想,但却是最干净、可靠的方法。现在,GitLab 的文档已经围绕使用进行了更新cache,并且还进行了扩展以支持每个作业的多个缓存键(不幸的是最多 4 个),有一种更好的方法来处理node_modules跨管道。
实施的基本原理是基于了解 GitLab 的怪癖及其npm工作原理。这些是基本原理:
NPM 建议在 CI/CD 环境中运行时使用 代替npm ci。npm install仅供参考,这需要存在package-lock.json,它用于确保在 CI 环境中运行时自动更新 0 个包(npm i默认情况下不会每次都创建相同的确定性构建,例如在作业重新运行时)。
npm cinode_modules在重新安装 中列出的所有软件包之前,故意删除整个第一个package-lock.json。因此,最好只将 GitLab 配置为运行npm ci一次,并确保将结果node_modules传递给其他作业。
NPM 有自己的缓存,用于存储~/.npm/离线构建和整体速度。您可以使用该选项指定不同的缓存位置--cache <dir>(您将需要这个)。(@Amityo 答案的变体)
GitLab无法缓存存储库之外的任何目录!这意味着默认缓存目录~/.npm无法被缓存。
GitLab 的全局缓存配置默认应用于每个作业。如果作业不需要全局缓存文件,则需要显式覆盖缓存配置。使用 YAML 锚点,可以复制和修改全局缓存配置。
要运行额外的安装npx或npm run <script>不重新运行安装,您应该node_modules/跨管道缓存文件夹。
GitLab 的期望是用户使用该cache功能来处理依赖项,并且仅用于artifacts动态生成的构建结果。这个答案现在比以前更好地支持了这个愿望。GitLab.com 上有一个限制,即工件应小于最大工件大小或 1GB(压缩后)。并且工件使用您的存储使用配额
needs或指令的使用dependencies将影响上一个作业中的工件是否会在下一个作业中自动下载(或删除)。
GitLab 缓存可以监视文件的哈希值并将其用作密钥,因此缓存可能仅在更新时才会更新package-lock.json。您可以使用package.json,但会使确定性构建无效,因为当次要版本或补丁可用时它不会更新。
如果您有一个单一存储库并且有超过 2 个单独的包,则在作业期间您将达到 4 个缓存条目限制install。您不会有理想的设置,但您可以将一些缓存定义组合在一起。还值得注意的是,GitLabcache.key.files最多支持 2 个文件用于密钥哈希,因此您可能需要使用另一种方法来确定有用的密钥。一种可能的解决方案是使用非文件相关的密钥并缓存node_modules/该密钥下的所有文件夹。这样,该作业只有 2 个缓存条目install,每个后续作业只有 1 个缓存条目。
不幸的是,GitLab 的缓存列表将索引值添加到它使用的缓存键之前(这非常不直观!),这可能会影响您的缓存在作业之间是否匹配。感谢@deanharber 提出这个问题。截至 2023 年 12 月 3 日,此示例已更新以反映作业中的新订单install。全局缓存条目必须位于安装作业的第一个位置,因为全局缓存键实际上是0_[CACHE_KEY_FOR_NODE_MODULES],而 npm 缓存位于第二个位置,因为它的键为1_[CACHE_KEY_FOR_NPM_TARBALLS]。
.pre使用整个存储库中缓存的下载包(tar.gz)运行单个安装作业作为阶段。node_modules/文件夹缓存到以下作业以执行该管道。不允许除安装之外的任何作业上传缓存(减少管道运行时间并防止意外后果)build/给其他作业# .gitlab-ci.yml
stages:
- build
- test
- deploy
# global cache settings for all jobs
# Ensure compatibility with the install job
# goal: the install job loads the cache and
# all other jobs can only use it
cache:
# most npm libraries will only have 1 entry for the base project deps
- &global_cache_node_mods
key:
files:
- package-lock.json
paths:
- node_modules/
policy: pull # prevent subsequent jobs from modifying cache
# # ATTN mono-repo users: with only additional node_modules,
# # add up to 2 additional cache entries.
# # See limitations in #10.
# - key:
# files:
# - core/pkg1/package-lock.json
# paths:
# - core/pkg1/node_modules/
# policy: pull # prevent jobs from modifying cache
install:
image: ...
stage: .pre # always first, no matter if it is listed in stages
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 (#5)
- <<: *global_cache_node_mods
when: on_success
policy: pull-push
# # ATTN Monorepo Users: add additional key entries from
# # the global cache and override the policy as above but
# # realize the limitations (read #10).
# - key:
# files:
# - core/pkg1/package-lock.json
# paths:
# - core/client/node_modules/
# when: on_success
# policy: pull-push
# store npm cache for all branches (stores download pkg.tar.gz's)
# will not be necessary for any other job
- key: ${CI_JOB_NAME}
# must be inside $CI_PROJECT_DIR for gitlab-runner caching (#3)
paths:
- .npm/
when: on_success
policy: pull-push
# before_script:
# - ...
script:
# define cache dir & use it npm!
- npm ci --cache .npm --prefer-offline
# # monorepo users: run secondary install actions
# - npx lerna bootstrap -- --cache .npm/ --prefer-offline
build:
stage: build
# global cache settings are inherited to grab `node_modules`
script:
- npm run build
artifacts:
paths:
- dist/ # where ever your build results are stored
test:
stage: test
# global cache settings are inherited to grab `node_modules`
needs:
# install job is not "needed" unless it creates artifacts
# install job also occurs in the previous stage `.pre` so it
# is implicitly required since `when: on_success` is the default
# for subsequent jobs in subsequent stages
- job: build
artifacts: true # grabs built files
# dependencies: could also be used instead of needs
script:
- npm test
deploy:
stage: deploy
when: on_success # only if previous stages' jobs all succeeded
# override inherited cache settings since node_modules is not needed
cache: {}
needs:
- job: build
artifacts: true # grabs dist/
script:
- npm publish
Run Code Online (Sandbox Code Playgroud)
GitLab 的建议可以在GitLab 文档npm中找到。
GitLab<13.12)到目前为止我看到的所有答案都只给出了一半答案,但实际上并没有完全完成缓存 IMO 的任务。
为了使用 npm 和 GitLab 进行完全缓存,您必须注意以下事项:
参见上面#1
npm cinode_modules在重新安装 中列出的所有软件包之前,故意删除整个第一个package-lock.json。因此,配置 GitLab 来缓存node_modules构建作业之间的目录是没有用的。重点是确保没有准备挂钩或node_modules之前运行的任何其他内容被修改。IMO,这对于 CI 环境来说并不是真正有效,但您无法更改它并维护完全确定性的构建。
参见上面#3-#4
如果您有多个阶段,则每个作业都会下载全局缓存。这可能不是您想要的!
要运行其他npx命令而不重新运行安装,您应该将该node_modules/文件夹作为工件传递给其他作业。
.pre使用整个存储库中缓存的下载包(tar.gz)运行单个安装作业作为阶段。
stages:
- build
- test
- deploy
install:
image: ...
stage: .pre # always first, no matter if it is listed in stages
cache:
key: NPM_DOWNLOAD_CACHE # a single-key-4-all-branches for install jobs
paths:
- .npm/
before_script:
- cp .env.gitlab-testing .env
- composer install --no-progress --no-interaction
- php artisan key:generate
script:
# define cache dir & use it npm!
- npm ci --cache .npm --prefer-offline
artifacts:
paths:
- vendor/
- bootstrap/
- node_modules/
- .env
- public/mix-manifest.json
build:
stage: build
needs:
- job: install
artifacts: true # true by default, grabs `node_modules`
script:
- npm run build
artifacts:
paths:
- dist/ # whereever your build results are stored
test:
stage: test
needs:
- job: install
artifacts: true # grabs node_modules
- job: build
artifacts: true # grabs built files
script:
- npm test
deploy:
stage: deploy
needs:
# does not need node_modules so don't state install as a need
- job: build
artifacts: true # grabs dist/
- job: test # must succeed
artifacts: false # not needed
script:
- npm publish
Run Code Online (Sandbox Code Playgroud)
dim*_*sus 10
实际上它应该可以工作,您的缓存是全局设置的,您的键是指当前分支${CI_COMMIT_REF_SLUG}...
这是我的构建,它似乎在阶段之间缓存 node_modules。
image: node:latest
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- node_modules/
- .next/
stages:
- install
- test
- build
- deploy
install_dependencies:
stage: install
script:
- npm install
test:
stage: test
script:
- npm run test
build:
stage: build
script:
- npm run build
Run Code Online (Sandbox Code Playgroud)
我遇到了同样的问题,对我来说问题出在缓存设置上,默认情况下缓存不保留未版本控制的 git 文件,并且由于我们不在 git 中存储 node_modules,因此根本没有缓存 npm 文件。所以我所要做的就是插入一行“untracked: true”,如下所示
cache:
untracked: true
key: ${CI_COMMIT_REF_SLUG}
paths:
- vendor/
- bootstrap/
- node_modules/
Run Code Online (Sandbox Code Playgroud)
现在 npm 更快了,虽然它仍然需要检查事情是否发生了变化,对我来说这仍然需要几分钟,所以我考虑让一个特定的工作来执行 npm 安装,但它已经加快了很多。
默认缓存路径是~/.npm
设置 npm 缓存目录:
npm config set cache <path> --global
Run Code Online (Sandbox Code Playgroud)
浏览此处获取更多信息