Skip to content

feat(css): support CSS import and asset URL externals - #15431

Open
intellild wants to merge 6 commits into
mainfrom
codex/fix-css-external-types
Open

feat(css): support CSS import and asset URL externals#15431
intellild wants to merge 6 commits into
mainfrom
codex/fix-css-external-types

Conversation

@intellild

@intellild intellild commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Summary

  • add asset, asset-url, and css-import to the public ExternalsType options
  • resolve an asset external as asset-url when it is consumed by CSS url(), while keeping JavaScript new URL() behavior as asset
  • rename the internal URL source type from SourceType::CssUrl to SourceType::AssetUrl
  • extend StringEnum with:
    • a newtype fallback that preserves unknown strings
    • serde-style rename_all rules, with snake_case as the default and per-variant rename taking precedence
  • derive the complete SourceType string mappings with rename_all = "kebab-case"
  • preserve external CSS URLs in generated CSS instead of emitting a JavaScript wrapper
  • port webpack's configCases/externals/asset-url coverage

The deprecated webpack css-url alias is intentionally not supported.

Example

module.exports = {
  externalsType: "asset-url",
  externals: {
    "external-image": "https://example.com/image.png"
  }
};

Given:

.logo {
  background: url(external-image);
}

Rspack now keeps the external URL in the emitted CSS. Before this fix, the external was treated as a JavaScript source and could not be generated correctly for the CSS consumer.

The new StringEnum forms keep mappings concise and custom source types round-trippable:

#[string_enum(rename_all = "kebab-case")]
enum SourceType {
  #[string_enum(rename = "javascript")]
  JavaScript,
  AssetUrl,
  #[string_enum(fallback)]
  Custom(Ustr),
}

Unknown strings are converted to Custom(value), and as_str() returns the preserved value.

Validation

  • pnpm run build:binding:dev
  • pnpm run test -t 'externals/asset-url'
  • pnpm run test -t 'custom-url'
  • pnpm run test -t 'css/import'
  • cargo test -p rspack_macros_test
  • cargo clippy -p rspack_macros -p rspack_macros_test -p rspack_core -p rspack_plugin_asset -p rspack_plugin_externals --all-targets -- -D warnings
  • cargo fmt --all -- --check
  • webpack gap tracker: no webpack-only files remain for configCases/css/import and configCases/externals/asset-url

Checklist

  • Tests added or updated
  • Relevant tests pass
  • Deprecated css-url is not exposed

by OpenAI Codex

@intellild intellild changed the title fix(css): support CSS external types feat(css): support CSS external types Sep 2, 2026
@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

📦 Binary Size-limit

