Skip to content

fix(webpack): keep binary files intact in the load and transform loaders - #623

Merged
antfu merged 1 commit into
unjs:mainfrom
boluwatifeajayi:fix/webpack-loaders-raw
Oct 26, 2026
Merged

antfu merged 1 commit into
unjs:mainfrom
boluwatifeajayi:fix/webpack-loaders-raw

Conversation

@boluwatifeajayi

@boluwatifeajayi boluwatifeajayi commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #524.

Both webpack loaders (load and transform) were regular loaders. webpack decodes the source as UTF-8 text before it gives it to a non raw loader, so for a binary file the loader got a corrupted string, and when the hook did not handle the file the loader passed that string on. Anything that is not valid UTF-8 (images, fonts) ended up broken, which is what happens in the reproduction with the vue-i18n plugin: its load hook returns nothing for those files, so unplugin handed back the damaged source.

The fix marks both loaders with export const raw = true (see https://webpack.js.org/api/loaders/#raw-loader), so the source arrives as a Buffer and the fallback paths pass the original Buffer on unchanged. webpack converts it back to a string for the next loader if that one is not raw. The one place that needs a string is the transform hook, so the loader decodes the Buffer to UTF-8 before calling the filter and the handler, which is what the hook got before.

I checked this against a real webpack build, not only with unit tests. With a plugin that has a load hook and no filter, a project that imports a PNG as asset/resource emitted a PNG that was different from the source before the change, and a byte for byte identical one after it. I also added unit tests for both loaders (they export raw, binary input is passed on as the same bytes when the hook does not handle it, and the transform handler still gets a string). Three of them fail without the change. The full vitest run and eslint pass.

This does not touch the rspack loaders, which have the same shape (src/rspack/loaders). I did not want to change them without testing them against rspack, I can look at those as a follow up if you want.

Summary by CodeRabbit

  • Bug Fixes

    • Improved webpack asset handling to preserve binary content when it is passed through unchanged.
    • Text transformations now correctly decode buffer-based input before processing.
    • Unchanged or unsuccessful processing returns the original asset data without corruption.
  • Tests

    • Added coverage for binary asset preservation and buffer-based transformation behavior.

Both loaders were regular loaders, so webpack decoded every file they ran
on as UTF-8 text before handing it over. A binary file that the hook did
not handle (an image or a font) was passed on as that decoded string and
came out corrupted. Mark them as raw loaders so the source arrives as a
Buffer and is passed on unchanged, and give the transform hook a string.

Fixes unjs#524
Copilot AI balanced review requested due to automatic review settings October 21, 2026 03:05

Copilot AI 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.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

An organization owner can choose the repository organization as the billing source for reviews requested by members with a paid Copilot license. Learn about Copilot code review billing.

@coderabbitai

coderabbitai Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 8ca10562-b73f-4d0e-9a85-2e009650842e
📥 Commits

Reviewing files that changed from the base of the PR and between bd0f8dd and 4a236cf.

📒 Files selected for processing: 4
  • src/webpack/loaders/load.ts
  • src/webpack/loaders/transform.ts
  • test/unit-tests/webpack/loaders/load.test.ts
  • test/unit-tests/webpack/loaders/transform.test.ts

Included review availability: This review used your included allowance. Your plan provides up to 8 included reviews per hour; 7 remain after this review.

📝 Walkthrough

The webpack load and transform loaders now declare raw input handling and accept Buffer sources. The transform loader decodes Buffer input as UTF-8 for filtering and handler calls. Tests cover binary pass-through and transformed output.

Changes: Webpack binary loader support

Layer / File(s) Summary
Load loader raw input handling
src/webpack/loaders/load.ts, test/unit-tests/webpack/loaders/load.test.ts
The load loader declares raw = true and accepts Buffer sources. Tests check the raw flag and that binary input remains unchanged when the load hook returns null.
Transform loader Buffer processing
src/webpack/loaders/transform.ts, test/unit-tests/webpack/loaders/transform.test.ts
The transform loader declares raw = true and accepts Buffer sources. It decodes Buffer input as UTF-8 for filtering and handler calls. Tests cover unchanged input when the filter does not match and transformed output when it does.

Priority: ➖ Normal

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix · Severity of issue fixed: Medium

Suggested reviewers: sxzz, ysknsid25

Merge Risk: ⚪ Minimal · up to 4a236

The webpack loaders are set up to preserve unhandled binary files, with no identified issue requiring a fix before merge. The published build should receive the usual validation.

Architecture risk: 🔵 Low · up to 4a236

The change affects 2 systems.

Changed systems: src, test

Architecture concerns
No architecture-level concerns identified.

Review details

Systems and components

  • observed — src (service) was modified; 2 changed files map to changed impact.
  • observed — test (service) was modified; 2 changed files map to changed impact.

Before / after behavior

  • observed — Modified behavior in src/webpack/loaders/load.ts: The loader imports the Buffer type, enables webpack’s raw-loader mode via the exported raw flag, and broadens load to accept binary Buffer sources instead of strings only.
  • observed — Modified behavior in src/webpack/loaders/transform.ts: Added the raw-loader declaration and documentation, and expanded transform to accept Buffer sources.
  • observed — Modified behavior in src/webpack/loaders/transform.ts: Introduced UTF-8 decoding for Buffer inputs; the transform filter now evaluates the decoded string.
  • observed — Modified behavior in src/webpack/loaders/transform.ts: The handler now receives decoded code instead of the original source value.
Pre-merge checks: Passed 4 · Failed 1

Failed 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%. Docstring coverage is scoped to functions touched by this diff. Analyzed 2 functions across 4 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly and concisely describes the main change: preserving binary files in the webpack load and transform loaders.
Linked Issues check Passed Issue #524 requires webpack to preserve binary assets when the unplugin hook does not handle them. The PR exports raw = true from both webpack load and transform loaders. The loaders accept `Buf…
Out of Scope Changes check Passed The diff changes only the webpack load and transform loaders and their focused unit tests. These changes directly support issue #524. The PR does not modify the rspack loaders or add unrelated beh…
Full details: Linked Issues check

Explanation

Issue #524 requires webpack to preserve binary assets when the unplugin hook does not handle them. The PR exports raw = true from both webpack load and transform loaders. The loaders accept Buffer input and pass the original source through unchanged on fallback paths. The transform loader decodes a Buffer only before filtering and calling the transform handler. Unit tests cover the raw declarations, byte preservation, and string input to the transform handler.

Full details: Out of Scope Changes check

Explanation

The diff changes only the webpack load and transform loaders and their focused unit tests. These changes directly support issue #524. The PR does not modify the rspack loaders or add unrelated behavior.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Warning

Some tools did not complete. Review the errors below.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

src/webpack/loaders/load.ts

ESLint skipped: missing config or dependency (missing-dependency). The ESLint configuration references a package that is not available in the sandbox.

src/webpack/loaders/transform.ts

ESLint skipped: the matched ESLint configuration already failed (missing-dependency).

test/unit-tests/webpack/loaders/load.test.ts

ESLint skipped: the matched ESLint configuration already failed (missing-dependency).

  • 1 others

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.

@antfu antfu added the low hanging fruit Quick for a maintainer to finish label Oct 26, 2026
@pkg-pr-new

pkg-pr-new Bot commented Oct 26, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/unjs/unplugin@623

commit: 4a236cf

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

Labels

low hanging fruit Quick for a maintainer to finish

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Binary file corruption: unplugin treats binary files as text

3 participants