Skip to content

refactor(build): remove micro-utility dependencies - #7095

Open
43081j wants to merge 7 commits into
netlify:mainfrom
43081j:jg/the-purge-0
Open

refactor(build): remove micro-utility dependencies#7095
43081j wants to merge 7 commits into
netlify:mainfrom
43081j:jg/the-purge-0

Conversation

@43081j

@43081j 43081j commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

This removes 9 dependencies as follows:

  • ansi-escapes was only used for ANSI links, which we can inline instead
  • clean-stack was mostly made redundant by the fact we already do our own filtering beforehand. If we inline the only
    remaining case (node internals), it becomes one extra small RegExp
  • filter-obj can be achieved by a filtered Object.entries
  • is-plain-obj can be inlined as our own util
  • p-event can be replaced with once (from node:events)
  • p-filter was never used with a concurrency limit, so can be replaced by a regular map of async tasks
  • p-locate was never used with a concurrency limit, so can be replaced by a regular for...of
  • p-map can be replaced by a basic pool of for...of on a shared iterator
  • path-exists can be replaced by fs.access

Reasons:

  • Reducing the supply chain footprint is good for security
  • In most cases, we use a fraction of the provided functionality, so are wastefully pulling in a larger dependency than
    needed
  • If we keep doing this, size of the build package will reduce over time (baby steps but still progress)

@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Summary by CodeRabbit

  • Bug Fixes
    • Improved build filtering for CLI flags, environment changes, dry runs, and plugin compatibility.
    • Enhanced stack trace cleanup, terminal hyperlinks, and error redaction.
  • Chores
    • Consolidated filesystem and object validation checks for more consistent build behavior.
    • Improved asynchronous processing for plugin communication and blob uploads.
  • Tests
    • Updated filesystem checks across build scenarios and added coverage for development blob uploads.

Walkthrough

Adds local isPlainObject and pathExists helpers, replaces external utilities with native implementations, updates asynchronous control flow and stack cleaning, removes package dependencies, and switches tests and fixtures to synchronous filesystem checks.

Estimated code review effort: 4 (Complex) | ~60 minutes

Suggested labels: Adds or modifies js files

Suggested reviewers: pieh

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: removing micro-utility dependencies from the build package.
Description check ✅ Passed The description explains the dependency removals, replacement approaches, and motivations, but does not include the template checklist or issue reference.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@43081j
43081j marked this pull request as ready for review June 25, 2026 13:20
@43081j
43081j requested a review from a team as a code owner June 25, 2026 13:20

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/build/src/utils/blobs.ts (1)

139-147: 🩺 Stability & Availability | 🟡 Minor

Update the return type annotation for data to remove the ArrayBuffer generic constraint.

The function returns Buffer<ArrayBuffer>, but readFile returns Buffer which is typed as Buffer<ArrayBufferLike> in @types/node v22+. Since ArrayBufferLike is a wider union (including SharedArrayBuffer) and TypeScript generic parameters are invariant, Buffer<ArrayBufferLike> is not assignable to the narrower Buffer<ArrayBuffer>.

Update the return type to just Buffer to allow the inferred type from readFile.

Current code ```typescript ): Promise<{ data: Buffer; metadata: Record }> => { ```

