Skip to content

Support preserving assets input structure in the output#3069

Open
bashmish wants to merge 5 commits into
masterfrom
feat/preserve-assets-input-structure
Open

Support preserving assets input structure in the output#3069
bashmish wants to merge 5 commits into
masterfrom
feat/preserve-assets-input-structure

Conversation

@bashmish
Copy link
Copy Markdown
Member

@bashmish bashmish commented May 8, 2026

What I did

  1. Add option preserveDynamicStructure to @web/rollup-plugin-import-meta-assets to resolve dynamic paths differently by using first asset as a base and preserving the dynamic part in the URL
  2. Improve handling of assets in CSS in @web/rollup-plugin-html so that same use-case as in preserveDynamicStructure is also supported (but it doesn't need any extra option since all paths are static and dynamic paths and dynamic runtime were not an issue)
  3. Support transforming of assets found in CSS

so that assetFileNames can preserve input structure of assets and no extra overhead is needed (e.g. no dynamic runtime in JS)

Review pointers:

  • rollup-plugin-import-meta-assets

    • tests for import-meta-assets were all refactored, so a bit hard to see what's new, you can see it in the diff if you check what "it" lines remained unchanged and what have new names, those will be new and also everything under describe('preserveDynamicStructure', () => { is new
    • the algorithm is based on the idea that file paths can be calculated in runtime relative to the first found asset (which is calculated by rollup's own internal algorithm), that made it easier to make it work for preserveDynamicStructure
    • I could solve preserveDynamicStructure use-case without the option, but the idea was that we don't want the dynamic runtime with path maps, so the main reason to introduce this option is to prevent that runtime from being generated
  • rollup-plugin-html

    • new tests are easy to find since tests structure remained the same, but most important ones to start with are under describe('preserved output paths', () => {
    • I noticed while refactoring that we don't transform assets in CSS which I consider a bug, and since I was changing the mechanism from sync to async (AST visitors were sync and I needed async), I saw opportunity to fix the transformations too since they also impact the hash, and since I made everything async, it wasn't hard for me to implement them correctly too with hashing in mind
    • I use xxhash64, not exactly what rollup uses since I just use a simple HEX representation of it, plus it's hardcoded to use 64bit algo to be future proof (as far as I understand the math behind it), I need to calculate the hash from both the content and output path, the latter is a weak point, because the output path as we know from preserved output paths is not correct at this point and the CSS content still might change, so in theory there is a possibility for bugs here, but in practice it needs to be a super weird assetFileNames configuration that can possibly result in such bug, I wasn't able to create a logical unit test for it (it must be some combination of using hash for CSS file names, but not assets, and then chanign output paths for some assets conditionally in assetFileNames, I can't possible imagine who would ever do that), so decided to stop chasing it

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 8, 2026

🦋 Changeset detected

Latest commit: 9105501

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
@web/rollup-plugin-import-meta-assets Minor
@web/rollup-plugin-html Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@bashmish bashmish marked this pull request as draft May 8, 2026 18:21
@bashmish bashmish requested a review from thepassle May 20, 2026 15:25
@bashmish bashmish marked this pull request as ready for review May 20, 2026 15:35
@bashmish bashmish changed the title Support preserving assets input structure Support preserving assets input structure in the output May 20, 2026
assetInCss.ref = ref;
assetInCss.outputPath = this.getFileName(ref);
if (!extractAssetsLegacyCss) {
assetInCss.hash = create64()
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.

can't we just use node:crypto? it would achieve the same goal right? its not entirely clear to me why we need a dep to create the hash

Copy link
Copy Markdown
Member Author

@bashmish bashmish May 21, 2026

Choose a reason for hiding this comment

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

@thepassle xxhash is super fast, it's used by rollup internally too (although they made their own bindings for Rust functions) and recommended for non-crypto hashes in such use-cases

* @param {string|string[]} [options.exclude] A picomatch pattern, or array of patterns, which specifies the files in the build the plugin should _ignore_. By default no files are ignored.
* @param {boolean} [options.warnOnError] By default, the plugin quits the build process when it encounters an error. If you set this option to true, it will throw a warning instead and leave the code untouched.
* @param {function} [options.transform] A function to transform assets.
* @param {boolean} [options.preserveDynamicStructure] When enabled, emits dynamic assets and rewrites the URL pattern to resolve the original dynamic path relative to the first emitted asset. Requires that the output preserves both filenames (no hashing) and directory structure from the dynamic expression onwards.
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@thepassle do you think preserveDynamicStructure is a suitable name given the behavior and purpose?

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