Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: do not access document in /@vite/client when not defined #16318

Merged
merged 4 commits into from
Apr 3, 2024
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
77 changes: 44 additions & 33 deletions packages/vite/src/client/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,11 @@ function setupWebSocket(

notifyListeners('vite:ws:disconnect', { webSocket: socket })

console.log(`[vite] server connection lost. polling for restart...`)
await waitForSuccessfulPing(protocol, hostAndPath)
location.reload()
if (hasDocument) {
console.log(`[vite] server connection lost. polling for restart...`)
await waitForSuccessfulPing(protocol, hostAndPath)
location.reload()
}
})

return socket
Expand Down Expand Up @@ -182,16 +184,20 @@ async function handleMessage(payload: HMRPayload) {
break
case 'update':
notifyListeners('vite:beforeUpdate', payload)
// if this is the first update and there's already an error overlay, it
// means the page opened with existing server compile error and the whole
// module script failed to load (since one of the nested imports is 500).
// in this case a normal update won't work and a full reload is needed.
if (isFirstUpdate && hasErrorOverlay()) {
window.location.reload()
return
} else {
clearErrorOverlay()
isFirstUpdate = false
if (hasDocument) {
// if this is the first update and there's already an error overlay, it
// means the page opened with existing server compile error and the whole
// module script failed to load (since one of the nested imports is 500).
// in this case a normal update won't work and a full reload is needed.
if (isFirstUpdate && hasErrorOverlay()) {
window.location.reload()
return
} else {
if (enableOverlay) {
clearErrorOverlay()
}
isFirstUpdate = false
}
}
await Promise.all(
payload.updates.map(async (update): Promise<void> => {
Expand Down Expand Up @@ -249,21 +255,23 @@ async function handleMessage(payload: HMRPayload) {
}
case 'full-reload':
notifyListeners('vite:beforeFullReload', payload)
if (payload.path && payload.path.endsWith('.html')) {
// if html file is edited, only reload the page if the browser is
// currently on that page.
const pagePath = decodeURI(location.pathname)
const payloadPath = base + payload.path.slice(1)
if (
pagePath === payloadPath ||
payload.path === '/index.html' ||
(pagePath.endsWith('/') && pagePath + 'index.html' === payloadPath)
) {
if (hasDocument) {
if (payload.path && payload.path.endsWith('.html')) {
// if html file is edited, only reload the page if the browser is
// currently on that page.
const pagePath = decodeURI(location.pathname)
const payloadPath = base + payload.path.slice(1)
if (
pagePath === payloadPath ||
payload.path === '/index.html' ||
(pagePath.endsWith('/') && pagePath + 'index.html' === payloadPath)
) {
pageReload()
}
return
} else {
pageReload()
}
return
} else {
pageReload()
}
break
case 'prune':
Expand All @@ -272,13 +280,15 @@ async function handleMessage(payload: HMRPayload) {
break
case 'error': {
notifyListeners('vite:error', payload)
const err = payload.err
if (enableOverlay) {
createErrorOverlay(err)
} else {
console.error(
`[vite] Internal Server Error\n${err.message}\n${err.stack}`,
)
if (hasDocument) {
const err = payload.err
if (enableOverlay) {
createErrorOverlay(err)
} else {
console.error(
`[vite] Internal Server Error\n${err.message}\n${err.stack}`,
)
}
}
break
}
Expand All @@ -298,6 +308,7 @@ function notifyListeners(event: string, data: any): void {
}

const enableOverlay = __HMR_ENABLE_OVERLAY__
const hasDocument = 'document' in globalThis

function createErrorOverlay(err: ErrorPayload['err']) {
clearErrorOverlay()
Expand Down
59 changes: 31 additions & 28 deletions packages/vite/src/client/overlay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,39 +165,41 @@ kbd {
`

// Error Template
const template = h(
'div',
{ class: 'backdrop', part: 'backdrop' },
let template: HTMLElement
const createTemplate = () =>
h(
'div',
{ class: 'window', part: 'window' },
h(
'pre',
{ class: 'message', part: 'message' },
h('span', { class: 'plugin', part: 'plugin' }),
h('span', { class: 'message-body', part: 'message-body' }),
),
h('pre', { class: 'file', part: 'file' }),
h('pre', { class: 'frame', part: 'frame' }),
h('pre', { class: 'stack', part: 'stack' }),
{ class: 'backdrop', part: 'backdrop' },
h(
'div',
{ class: 'tip', part: 'tip' },
'Click outside, press ',
h('kbd', {}, 'Esc'),
' key, or fix the code to dismiss.',
h('br'),
'You can also disable this overlay by setting ',
h('code', { part: 'config-option-name' }, 'server.hmr.overlay'),
' to ',
h('code', { part: 'config-option-value' }, 'false'),
' in ',
h('code', { part: 'config-file-name' }, hmrConfigName),
'.',
{ class: 'window', part: 'window' },
h(
'pre',
{ class: 'message', part: 'message' },
h('span', { class: 'plugin', part: 'plugin' }),
h('span', { class: 'message-body', part: 'message-body' }),
),
h('pre', { class: 'file', part: 'file' }),
h('pre', { class: 'frame', part: 'frame' }),
h('pre', { class: 'stack', part: 'stack' }),
h(
'div',
{ class: 'tip', part: 'tip' },
'Click outside, press ',
h('kbd', {}, 'Esc'),
' key, or fix the code to dismiss.',
h('br'),
'You can also disable this overlay by setting ',
h('code', { part: 'config-option-name' }, 'server.hmr.overlay'),
' to ',
h('code', { part: 'config-option-value' }, 'false'),
' in ',
h('code', { part: 'config-file-name' }, hmrConfigName),
'.',
),
),
),
h('style', {}, templateStyle),
)
h('style', {}, templateStyle),
)

const fileRE = /(?:[a-zA-Z]:\\|\/).*?:\d+:\d+/g
const codeframeRE = /^(?:>?\s*\d+\s+\|.*|\s+\|\s*\^.*)\r?\n/gm
Expand All @@ -213,6 +215,7 @@ export class ErrorOverlay extends HTMLElement {
super()
this.root = this.attachShadow({ mode: 'open' })

template ??= createTemplate()
this.root.appendChild(template)

codeframeRE.lastIndex = 0
Expand Down
2 changes: 1 addition & 1 deletion playground/worker/__tests__/es/worker-es.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ test('emit chunk', async () => {
)
await untilUpdated(
() => page.textContent('.emit-chunk-dynamic-import-worker'),
'"A string/es/"',
'"A stringmodule1/es/"',
true,
)
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ test.runIf(isBuild)('emit chunk', async () => {
)
await untilUpdated(
() => page.textContent('.emit-chunk-dynamic-import-worker'),
'"A string./"',
'"A stringmodule1./"',
true,
)
})
Expand Down
6 changes: 5 additions & 1 deletion playground/worker/emit-chunk-dynamic-import-worker.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import module1Url from './modules/module1.js?url'

import('./modules/module0').then((module) => {
self.postMessage(module.default + import.meta.env.BASE_URL)
import(/* @vite-ignore */ module1Url).then((module1) => {
self.postMessage(module.default + module1.msg1 + import.meta.env.BASE_URL)
})
})

// for sourcemap
Expand Down