Change to:

): Promise<{ data: Buffer; metadata: Record<string, string> }> => {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/build/src/utils/blobs.ts` around lines 139 - 147, The return type on
the blob-reading helper is too narrow because it declares data as
Buffer<ArrayBuffer>, which conflicts with the type returned by readFile in
modern `@types/node`. Update the Promise return annotation in the blob utility
function that reads contentPath and metadataPath so data is just Buffer, keeping
metadata unchanged, and let the inferred type from readFile flow through without
the ArrayBuffer generic constraint.
🧹 Nitpick comments (1)
packages/build/src/plugins/child/diff.js (1)

5-6: 🎯 Functional Correctness | 🔵 Trivial

isPlainObject semantics diverge from is-plain-obj but are safe for this context

The internal helper omits Symbol.toStringTag and Symbol.iterator checks found in is-plain-obj v4. This is acceptable: netlifyConfig is derived from JSON/YAML (which lack symbols), and the validation paths handle standard POJOs. The simplified logic reduces dependencies without impacting correctness for these inputs.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/build/src/plugins/child/diff.js` around lines 5 - 6, The concern is
the simplified isPlainObject behavior differs from is-plain-obj, but this path
is safe because diff.js only validates netlifyConfig coming from JSON/YAML
inputs. Keep using the internal isPlainObject helper in the child diff plugin
and do not replace it with the external package; ensure the validation logic
continues to rely on standard POJO checks only, since the existing netlifyConfig
handling already covers the intended inputs.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/build/src/plugins_core/blobs_upload/index.ts`:
- Around line 60-67: The shared-iterator worker loop in blobs_upload/index.ts
keeps pulling items from queue even after one upload fails, because Promise.all
rejects but the other async workers continue running. Update the worker logic
around the queue consumption and blobStore.set path so that the first caught
error flips a shared failure flag and prevents any further iterations from
reading new entries; reference the Promise.all worker block and the queue
iterator to gate new pulls once an error is seen.

In `@packages/build/src/plugins_core/dev_blobs_upload/index.ts`:
- Around line 63-73: The dev blob upload worker pool can keep processing after
one worker fails, because the shared queue iterator in dev_blobs_upload/index.ts
is still consumed by other async workers spawned in the Promise.all block.
Update the worker loop around the queue iteration in the upload routine to use a
shared stop flag that is set on first rejection, and check it before pulling the
next item from the queue so no further blobs are uploaded after a failure. Use
the existing worker-pool logic in this block (the queue, Promise.all, and the
per-item upload loop) as the place to add the early-exit behavior.

In `@packages/build/src/plugins/ipc.js`:
- Around line 53-58: Add an error listener to getEventFromChild so child_process
errors are handled alongside message and exit. Update the cleanup logic and
event wiring in getEventFromChild to register an error handler that rejects or
otherwise settles the promise, and make sure it is removed in cleanup with the
existing onMessage and onExit listeners.

---

Outside diff comments:
In `@packages/build/src/utils/blobs.ts`:
- Around line 139-147: The return type on the blob-reading helper is too narrow
because it declares data as Buffer<ArrayBuffer>, which conflicts with the type
returned by readFile in modern `@types/node`. Update the Promise return annotation
in the blob utility function that reads contentPath and metadataPath so data is
just Buffer, keeping metadata unchanged, and let the inferred type from readFile
flow through without the ArrayBuffer generic constraint.

---

Nitpick comments:
In `@packages/build/src/plugins/child/diff.js`:
- Around line 5-6: The concern is the simplified isPlainObject behavior differs
from is-plain-obj, but this path is safe because diff.js only validates
netlifyConfig coming from JSON/YAML inputs. Keep using the internal
isPlainObject helper in the child diff plugin and do not replace it with the
external package; ensure the validation logic continues to rely on standard POJO
checks only, since the existing netlifyConfig handling already covers the
intended inputs.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c42c6848-b4b7-49b6-83fd-d2f9dedf84d5

📥 Commits

Reviewing files that changed from the base of the PR and between 96b864c and 5741b2c.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (46)
  • eslint_temporary_suppressions.js
  • packages/build/package.json
  • packages/build/src/core/bin.js
  • packages/build/src/core/constants.ts
  • packages/build/src/core/dry.js
  • packages/build/src/core/missing_side_file.js
  • packages/build/src/env/changes.js
  • packages/build/src/env/main.ts
  • packages/build/src/env/metadata.js
  • packages/build/src/error/api.js
  • packages/build/src/error/handle.ts
  • packages/build/src/error/parse/clean_stack.js
  • packages/build/src/install/main.js
  • packages/build/src/install/missing.js
  • packages/build/src/log/messages/core.ts
  • packages/build/src/log/messages/mutations.js
  • packages/build/src/plugins/child/diff.js
  • packages/build/src/plugins/child/load.ts
  • packages/build/src/plugins/child/status.ts
  • packages/build/src/plugins/compatibility.ts
  • packages/build/src/plugins/ipc.js
  • packages/build/src/plugins/list.ts
  • packages/build/src/plugins/manifest/validate.js
  • packages/build/src/plugins_core/blobs_upload/index.ts
  • packages/build/src/plugins_core/db_setup/migrations.ts
  • packages/build/src/plugins_core/db_setup/utils.ts
  • packages/build/src/plugins_core/deploy/buildbot_client.ts
  • packages/build/src/plugins_core/dev_blobs_upload/index.ts
  • packages/build/src/plugins_core/edge_functions/index.ts
  • packages/build/src/plugins_core/frameworks_api/util.ts
  • packages/build/src/plugins_core/functions/index.ts
  • packages/build/src/plugins_core/functions_install/index.js
  • packages/build/src/steps/update_config.js
  • packages/build/src/utils/blobs.ts
  • packages/build/src/utils/is_plain_object.ts
  • packages/build/src/utils/omit.ts
  • packages/build/src/utils/path_exists.ts
  • packages/build/src/utils/remove_falsy.ts
  • packages/build/tests/constants/fixtures/functions_src_missing/plugin.js
  • packages/build/tests/constants/fixtures/publish_missing/plugin.js
  • packages/build/tests/core/tests.js
  • packages/build/tests/edge_functions/fixtures/src_missing/plugin.js
  • packages/build/tests/edge_functions/tests.js
  • packages/build/tests/functions/tests.js
  • packages/build/tests/install/tests.js
  • packages/build/tests/mutate_save/tests.js
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • netlify/blueprints (manual)
💤 Files with no reviewable changes (1)
  • packages/build/package.json

Comment thread packages/build/src/plugins_core/blobs_upload/index.ts
Comment thread packages/build/src/plugins_core/dev_blobs_upload/index.ts
Comment thread packages/build/src/plugins/ipc.js
This removes 8 dependencies as follows:

- `ansi-escapes` was only used for ANSI links, which we can inline instead
- `clean-stack` was mostly made redundant by the fact we already do our own filtering beforehand. If we inline the only
  remaining case (node internals), it becomes one extra small RegExp
- `filter-obj` can be achieved by a filtered `Object.entries`
- `is-plain-obj` can be inlined as our own util
- `p-event` can be replaced with `once` (from `node:events`)
- `p-filter` was never used with a concurrency limit, so can be replaced by a regular `map` of async tasks
- `p-locate` was never used with a concurrency limit, so can be replaced by a regular `for...of`
- `p-map` can be replaced by a basic pool of `for...of` on a shared iterator

Reasons:

- Reducing the supply chain footprint is good for security
- In most cases, we use a fraction of the provided functionality, so are wastefully pulling in a larger dependency than
  needed
- If we keep doing this, size of the build package will reduce over time (baby steps but still progress)
@github-actions

Copy link
Copy Markdown
Contributor

e18e dependency analysis

No dependency warnings found.

@pkg-pr-new

pkg-pr-new Bot commented Jul 22, 2026

Copy link
Copy Markdown

Open in StackBlitz

@netlify/build

npm i https://pkg.pr.new/@netlify/build@7095

@netlify/build-info

npm i https://pkg.pr.new/@netlify/build-info@7095

@netlify/cache-utils

npm i https://pkg.pr.new/@netlify/cache-utils@7095

@netlify/config

npm i https://pkg.pr.new/@netlify/config@7095

@netlify/edge-bundler

npm i https://pkg.pr.new/@netlify/edge-bundler@7095

@netlify/functions-utils

npm i https://pkg.pr.new/@netlify/functions-utils@7095

@netlify/git-utils

npm i https://pkg.pr.new/@netlify/git-utils@7095

@netlify/headers-parser

npm i https://pkg.pr.new/@netlify/headers-parser@7095

@netlify/api

npm i https://pkg.pr.new/@netlify/api@7095

@netlify/nock-udp

npm i https://pkg.pr.new/@netlify/nock-udp@7095

@netlify/opentelemetry-sdk-setup

npm i https://pkg.pr.new/@netlify/opentelemetry-sdk-setup@7095

@netlify/opentelemetry-utils

npm i https://pkg.pr.new/@netlify/opentelemetry-utils@7095

@netlify/redirect-parser

npm i https://pkg.pr.new/@netlify/redirect-parser@7095

@netlify/run-utils

npm i https://pkg.pr.new/@netlify/run-utils@7095

@netlify/zip-it-and-ship-it

npm i https://pkg.pr.new/@netlify/zip-it-and-ship-it@7095

commit: 1d82c39

Comment thread packages/build/src/plugins_core/dev_blobs_upload/index.ts Outdated
@serhalp serhalp self-assigned this Aug 2, 2026

@serhalp serhalp left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thank you!

📝 I think this one merits some manual QA

Comment on lines -81 to -104
"ansi-escapes": "^7.0.0",
"ansis": "^4.1.0",
"clean-stack": "^5.0.0",
"execa": "^8.0.0",
"fast-string-width": "^3.0.2",
"fdir": "^6.0.1",
"figures": "^6.0.0",
"filter-obj": "^6.0.0",
"hot-shots": "11.4.0",
"ignore": "^7.0.0",
"indent-string": "^5.0.0",
"is-plain-obj": "^4.0.0",
"keep-func-props": "^6.0.0",
"log-process-errors": "^11.0.0",
"memoize-one": "^6.0.0",
"minimatch": "^10.2.4",
"os-name": "^6.0.0",
"p-event": "^6.0.0",
"p-filter": "^4.0.0",
"p-locate": "^6.0.0",
"p-map": "^7.0.0",
"p-reduce": "^3.0.0",
"package-directory": "^8.0.0",
"path-exists": "^5.0.0",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤩

'@typescript-eslint/no-unsafe-return': 'off',
},
},
{

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file was some gross one-time tech debt in order to get upgraded to eslint 9. We'd like to avoid adding anything to it. Is that possible?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

afaict its actually because of eslint-plugin-import not being able to resolve some things.

in #7044 i remove most of this

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants