Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
"oxfmt": "^0.54.0",
"picocolors": "^1.1.1",
"playwright-chromium": "^1.60.0",
"rolldown": "~1.1.1",
"rolldown": "~1.1.2",
"rollup": "^4.59.0",
"simple-git-hooks": "^2.13.1",
"tsx": "^4.22.4",
Expand Down
2 changes: 1 addition & 1 deletion packages/vite/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@
"lightningcss": "^1.32.0",
"picomatch": "^4.0.4",
"postcss": "^8.5.15",
"rolldown": "~1.1.1",
"rolldown": "~1.1.2",
"tinyglobby": "^0.2.17"
},
"optionalDependencies": {
Expand Down
60 changes: 55 additions & 5 deletions packages/vite/src/node/server/bundledDev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ export class BundledDev {
})
})

private fullReloadPending = false

private lastBuildError: Error | null = null

memoryFiles: MemoryFiles = new MemoryFiles()

constructor(private environment: DevEnvironment) {
Expand Down Expand Up @@ -108,6 +112,17 @@ export class BundledDev {
this.clients.setupIfNeeded(client, payload.clientId)
this.devEngine.registerModules(payload.clientId, payload.modules)
})
this.environment.hot.on('vite:client:connect', (_payload, client) => {
// Replay the cached build error to freshly connected clients.
if (this.lastBuildError) {
debug?.('REPLAY: replaying last build error to newly connected client')

client.send({
type: 'error',
err: prepareError(this.lastBuildError),
})
}
})
this.environment.hot.on('vite:client:disconnect', (_payload, client) => {
const clientId = this.clients.delete(client)
if (clientId) {
Expand Down Expand Up @@ -151,12 +166,15 @@ export class BundledDev {
error: result,
},
)
this.lastBuildError = result
this.fullReloadPending = false
this.environment.hot.send({
type: 'error',
err: prepareError(result),
})
return
}
this.lastBuildError = null

// NOTE: don't clear memoryFiles here as incremental build reuses the files
for (const outputFile of result.output) {
Expand All @@ -169,6 +187,12 @@ export class BundledDev {
}
})
}

