Skip to content

test(template-compiler): preprocessor cache check passes on partial npm installs #181

Description

@lukekania

Symptom

All 7 of crates/template-compiler/tests/preprocessor_integration.rs's *_style_url_is_compiled / *_preprocesses_* / *_processes_scss_* tests fail with Cannot find module 'sass' (or less / stylus) — but only on machines whose /tmp/ngc-preprocessor-test-cache-v1/node_modules/sass/ exists from a prior run that was interrupted. The package directory is there; its actual contents are not.

Reproducing on a fresh checkout works (the cache gets installed cleanly on first invocation). Reproducing on a machine with a corrupted cache fails every time until the cache is removed by hand.

Root cause

preprocessor_cache() decides the cache is good if each expected package directory exists:

let all_present = [\"sass\", \"less\", \"stylus\"]
    .iter()
    .all(|pkg| node_modules.join(pkg).is_dir());
if all_present {
    return Some(node_modules);
}

An interrupted npm install (Ctrl-C, OS shutdown, network blip, etc.) can leave behind a node_modules/sass/ that only contains an early-installed sub-tree like types/ while the package's real entry point (package.json, dist/, lib/) never got written. The directory check passes, the cache is returned, the symlinked subprocess fails with Cannot find module 'sass'.

Suggested fix

Tighten the cache validity check to require the package's manifest, not just its folder. Something like:

let all_present = [\"sass\", \"less\", \"stylus\"]
    .iter()
    .all(|pkg| node_modules.join(pkg).join(\"package.json\").is_file());

A corrupted cache then falls through to the re-install path instead of poisoning every preprocessor test on the box.

Why this matters

Whoever hits this for the first time will see all eight preprocessor tests fail with a confusing "missing module" diagnostic from a Node subprocess and have no obvious lead — the test logs don't say "installing sass..." (because the cache looks present), and the failures look like they're inherent to the runtime rather than a stale /tmp artifact. Tightening the check makes the cache self-healing.

Repro on a clean cache

rm -rf /tmp/ngc-preprocessor-test-cache-v1
cargo test -p ngc-template-compiler --test preprocessor_integration
# → 8 passed

To synthesise the broken state (then watch all but the diagnostics test fail):

mkdir -p /tmp/ngc-preprocessor-test-cache-v1/node_modules/sass/types
mkdir -p /tmp/ngc-preprocessor-test-cache-v1/node_modules/less
mkdir -p /tmp/ngc-preprocessor-test-cache-v1/node_modules/stylus
cargo test -p ngc-template-compiler --test preprocessor_integration

Notes

  • Not a runtime / compiler bug; purely a test-harness robustness issue.
  • CI on ubuntu-latest runs in a clean container each time and has never hit this.
  • No PR open for it yet — the surface is one cache-validity predicate.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions