|
|
@@ -1,14 +1,13 @@
|
|
|
-<template>
|
|
|
- <div class="preview-container" ref="container">
|
|
|
-</div>
|
|
|
- <Message :err="runtimeError" />
|
|
|
- <Message v-if="!runtimeError" :warn="runtimeWarning" />
|
|
|
-</template>
|
|
|
-
|
|
|
<script setup lang="ts">
|
|
|
import Message from '../Message.vue'
|
|
|
-import { ref, onMounted, onUnmounted, watchEffect, watch } from 'vue'
|
|
|
-import type { WatchStopHandle } from 'vue'
|
|
|
+import {
|
|
|
+ ref,
|
|
|
+ onMounted,
|
|
|
+ onUnmounted,
|
|
|
+ watchEffect,
|
|
|
+ watch,
|
|
|
+ WatchStopHandle
|
|
|
+} from 'vue'
|
|
|
import srcdoc from './srcdoc.html?raw'
|
|
|
import { PreviewProxy } from './PreviewProxy'
|
|
|
import { MAIN_FILE, vueRuntimeUrl } from '../sfcCompiler'
|
|
|
@@ -27,34 +26,35 @@ let stopUpdateWatcher: WatchStopHandle
|
|
|
onMounted(createSandbox)
|
|
|
|
|
|
// reset sandbox when import map changes
|
|
|
-watch(() => store.importMap, (importMap, prev) => {
|
|
|
- if (!importMap) {
|
|
|
- if (prev) {
|
|
|
- // import-map.json deleted
|
|
|
- createSandbox()
|
|
|
- }
|
|
|
- return
|
|
|
- }
|
|
|
- try {
|
|
|
- const map = JSON.parse(importMap)
|
|
|
- if (!map.imports) {
|
|
|
- store.errors = [
|
|
|
- `import-map.json is missing "imports" field.`
|
|
|
- ]
|
|
|
+watch(
|
|
|
+ () => store.importMap,
|
|
|
+ (importMap, prev) => {
|
|
|
+ if (!importMap) {
|
|
|
+ if (prev) {
|
|
|
+ // import-map.json deleted
|
|
|
+ createSandbox()
|
|
|
+ }
|
|
|
return
|
|
|
}
|
|
|
- if (map.imports.vue) {
|
|
|
- store.errors = [
|
|
|
- 'Select Vue versions using the top-right dropdown.\n' +
|
|
|
- 'Specifying it in the import map has no effect.'
|
|
|
- ]
|
|
|
+ try {
|
|
|
+ const map = JSON.parse(importMap)
|
|
|
+ if (!map.imports) {
|
|
|
+ store.errors = [`import-map.json is missing "imports" field.`]
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if (map.imports.vue) {
|
|
|
+ store.errors = [
|
|
|
+ 'Select Vue versions using the top-right dropdown.\n' +
|
|
|
+ 'Specifying it in the import map has no effect.'
|
|
|
+ ]
|
|
|
+ }
|
|
|
+ createSandbox()
|
|
|
+ } catch (e) {
|
|
|
+ store.errors = [e as Error]
|
|
|
+ return
|
|
|
}
|
|
|
- createSandbox()
|
|
|
- } catch (e) {
|
|
|
- store.errors = [e]
|
|
|
- return
|
|
|
}
|
|
|
-})
|
|
|
+)
|
|
|
|
|
|
// reset sandbox when version changes
|
|
|
watch(vueRuntimeUrl, createSandbox)
|
|
|
@@ -73,21 +73,24 @@ function createSandbox() {
|
|
|
}
|
|
|
|
|
|
sandbox = document.createElement('iframe')
|
|
|
- sandbox.setAttribute('sandbox', [
|
|
|
- 'allow-forms',
|
|
|
- 'allow-modals',
|
|
|
- 'allow-pointer-lock',
|
|
|
- 'allow-popups',
|
|
|
- 'allow-same-origin',
|
|
|
- 'allow-scripts',
|
|
|
- 'allow-top-navigation-by-user-activation'
|
|
|
- ].join(' '))
|
|
|
+ sandbox.setAttribute(
|
|
|
+ 'sandbox',
|
|
|
+ [
|
|
|
+ 'allow-forms',
|
|
|
+ 'allow-modals',
|
|
|
+ 'allow-pointer-lock',
|
|
|
+ 'allow-popups',
|
|
|
+ 'allow-same-origin',
|
|
|
+ 'allow-scripts',
|
|
|
+ 'allow-top-navigation-by-user-activation'
|
|
|
+ ].join(' ')
|
|
|
+ )
|
|
|
|
|
|
let importMap: Record<string, any>
|
|
|
try {
|
|
|
importMap = JSON.parse(store.importMap || `{}`)
|
|
|
} catch (e) {
|
|
|
- store.errors = [`Syntax error in import-map.json: ${e.message}`]
|
|
|
+ store.errors = [`Syntax error in import-map.json: ${(e as Error).message}`]
|
|
|
return
|
|
|
}
|
|
|
|
|
|
@@ -95,7 +98,10 @@ function createSandbox() {
|
|
|
importMap.imports = {}
|
|
|
}
|
|
|
importMap.imports.vue = vueRuntimeUrl.value
|
|
|
- const sandboxSrc = srcdoc.replace(/<!--IMPORT_MAP-->/, JSON.stringify(importMap))
|
|
|
+ const sandboxSrc = srcdoc.replace(
|
|
|
+ /<!--IMPORT_MAP-->/,
|
|
|
+ JSON.stringify(importMap)
|
|
|
+ )
|
|
|
sandbox.srcdoc = sandboxSrc
|
|
|
container.value.appendChild(sandbox)
|
|
|
|
|
|
@@ -104,13 +110,15 @@ function createSandbox() {
|
|
|
// pending_imports = progress;
|
|
|
},
|
|
|
on_error: (event: any) => {
|
|
|
- const msg = event.value instanceof Error ? event.value.message : event.value
|
|
|
+ const msg =
|
|
|
+ event.value instanceof Error ? event.value.message : event.value
|
|
|
if (
|
|
|
msg.includes('Failed to resolve module specifier') ||
|
|
|
msg.includes('Error resolving module specifier')
|
|
|
) {
|
|
|
- runtimeError.value = msg.replace(/\. Relative references must.*$/, '') +
|
|
|
- `.\nTip: add an "import-map.json" file to specify import paths for dependencies.`
|
|
|
+ runtimeError.value =
|
|
|
+ msg.replace(/\. Relative references must.*$/, '') +
|
|
|
+ `.\nTip: add an "import-map.json" file to specify import paths for dependencies.`
|
|
|
} else {
|
|
|
runtimeError.value = event.value
|
|
|
}
|
|
|
@@ -173,24 +181,30 @@ async function updatePreview() {
|
|
|
`window.__modules__ = {};window.__css__ = ''`,
|
|
|
...modules,
|
|
|
`
|
|
|
-import { createApp as _createApp } from "vue"
|
|
|
-
|
|
|
-if (window.__app__) {
|
|
|
- window.__app__.unmount()
|
|
|
- document.getElementById('app').innerHTML = ''
|
|
|
-}
|
|
|
-
|
|
|
-document.getElementById('__sfc-styles').innerHTML = window.__css__
|
|
|
-const app = window.__app__ = _createApp(__modules__["${MAIN_FILE}"].default)
|
|
|
-app.config.errorHandler = e => console.error(e)
|
|
|
-app.mount('#app')`.trim()
|
|
|
+ import { createApp as _createApp } from "vue"
|
|
|
+
|
|
|
+ if (window.__app__) {
|
|
|
+ window.__app__.unmount()
|
|
|
+ document.getElementById('app').innerHTML = ''
|
|
|
+ }
|
|
|
+
|
|
|
+ document.getElementById('__sfc-styles').innerHTML = window.__css__
|
|
|
+ const app = window.__app__ = _createApp(__modules__["${MAIN_FILE}"].default)
|
|
|
+ app.config.errorHandler = e => console.error(e)
|
|
|
+ app.mount('#app')`.trim()
|
|
|
])
|
|
|
} catch (e) {
|
|
|
- runtimeError.value = e.message
|
|
|
+ runtimeError.value = (e as Error).message
|
|
|
}
|
|
|
}
|
|
|
</script>
|
|
|
|
|
|
+<template>
|
|
|
+ <div class="preview-container" ref="container"></div>
|
|
|
+ <Message :err="runtimeError" />
|
|
|
+ <Message v-if="!runtimeError" :warn="runtimeWarning" />
|
|
|
+</template>
|
|
|
+
|
|
|
<style>
|
|
|
.preview-container,
|
|
|
iframe {
|