| import { WebContainer } from '@webcontainer/api'; |
| import { WORK_DIR_NAME } from '~/utils/constants'; |
| import { cleanStackTrace } from '~/utils/stacktrace'; |
|
|
| interface WebContainerContext { |
| loaded: boolean; |
| } |
|
|
| export const webcontainerContext: WebContainerContext = import.meta.hot?.data.webcontainerContext ?? { |
| loaded: false, |
| }; |
|
|
| if (import.meta.hot) { |
| import.meta.hot.data.webcontainerContext = webcontainerContext; |
| } |
|
|
| export let webcontainer: Promise<WebContainer> = new Promise(() => { |
| |
| }); |
|
|
| if (!import.meta.env.SSR) { |
| webcontainer = |
| import.meta.hot?.data.webcontainer ?? |
| Promise.resolve() |
| .then(() => { |
| return WebContainer.boot({ |
| coep: 'credentialless', |
| workdirName: WORK_DIR_NAME, |
| forwardPreviewErrors: true, |
| }); |
| }) |
| .then(async (webcontainer) => { |
| webcontainerContext.loaded = true; |
|
|
| const { workbenchStore } = await import('~/lib/stores/workbench'); |
|
|
| |
| webcontainer.on('preview-message', (message) => { |
| console.log('WebContainer preview message:', message); |
|
|
| |
| if (message.type === 'PREVIEW_UNCAUGHT_EXCEPTION' || message.type === 'PREVIEW_UNHANDLED_REJECTION') { |
| const isPromise = message.type === 'PREVIEW_UNHANDLED_REJECTION'; |
| workbenchStore.actionAlert.set({ |
| type: 'preview', |
| title: isPromise ? 'Unhandled Promise Rejection' : 'Uncaught Exception', |
| description: message.message, |
| content: `Error occurred at ${message.pathname}${message.search}${message.hash}\nPort: ${message.port}\n\nStack trace:\n${cleanStackTrace(message.stack || '')}`, |
| source: 'preview', |
| }); |
| } |
| }); |
|
|
| return webcontainer; |
| }); |
|
|
| if (import.meta.hot) { |
| import.meta.hot.data.webcontainer = webcontainer; |
| } |
| } |
|
|