// Trigger a full reload if there's no error in the result and a reload is pending from HMR.
if (this.fullReloadPending) {
this.fullReloadPending = false
this.debouncedFullReload()
}
Comment thread
h-a-n-a marked this conversation as resolved.
},
watch: {
skipWrite: true,
Expand All @@ -192,9 +216,11 @@ export class BundledDev {

private async waitForInitialBuildFinish(): Promise<void> {
await this.devEngine.ensureCurrentBuildFinish()
while (this.memoryFiles.size === 0) {
let state = await this.devEngine.getBundleState()
while (this.memoryFiles.size === 0 && !state.lastBuildErrored) {
await setTimeout(10)
await this.devEngine.ensureCurrentBuildFinish()
state = await this.devEngine.getBundleState()
}
}

Expand Down Expand Up @@ -254,9 +280,26 @@ export class BundledDev {

async triggerBundleRegenerationIfStale(): Promise<boolean> {
const bundleState = await this.devEngine.getBundleState()

// Trigger full build if the HMR errors,
// this is to make it easier to recover if the HMR generation is broken for some reason.
if (
this.initialBuildCompleted &&
bundleState.lastBuildErrored &&
bundleState.lastErrorStage === 'Hmr'
) {
debug?.(`TRIGGER: access after HMR-stage failure, forcing full rebuild`)

this.devEngine.triggerFullBuild()
this.devEngine.ensureLatestBuildOutput().then(() => {
this.debouncedFullReload()
})
return true
}

const shouldTrigger =
bundleState.hasStaleOutput &&
!bundleState.lastFullBuildFailed &&
!bundleState.lastBuildErrored &&
this.initialBuildCompleted
if (shouldTrigger) {
this.devEngine.ensureLatestBuildOutput().then(() => {
Expand Down Expand Up @@ -348,9 +391,16 @@ export class BundledDev {
colors.green(`trigger page reload `) + colors.dim(shortFile) + reason,
{ clear: !invalidateInformation, timestamp: true },
)
this.devEngine.ensureLatestBuildOutput().then(() => {
this.debouncedFullReload()
})
if (invalidateInformation) {
// Invalidate does not get upgraded to `rebuild`,
// so `onOutput` will not be triggered and thus the reload needs to be triggered here.
this.devEngine.ensureLatestBuildOutput().then(async () => {
this.debouncedFullReload()
})
} else {
// Use a flag to defer the reload until the `onOutput` callback to avoid error lay flashes.
this.fullReloadPending = true
}
return
}

Expand Down
4 changes: 2 additions & 2 deletions playground/js-sourcemap/__tests__/js-sourcemap.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ describe.runIf(isBuild)('build tests', () => {
content: {
"debugId": "00000000-0000-0000-0000-000000000000",
"ignoreList": [],
"mappings": ";muCAAA,OAAO,qDAEP,QAAQ,IAAI,uBAAuB",
"mappings": ";+tCAAA,OAAO,qDAEP,QAAQ,IAAI,uBAAuB",
"sources": [
"../../after-preload-dynamic.js",
],
Expand All @@ -291,7 +291,7 @@ describe.runIf(isBuild)('build tests', () => {
],
"version": 3,
},
visualization: "https://evanw.github.io/source-map-visualization/#MTYxNgBjb25zdCBfX3ZpdGVfX21hcERlcHM9KGksbT1fX3ZpdGVfX21hcERlcHMsZD0obS5mfHwobS5mPVsiYXNzZXRzL2R5bmFtaWMtZm9vLUJ3aFpUa3RCLmpzIiwiYXNzZXRzL2R5bmFtaWMtZm9vLURzcUtSckV5LmNzcyJdKSkpPT5pLm1hcChpPT5kW2ldKTsKdmFyIGU9YG1vZHVsZXByZWxvYWRgLHQ9ZnVuY3Rpb24oZSl7cmV0dXJuYC9gK2V9LG49e30scj1mdW5jdGlvbihyLGksYSl7bGV0IG89UHJvbWlzZS5yZXNvbHZlKCk7aWYoaSYmaS5sZW5ndGg+MCl7bGV0IHI9ZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoYGxpbmtgKSxzPWRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoYG1ldGFbcHJvcGVydHk9Y3NwLW5vbmNlXWApLGM9cz8ubm9uY2V8fHM/LmdldEF0dHJpYnV0ZShgbm9uY2VgKTtmdW5jdGlvbiBsKGUpe3JldHVybiBQcm9taXNlLmFsbChlLm1hcChlPT5Qcm9taXNlLnJlc29sdmUoZSkudGhlbihlPT4oe3N0YXR1czpgZnVsZmlsbGVkYCx2YWx1ZTplfSksZT0+KHtzdGF0dXM6YHJlamVjdGVkYCxyZWFzb246ZX0pKSkpfWZ1bmN0aW9uIHUoZSl7cmV0dXJuIGltcG9ydC5tZXRhLnJlc29sdmU/aW1wb3J0Lm1ldGEucmVzb2x2ZShlKTpuZXcgVVJMKGUsbmV3IFVSTChgLi4vLi4vLi4vc3JjL25vZGUvcGx1Z2lucy9pbXBvcnRBbmFseXNpc0J1aWxkLnRzYCxpbXBvcnQubWV0YS51cmwpKS5ocmVmfW89bChpLm1hcChpPT57aWYoaT10KGksYSksaT11KGkpLGkgaW4gbilyZXR1cm47bltpXT0hMDtsZXQgbz1pLmVuZHNXaXRoKGAuY3NzYCk7Zm9yKGxldCBlPXIubGVuZ3RoLTE7ZT49MDtlLS0pe2xldCB0PXJbZV07aWYodC5ocmVmPT09aSYmKCFvfHx0LnJlbD09PWBzdHlsZXNoZWV0YCkpcmV0dXJufWxldCBzPWRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoYGxpbmtgKTtpZihzLnJlbD1vP2BzdHlsZXNoZWV0YDplLG98fChzLmFzPWBzY3JpcHRgKSxzLmNyb3NzT3JpZ2luPWBgLHMuaHJlZj1pLGMmJnMuc2V0QXR0cmlidXRlKGBub25jZWAsYyksZG9jdW1lbnQuaGVhZC5hcHBlbmRDaGlsZChzKSxvKXJldHVybiBuZXcgUHJvbWlzZSgoZSx0KT0+e3MuYWRkRXZlbnRMaXN0ZW5lcihgbG9hZGAsZSkscy5hZGRFdmVudExpc3RlbmVyKGBlcnJvcmAsKCk9PnQoRXJyb3IoYFVuYWJsZSB0byBwcmVsb2FkIENTUyBmb3IgJHtpfWApKSl9KX0pKX1mdW5jdGlvbiBzKGUpe2xldCB0PW5ldyBFdmVudChgdml0ZTpwcmVsb2FkRXJyb3JgLHtjYW5jZWxhYmxlOiEwfSk7aWYodC5wYXlsb2FkPWUsd2luZG93LmRpc3BhdGNoRXZlbnQodCksIXQuZGVmYXVsdFByZXZlbnRlZCl0aHJvdyBlfXJldHVybiBvLnRoZW4oZT0+e2ZvcihsZXQgdCBvZiBlfHxbXSl0LnN0YXR1cz09PWByZWplY3RlZGAmJnModC5yZWFzb24pO3JldHVybiByKCkuY2F0Y2gocyl9KX07cigoKT0+aW1wb3J0KGAuL2R5bmFtaWMtZm9vLUJ3aFpUa3RCLmpzYCksX192aXRlX19tYXBEZXBzKFswLDFdKSksY29uc29sZS5sb2coYGFmdGVyIHByZWxvYWQgZHluYW1pY2ApO2V4cG9ydHtyIGFzIHR9OwovLyMgZGVidWdJZD04NzkzMWI0NS0xYTFjLTQ1OTgtODc4Ni1iYzIyZGEyNjNkYjMKLy8jIHNvdXJjZU1hcHBpbmdVUkw9YWZ0ZXItcHJlbG9hZC1keW5hbWljLUNIa3h0RkdoLmpzLm1hcDI2NwB7InZlcnNpb24iOjMsIm1hcHBpbmdzIjoiO211Q0FBQSxPQUFPLHFEQUVQLFFBQVEsSUFBSSx1QkFBdUIiLCJpZ25vcmVMaXN0IjpbXSwic291cmNlcyI6WyIuLi8uLi9hZnRlci1wcmVsb2FkLWR5bmFtaWMuanMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0KCcuL2R5bmFtaWMvZHluYW1pYy1mb28nKVxuXG5jb25zb2xlLmxvZygnYWZ0ZXIgcHJlbG9hZCBkeW5hbWljJylcbiJdLCJkZWJ1Z0lkIjoiMDAwMDAwMDAtMDAwMC0wMDAwLTAwMDAtMDAwMDAwMDAwMDAwIn0="
visualization: "https://evanw.github.io/source-map-visualization/#MTYxMgBjb25zdCBfX3ZpdGVfX21hcERlcHM9KGksbT1fX3ZpdGVfX21hcERlcHMsZD0obS5mfHwobS5mPVsiYXNzZXRzL2R5bmFtaWMtZm9vLUJ3aFpUa3RCLmpzIiwiYXNzZXRzL2R5bmFtaWMtZm9vLURzcUtSckV5LmNzcyJdKSkpPT5pLm1hcChpPT5kW2ldKTsKdmFyIGU9ZnVuY3Rpb24oZSl7cmV0dXJuYC9gK2V9LHQ9e30sbj1mdW5jdGlvbihuLHIsaSl7bGV0IGE9UHJvbWlzZS5yZXNvbHZlKCk7aWYociYmci5sZW5ndGg+MCl7bGV0IG49ZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoYGxpbmtgKSxvPWRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoYG1ldGFbcHJvcGVydHk9Y3NwLW5vbmNlXWApLHM9bz8ubm9uY2V8fG8/LmdldEF0dHJpYnV0ZShgbm9uY2VgKTtmdW5jdGlvbiBjKGUpe3JldHVybiBQcm9taXNlLmFsbChlLm1hcChlPT5Qcm9taXNlLnJlc29sdmUoZSkudGhlbihlPT4oe3N0YXR1czpgZnVsZmlsbGVkYCx2YWx1ZTplfSksZT0+KHtzdGF0dXM6YHJlamVjdGVkYCxyZWFzb246ZX0pKSkpfWZ1bmN0aW9uIGwoZSl7cmV0dXJuIGltcG9ydC5tZXRhLnJlc29sdmU/aW1wb3J0Lm1ldGEucmVzb2x2ZShlKTpuZXcgVVJMKGUsbmV3IFVSTChgLi4vLi4vLi4vc3JjL25vZGUvcGx1Z2lucy9pbXBvcnRBbmFseXNpc0J1aWxkLnRzYCxpbXBvcnQubWV0YS51cmwpKS5ocmVmfWE9YyhyLm1hcChyPT57aWYocj1lKHIsaSkscj1sKHIpLHIgaW4gdClyZXR1cm47dFtyXT0hMDtsZXQgYT1yLmVuZHNXaXRoKGAuY3NzYCk7Zm9yKGxldCBlPW4ubGVuZ3RoLTE7ZT49MDtlLS0pe2xldCB0PW5bZV07aWYodC5ocmVmPT09ciYmKCFhfHx0LnJlbD09PWBzdHlsZXNoZWV0YCkpcmV0dXJufWxldCBvPWRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoYGxpbmtgKTtpZihvLnJlbD1hP2BzdHlsZXNoZWV0YDpgbW9kdWxlcHJlbG9hZGAsYXx8KG8uYXM9YHNjcmlwdGApLG8uY3Jvc3NPcmlnaW49YGAsby5ocmVmPXIscyYmby5zZXRBdHRyaWJ1dGUoYG5vbmNlYCxzKSxkb2N1bWVudC5oZWFkLmFwcGVuZENoaWxkKG8pLGEpcmV0dXJuIG5ldyBQcm9taXNlKChlLHQpPT57by5hZGRFdmVudExpc3RlbmVyKGBsb2FkYCxlKSxvLmFkZEV2ZW50TGlzdGVuZXIoYGVycm9yYCwoKT0+dChFcnJvcihgVW5hYmxlIHRvIHByZWxvYWQgQ1NTIGZvciAke3J9YCkpKX0pfSkpfWZ1bmN0aW9uIG8oZSl7bGV0IHQ9bmV3IEV2ZW50KGB2aXRlOnByZWxvYWRFcnJvcmAse2NhbmNlbGFibGU6ITB9KTtpZih0LnBheWxvYWQ9ZSx3aW5kb3cuZGlzcGF0Y2hFdmVudCh0KSwhdC5kZWZhdWx0UHJldmVudGVkKXRocm93IGV9cmV0dXJuIGEudGhlbihlPT57Zm9yKGxldCB0IG9mIGV8fFtdKXQuc3RhdHVzPT09YHJlamVjdGVkYCYmbyh0LnJlYXNvbik7cmV0dXJuIG4oKS5jYXRjaChvKX0pfTtuKCgpPT5pbXBvcnQoYC4vZHluYW1pYy1mb28tQndoWlRrdEIuanNgKSxfX3ZpdGVfX21hcERlcHMoWzAsMV0pKSxjb25zb2xlLmxvZyhgYWZ0ZXIgcHJlbG9hZCBkeW5hbWljYCk7ZXhwb3J0e24gYXMgdH07Ci8vIyBkZWJ1Z0lkPWI5Zjk3NGQwLWFkZWEtNDFkYi1hMzM0LTk1ZWFmMDFlNGRhNQovLyMgc291cmNlTWFwcGluZ1VSTD1hZnRlci1wcmVsb2FkLWR5bmFtaWMtQzUtWFRRcmUuanMubWFwMjY3AHsidmVyc2lvbiI6MywibWFwcGluZ3MiOiI7K3RDQUFBLE9BQU8scURBRVAsUUFBUSxJQUFJLHVCQUF1QiIsImlnbm9yZUxpc3QiOltdLCJzb3VyY2VzIjpbIi4uLy4uL2FmdGVyLXByZWxvYWQtZHluYW1pYy5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQoJy4vZHluYW1pYy9keW5hbWljLWZvbycpXG5cbmNvbnNvbGUubG9nKCdhZnRlciBwcmVsb2FkIGR5bmFtaWMnKVxuIl0sImRlYnVnSWQiOiIwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDAifQ=="
}
`)
// verify sourcemap comment is preserved at the last line
Expand Down
2 changes: 1 addition & 1 deletion playground/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,6 @@
"convert-source-map": "^2.0.0",
"css-color-names": "^1.0.1",
"kill-port": "^1.6.1",
"rolldown": "~1.1.1"
"rolldown": "~1.1.2"
}
}
1 change: 1 addition & 0 deletions playground/resolve-tsconfig-paths/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@
"#/*": ["./src/*"]
}
},
"include": ["**/*", "index.html"],
"exclude": ["./__tests__"]
}
Loading