Comparing aa4d5ac to fix(devtool): key eval cache by module to keep sourceURL correct (#14866) by pshu

❌ Size increased by 4.00KB from 68.33MB to 68.33MB (⬆️0.01%)

@github-actions

github-actions Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Rsdoctor Bundle Diff Analysis

⚠️ Note: The latest commit (375056caff1c5025eecfe05a6a8bb8f13dcc9bb6) does not have baseline artifacts. Using commit 3d12941ecde864530fcc6887c7a03287c076d264 for baseline comparison instead. If this seems incorrect, please wait a few minutes and try rerunning the workflow.

Found 5 projects in monorepo, 0 projects with changes.

📊 Quick Summary
Project Total Size Gzip Size Change Gzip Change
popular-libs 1.7 MB 523.6 KB 0 0
react-10k 5.3 MB 1.3 MB 0 0
react-1k 799.1 KB 217.5 KB 0 0
react-5k 2.6 MB 662.0 KB 0 0
ui-components 4.9 MB 1.4 MB 0 0

Generated by Rsdoctor GitHub Action

@codspeed-hq

codspeed-hq Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Merging this PR will improve performance by 2.45%

⚡ 1 improved benchmark
✅ 49 untouched benchmarks
⏩ 47 skipped benchmarks1

Performance Changes

Mode Benchmark BASE HEAD Efficiency
Simulation rust@create_module_ids 3.4 ms 3.3 ms +2.45%

Tip

Curious why performance improved? Comment @codspeedbot explain why performance improved on this PR, or directly use the CodSpeed MCP with your agent.


Comparing codex/fix-css-external-types (aa4d5ac) with main (375056c)

Open in CodSpeed

Footnotes

  1. 47 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@intellild

Copy link
Copy Markdown
Contributor Author

@codspeedbot is this regression real ?

@codspeed-hq

codspeed-hq Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

@codspeedbot is this regression real ?

No — this one is a measurement artifact, not a real regression. No code change needed.

What the numbers actually are

rust@create_chunk_hashes (Simulation): base 04133c9 1640.4 µs → head 54074eb 1716.6 µs (+76.2 µs).

Where the +76 µs lives

Comparing the two flamegraphs, every user-code subtree is flat (identical to the tenth of a µs), with identical call counts:

Subtree BASE HEAD
CompilationContentHash hook 763.5 µs 756.4 µs
Chunk::update_hash 426.8 µs 426.7 µs
RspackHasher::write → xxh64 298.2 µs 298.2 µs
get_ordered_chunk_modules_identifier 168.7 µs 168.6 µs
libc memcpy (self) 137.3 µs / 19 calls 137.2 µs / 19 calls
libc memcmp (self) 201.8 µs / 4 calls 201.8 µs / 4 calls

The entire delta is inside mimalloc: the aggregated _mi_malloc_generic subtree goes 6.5 µs → 68.4 µs (+61.9 µs, one call in both runs), because in the head run that single over-aligned allocation took the slow path — _mi_page_abandon (30.3 µs) → _mi_arenas_collect (9.2 µs), both entirely absent in base — plus mi_page_queue_find_free_ex 3.5 → 26.9 µs. Aggregated mi_malloc_aligned 90.6 → 144.0 µs. That is mimalloc's periodic page-abandon/arena-purge happening to land inside the measured window, not work your diff added.

Corroborating evidence

  • Main itself is bimodal on this benchmark. Last 9 main commits: 1629.7 / 1822.5 / 1822.5 / 1822.5 / 1630.2 / 1640.4 / 1654.7 / 1629.4 / 1640.4 µs — an ~11.8% spread with no relevant code change. The head value of 1716.6 µs sits inside that band, and the base at 1640.4 just happened to be on the low rung.
  • The benchmark can't be reached by this PR's code. It measures only compute_chunk_hashes over a synthetic JS-only fixture (create_general_stage_compiler + prepare_large_code_splitting_case), built in setup — no externals, no CSS, no asset modules. Your diff touches crates/rspack_core/src/external_module.rs, crates/rspack_plugin_externals/src/plugin.rs, TS config types and test fixtures; none of that executes in the measured region.
  • The report also flags different runtime environments (EPYC 7763 → 9V74), and this benchmark is on the affected list.

Conclusion: safe to acknowledge the regression on CodSpeed. If you want extra confidence, a re-run of the same head commit will typically land on the other rung of the main band.

Summary
  • Warming up the performance wizard...
  • Investigate rust@create_chunk_hashes regression — Attributed the whole +76 µs to a mimalloc page-abandon/arena-collect landing in the measured window; user subtrees byte-identical. Not a real regression.
  • Handling comment — Comment handling finished successfully

Was this response helpful? React with 👍 or 👎 to help us improve CodSpeedBot.

@intellild intellild changed the title feat(css): support CSS external types fix(css): support CSS import and asset URL externals Sep 2, 2026
@intellild intellild changed the title fix(css): support CSS import and asset URL externals feat(css): support CSS import and asset URL externals Sep 3, 2026
@intellild

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 3, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-03T03:11:03.584571Z aa4d5ac Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 🚀

Reviewed commit: aa4d5ac017

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@intellild
intellild marked this pull request as ready for review September 3, 2026 03:07
@intellild
intellild requested a review from hardfist as a code owner September 3, 2026 03:07
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.

[Feature]: Support externalsType: 'css-import' (and 'css-url') for CSS externals

1 participant