diff --git a/packages/vite/src/node/plugins/asset.ts b/packages/vite/src/node/plugins/asset.ts index 8c02f06d5fe006..c6b3839246c5a6 100644 --- a/packages/vite/src/node/plugins/asset.ts +++ b/packages/vite/src/node/plugins/asset.ts @@ -49,6 +49,7 @@ const assetCache = new WeakMap>() export interface GeneratedAssetMeta { originalFileName: string | undefined isEntry?: boolean + content?: Buffer } export const generatedAssetsMap = new WeakMap< Environment, @@ -421,7 +422,9 @@ async function fileToBuiltUrl( originalFileName, source: content, }) - generatedAssetsMap.get(environment)!.set(referenceId, { originalFileName }) + generatedAssetsMap + .get(environment)! + .set(referenceId, { originalFileName, content }) url = `__VITE_ASSET__${referenceId}__${postfix ? `$_${postfix}__` : ``}` } diff --git a/packages/vite/src/node/server/environments/rolldown.ts b/packages/vite/src/node/server/environments/rolldown.ts index ec8a282df94e69..8be202b0851364 100644 --- a/packages/vite/src/node/server/environments/rolldown.ts +++ b/packages/vite/src/node/server/environments/rolldown.ts @@ -19,6 +19,7 @@ import type { import { CLIENT_ENTRY, VITE_PACKAGE_DIR } from '../../constants' import { injectEnvironmentToHooks } from '../../build' import { cleanUrl } from '../../../shared/utils' +import { generatedAssetsMap } from '../../plugins/asset' const require = createRequire(import.meta.url) @@ -142,6 +143,7 @@ class RolldownEnvironment extends DevEnvironment { outputOptions!: rolldown.OutputOptions lastModules: Record = {} newModules: Record = {} + lastAssets: Record = {} fileModuleIds = new Set() buildPromise?: Promise @@ -232,6 +234,10 @@ class RolldownEnvironment extends DevEnvironment { moduleTypes: { '.css': 'js', }, + // TODO: isolating finalizer doesn't rewrite yet + // experimental: { + // resolveNewUrlToAsset: true, + // }, } this.instance = await rolldown.rolldown(this.inputOptions) @@ -254,6 +260,23 @@ class RolldownEnvironment extends DevEnvironment { // `generate` should work but we use `write` so it's easier to see output and debug this.result = await this.instance.write(this.outputOptions) + // find changed assets + const changedAssets: string[] = [] + for (const [id, { content }] of generatedAssetsMap.get(this) ?? []) { + if (content) { + const data = content.toString('utf8') + if (this.lastAssets[id] !== data) { + changedAssets.push(id) + } + this.lastAssets[id] = data + } + } + // detect change of content of assert url placeholder __VITE_ASSET__xxx + const changedAssetsRegex = new RegExp( + // eslint-disable-next-line + `__VITE_ASSET__(${changedAssets.join('|')})__`, + ) + // extract hmr chunk // cf. https://github.com/web-infra-dev/rspack/blob/5a967f7a10ec51171a304a1ce8d741bd09fa8ed5/crates/rspack_plugin_hmr/src/lib.rs#L60 const chunk = this.result.output[0] @@ -262,6 +285,10 @@ class RolldownEnvironment extends DevEnvironment { for (const [id, mod] of Object.entries(chunk.modules)) { const current = mod.code const last = this.lastModules?.[id] + if (current?.match(changedAssetsRegex)) { + // TODO: need to replace __VITE_ASSET__xxx + this.newModules[id] = current + } if (current !== last) { this.newModules[id] = current } @@ -426,6 +453,8 @@ function patchRuntimePlugin(environment: RolldownEnvironment): rolldown.Plugin { }, }, renderChunk(code, chunk) { + // TODO: this magic string is heavy + // silly but we can do `render_app` on our own for now // https://github.com/rolldown/rolldown/blob/a29240168290e45b36fdc1a6d5c375281fb8dc3e/crates/rolldown/src/ecmascript/format/app.rs#L28-L55 const output = new MagicString(code) diff --git a/playground/rolldown-dev-react/src/app.tsx b/playground/rolldown-dev-react/src/app.tsx index 31ac12a5ed86a9..9ca7700eb6e75e 100644 --- a/playground/rolldown-dev-react/src/app.tsx +++ b/playground/rolldown-dev-react/src/app.tsx @@ -9,6 +9,10 @@ import testStyleInline from './test-style-inline.css?inline' // TODO: hmr for url assets? import testStyleUrl from './test-style-url.css?url' +// TODO: isolating finalizer doesn't rewrite yet +// const testAssetTxt = new URL('./test-asset.txt', import.meta.url).href; +// console.log(testAssetTxt); + export function App() { const [count, setCount] = React.useState(0) diff --git a/playground/rolldown-dev-react/src/test-asset.txt b/playground/rolldown-dev-react/src/test-asset.txt new file mode 100644 index 00000000000000..ce013625030ba8 --- /dev/null +++ b/playground/rolldown-dev-react/src/test-asset.txt @@ -0,0 +1 @@ +hello