From ddef0916de13949e800a63fa3490a73e98996fa2 Mon Sep 17 00:00:00 2001 From: Owen Jacobson Date: Wed, 11 Jun 2025 23:29:30 -0400 Subject: Use `npm ci` for automated package installation. From its documentation: > This command is similar to `npm install`, except it's meant to be used in automated environments such as test platforms, continuous integration, and deployment -- or any situation where you want to make sure you're doing a clean install of your dependencies. We don't need a clean install, necessarily - just a complete one that matches the package configuration. However, this command is clearly documented as being used for automated environments, and I think integration with another build tool is close enough to that intention to fit. It also promises not to rewrite `package.json` or `package-lock.json`. (`npm install`, on the other hand, rewrites `package-lock.json` regularly.) As we do not intend to change the source tree when building it, this is the preferred behaviour. Finally, this fixes a behaviour I encountered where certain `cargo` commands - sometimes including `cargo build` - could completely reformat `package-lock.json` without any warning and without any user-visible rationale for it. --- build.rs | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) (limited to 'build.rs') diff --git a/build.rs b/build.rs index 6d4805f..94531ab 100644 --- a/build.rs +++ b/build.rs @@ -4,19 +4,30 @@ fn main() -> Result<(), io::Error> { // trigger recompilation when a new migration is added println!("cargo::rerun-if-changed=migrations"); - // rerun npm install whenever packages or npm config are changed + // The following sections are intended to allow developers and packagers to create a working + // `pilcrow` binary in one step in a clean source tree, using Cargo, even though Pilcrow is + // written in two-and-a-half languages. + // + // The final binary embeds the Svelte UI. These steps build it. And, in service of that one-step + // build idea, they also install the NPM dependencies needed to carry out that build. (Cargo + // does this out of the box for Rust dependencies.) + + // rerun npm ci whenever packages or npm config are changed println!("cargo::rerun-if-changed=.npmrc"); println!("cargo::rerun-if-changed=package.json"); - // `node_modules` and `package-lock.json` are always touched if `npm install` - // runs, leading to spurious rebuilds. + println!("cargo::rerun-if-changed=package-lock.json"); + // In theory, we should rerun `npm ci` if `node_modules` has changed since the last build, to + // put it back into a known-good state. However, `npm ci` itself _always_ rewrites + // `node_modules`, so asking Cargo to rerun this build script if `node_modules` changes leads to + // Cargo always rerunning this build script. So, as a compromise, we assume that changes to + // `package-lock.json` or `package.json` are sufficient justification to rerun `npm ci`, because + // those are the most likely secondary indicators of changes to the installed packages. // - // See: - // println!("cargo::rerun-if-changed=package-lock.json"); // println!("cargo::rerun-if-changed=node_modules"); - let status = Command::new("npm").args(["install"]).status()?; + let status = Command::new("npm").args(["ci"]).status()?; if !status.success() { return Err(io::Error::other(format!( - "'npm install' exited with status {status:?}" + "'npm ci' exited with status {status:?}" ))); } -- cgit v1.2.3