借助官方@vue/repl

// App.vue<script setup lang="ts">
import { Repl } from '@vue/repl'
import { watchEffect } from 'vue'import { ReplStore } from './store'const setVH = () => {document.documentElement.style.setProperty('--vh', window.innerHeight + 'px')
}
window.addEventListener('resize', setVH)
setVH()
const store = new ReplStore({serializedState: location.hash.slice(1),
})const sfcOptions = {script: {reactivityTransform: true,},
}watchEffect(() => history.replaceState({}, '', store.serialize()))
</script><template><Repl:store="store":show-compile-output="true":auto-resize="true":sfc-options="sfcOptions":clear-console="false"@keydown.ctrl.s.prevent@keydown.meta.s.prevent/>
</template><style>
body {font-size: 13px;font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen,Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;margin: 0;--base: #444;--nav-height: 50px;
}.vue-repl {height: calc(var(--vh) - var(--nav-height));
}button {border: none;outline: none;cursor: pointer;margin: 0;background-color: transparent;
}
</style>

核心

//store.tsimport { reactive, watchEffect, version } from 'vue'
import * as defaultCompiler from 'vue/compiler-sfc'
import type { Store, SFCOptions, StoreState, OutputModes } from '@vue/repl'
import { compileFile, File } from '@vue/repl'
import { utoa, atou } from './utils/encode'
import {defaultMainFile,getVueRuntimeURL,getVueCompilerURL,getVantURL,vantInjectPlugin,additionalImports,additionalFiles,defaultDeleteTips,welcomeCode
} from './config'import { convertBugImportMapCdnUrl } from './helpers'export interface StoreStateWithVantURL extends StoreState {vantURL?: string
}export class ReplStore implements Store {state: StoreStateWithVantURLcompiler = defaultCompileroptions?: SFCOptionsinitialShowOutput: booleaninitialOutputMode: OutputModes = 'preview'private readonly defaultVueRuntimeURL: stringprivate pendingCompiler: Promise<any> | null = nullconstructor ({serializedState = '',defaultVueRuntimeURL = getVueRuntimeURL(version),showOutput = false,outputMode = 'preview'}: {serializedState?: stringshowOutput?: boolean// loose type to allow getting from the URL without inducing a typing erroroutputMode?: OutputModes | stringdefaultVueRuntimeURL?: string}) {let files: StoreStateWithVantURL['files'] = {}if (serializedState) {const saved = JSON.parse(atou(serializedState))// eslint-disable-next-line no-restricted-syntaxfor (const filename of Object.keys(saved)) {let codeContent = saved[filename]// fix some error cdn urlif (filename === 'import-map.json') {const json = JSON.parse(codeContent)convertBugImportMapCdnUrl(json.imports)codeContent = JSON.stringify(json, null, 2)}files[filename] = new File(filename, codeContent)}} else {files = {[defaultMainFile]: new File(defaultMainFile, welcomeCode)}}this.defaultVueRuntimeURL = defaultVueRuntimeURLthis.initialShowOutput = showOutputthis.initialOutputMode = outputMode as OutputModeslet mainFile = defaultMainFileif (!files[mainFile]) {mainFile = Object.keys(files)[0]}this.state = reactive({mainFile,files,activeFile: files[mainFile],errors: [],vueRuntimeURL: this.defaultVueRuntimeURL,vantURL: getVantURL()})this.initImportMap()watchEffect(() => compileFile(this, this.state.activeFile))for (const file in this.state.files) {if (file !== defaultMainFile) {compileFile(this, this.state.files[file])}}}setActive (filename: string) {this.state.activeFile = this.state.files[filename]}addFile (fileOrFilename: string | File) {const file = typeof fileOrFilename === 'string' ? new File(fileOrFilename) : fileOrFilenamethis.state.files[file.filename] = fileif (!file.hidden) this.setActive(file.filename)}deleteFile (filename: string) {for (const file of additionalFiles) {if (filename === file.filename && file.canDelete === false) {alert(file.deleteTips || defaultDeleteTips)return}}if (confirm(`Are you sure you want to delete ${filename}?`)) {if (this.state.activeFile.filename === filename) {this.state.activeFile = this.state.files[this.state.mainFile]}delete this.state.files[filename]}}serialize () {return '#' + utoa(JSON.stringify(this.getFiles()))}getFiles () {const exported: Record<string, string> = {}for (const filename in this.state.files) {exported[filename] = this.state.files[filename].code}return exported}async setFiles (newFiles: Record<string, string>, mainFile = defaultMainFile) {const files: Record<string, File> = {}if (mainFile === defaultMainFile && !newFiles[mainFile]) {files[mainFile] = new File(mainFile, welcomeCode)}// eslint-disable-next-line no-restricted-syntaxfor (const [filename, file] of Object.entries(newFiles)) {files[filename] = new File(filename, file)}// eslint-disable-next-line no-restricted-syntaxfor (const file of Object.values(files)) {await compileFile(this, file)}this.state.mainFile = mainFilethis.state.files = filesthis.initImportMap()this.setActive(mainFile)}private initImportMap () {const map = this.state.files['import-map.json']if (!map) {this.state.files['import-map.json'] = new File('import-map.json',JSON.stringify({imports: {vue: this.defaultVueRuntimeURL,...additionalImports}},null,2))} else {try {const json = JSON.parse(map.code)convertBugImportMapCdnUrl(json.imports)if (!json.imports.vue) {json.imports.vue = this.defaultVueRuntimeURLmap.code = JSON.stringify(json, null, 2)}} catch (e) {}}// additionalFiles injectadditionalFiles.forEach(file => {const { filename, code, hidden } = filethis.state.files[filename] = new File(vantInjectPlugin, code)this.state.files[filename].hidden = !!hidden})}getImportMap () {try {const codeJson = JSON.parse(this.state.files['import-map.json'].code)convertBugImportMapCdnUrl(codeJson.imports)return codeJson} catch (e) {this.state.errors = [`Syntax error in import-map.json: ${(e as Error).message}`]return {}}}setImportMap (map: {imports: Record<string, string>scopes?: Record<string, Record<string, string>>}) {this.state.files['import-map.json'].code = JSON.stringify(map, null, 2)}async setVueVersion (version: string) {const compilerUrl = getVueCompilerURL(version)const runtimeUrl = getVueRuntimeURL(version)this.pendingCompiler = import(/* @vite-ignore */ compilerUrl)this.compiler = await this.pendingCompilerthis.pendingCompiler = nullthis.state.vueRuntimeURL = runtimeUrlconst importMap = this.getImportMap();(importMap.imports || (importMap.imports = {})).vue = runtimeUrlthis.setImportMap(importMap)console.info(`[@vue/repl] Now using Vue version: ${version}`)}resetVueVersion () {this.compiler = defaultCompilerthis.state.vueRuntimeURL = this.defaultVueRuntimeURL}async setVantVersion (version: string) {const vantUrl = getVantURL(version)this.state.vantURL = vantUrlconst importMap = this.getImportMap();(importMap.imports || (importMap.imports = {})).vant = vantUrlthis.setImportMap(importMap)console.info(`[@vue/repl] Now using Vant version: ${version}`)}resetVantVersion () {this.state.vantURL = getVantURL()}
}
// config.tsimport { File } from '@vue/repl'export enum npmCdnEnum {jsdelivr = 'https://cdn.jsdelivr.net/npm',unpkg = 'https://unpkg.com',skypack = 'https://cdn.skypack.dev',cndjs = 'https://cdnjs.com/libraries'
}export const DEFAULT_CDN = npmCdnEnum.unpkg/** get vue runtime cdn url buy version */
export const getVueRuntimeURL = (version: string) => `${DEFAULT_CDN}/@vue/runtime-dom@${version}/dist/runtime-dom.esm-browser.js`/** get vue compiler cdn url buy version */
export const getVueCompilerURL = (version: string) => `${DEFAULT_CDN}/@vue/compiler-sfc@${version}/dist/compiler-sfc.esm-browser.js`export const vantCss = `${DEFAULT_CDN}/vant/lib/index.css`export const additionalImportsCss = [vantCss
]/** get vant cdn url buy version */
export const getVantURL = (version?: string) => {if (version) {return `${DEFAULT_CDN}/vant@${version}/lib/vant.es.min.js`}return `${DEFAULT_CDN}/vant/lib/vant.es.min.js`
}export const defaultMainFile = 'App.vue'
export const vantInjectPlugin = 'vant-inject-plugin.js'/*** get cdn url by package name & filePath* if use unpkg cdn, url will add query params: ?module'*/
export const getCdnUrl = (npmName: string, filePath?: string) => {if (DEFAULT_CDN === npmCdnEnum.unpkg) {return `${DEFAULT_CDN}/${npmName}?module`}return `${DEFAULT_CDN}/${npmName}/${filePath}`
}export const vantImports: Record<string, string> = {vant: getVantURL(),'@vant/use': getCdnUrl('@vant/use', '/dist/index.esm.mjs'),'@vant/popperjs': getCdnUrl('@vant/popperjs', '/dist/index.esm.mjs'),'@vant/touch-emulator': `${DEFAULT_CDN}/@vant/touch-emulator`
}export const additionalImports = {...vantImports
}export const welcomeCode = `\
<script setup lang='ts'>
import { ref } from 'vue'
import { Button } from 'vant';
import { injectVant } from './vant-inject-plugin.js'injectVant()
const msg = ref('Hello Vant!')
</script><template>Button:<Button type="primary">{{ msg }}</Button><van-divider />van-button:<van-button type="primary">{{ msg }}</van-button><van-divider />van-Button:<van-Button type="primary">{{ msg }}</van-Button>
</template>
`export const vantReplPluginCode = `\
import { getCurrentInstance } from 'vue'import Vant from 'vant'
import '@vant/touch-emulator'export function injectVant() {const instance = getCurrentInstance()instance.appContext.app.use(Vant)
}export function appendStyle() {return new Promise((resolve, reject) => {const link = document.createElement('link')link.rel = 'stylesheet'link.href = '${vantCss}'link.onload = resolvelink.onerror = rejectdocument.body.appendChild(link)})
}await appendStyle()
`export type additionalFileType = Pick<File, 'filename' | 'code'> & Partial<Omit<File, 'filename' | 'code'>> & {canDelete?: boolean,/** default project depends on this file, cannot be deleted */deleteTips?: string,
}export const defaultDeleteTips = 'project depends on this file, cannot be deleted'export const additionalFiles: additionalFileType[] = [{filename: vantInjectPlugin,code: vantReplPluginCode,// hidden: true,canDelete: false,deleteTips: 'vant depends on this file'
}]

Vue FSC在线编译代码实时预览@vue/repl相关推荐

  1. VSCode设置网页代码实时预览

    目录 一.设置描述 二.操作步骤 一.设置描述 1.VSCode作为一款很不错的开发软件,相比DW更小巧,用来测试前端特别不错,那么我们平时开发网页发现只有写完代码,然后保存,接下来到浏览器中刷新查看 ...

  2. 用户收货地址h5页面_如何实现H5可视化编辑器的实时预览和真机扫码预览功能...

    前言所见即所得的设计理念在WEB IDE领域里一直是备受瞩目的功能亮点, 也能极大的提高 web coder的编程体验和编程效率. 笔者接下来就将对H5可视化编辑器的实时预览和真机扫码预览功能做一次方 ...

  3. 用户收货地址h5页面_如何实现H5可视化编辑器的实时预览和真机扫码预览功能?...

    前言 所见即所得的设计理念在WEB IDE领域里一直是备受瞩目的功能亮点, 也能极大的提高 web coder的编程体验和编程效率. 笔者接下来就将对H5可视化编辑器的实时预览和真机扫码预览功能做一次 ...

  4. 如何实现H5可视化编辑器的实时预览和真机扫码预览功能

    往期精彩 基于NodeJS从零构建线上自动化打包工作流(H5-Dooring特别版) 在线IDE开发入门之从零实现一个在线代码编辑器 基于React+Koa实现一个h5页面可视化编辑器-Dooring ...

  5. h5案例欣赏及分析_如何实现H5可视化编辑器的实时预览和真机扫码预览功能

    往期精彩 基于NodeJS从零构建线上自动化打包工作流(H5-Dooring特别版) 在线IDE开发入门之从零实现一个在线代码编辑器 基于React+Koa实现一个h5页面可视化编辑器-Dooring ...

  6. vue2实现海康威视根据海康插件进行监控实时预览和回放功能,全套代码,开箱即用。

    这是一套拿到手就能直接用的根据海康提供的摄像机节点实时预览和回放的全步骤代码,开箱即用. 前言 我的是基于vue2写的,vue3可以看我下一篇文章.  点击跳转至vue3关于海康视频开发文章. 很多人 ...

  7. VSCode中安装Live Server插件实现Html网页代码的实时预览

    VSCode中安装Live Server插件实现Html网页代码的实时预览 利用寒假时间学习了一些基本的网页知识,在编写Html代码时可以利用IDEA.WebStorm.Dream Weaver等工具 ...

  8. 海康威视实时预览回调PS流用EasyRTMP向RTMP服务器推流中视频数据处理的代码

    在上一篇方案<EasyRTMP结合海康HCNetSDK获取海康摄像机H.264实时流并转化成为RTMP直播推流(附源码)>我们介绍了将海康安防摄像机进行互联网直播的整体方案流程,其中有一个 ...

  9. EasyRTMP:RTMP推流海康威视实时预览回调PS流用EasyRTMP向RTMP服务器推流中视频数据处理的代码

    在上一篇方案<EasyRTMP结合海康HCNetSDK获取海康摄像机H.264实时流并转化成为RTMP直播推流(附源码)>中我们介绍了将海康安防摄像机进行互联网直播的整体方案流程,其中有一 ...

最新文章

  1. php----------const 定义的常量和define()定义的常量的区别?
  2. onkeyup,onkeydown和onkeypress的区别介绍
  3. Java黑皮书课后题第8章:*8.16(对二维数组排序)编写一个方法,使用下面的方法头对二维数组排序。这个方法首先按行排序,然后按列排序
  4. asp.net 返回超时的解决方法
  5. 动物识别专家系统python_Python有哪些作用?
  6. 【C语言进阶深度学习记录】九 C语言中const的详细分析
  7. 网页优化系列三:使用压缩后置viewstate
  8. iOS CocoaPods:Updating local specs repositories一直停在那里了
  9. IT运维存在问题及改进
  10. Android相框合成图片抠图
  11. Excel图表制作(二):滚动条实现动态图表
  12. Google翻译接口调用
  13. 最简单易学的手机打字方法
  14. 渗透测试-安全岗位面试题总结(含答案)
  15. 三大主流Mac清理软件实测:Cleaner One | 柠檬清理 | CleanmyMac
  16. 使用Vue3学习Vue的基础知识
  17. 西电2020计算机考研,西安电子科技大学研究生院,西电2020年考研成绩最新信息!...
  18. vue自定义指令实现按钮界别权限管理
  19. linux软中断和消息队列结合,传统UNIX进程间通信内核实现概要
  20. PHP初级【10天小积累-第十天】

热门文章

  1. 修复计算机的英语怎么拼,电脑输入法不见了怎么恢复?手把手教你恢复电脑输入法的方法...
  2. 微信小程序开屏广告实现
  3. 产品经理就业喜报:沉舟侧畔终迎万木春
  4. 云存储数据的一般完整性验证
  5. wp下载吧主题模板_内含newzhan2.60无授权版本
  6. 12星座都是什么性格?(python爬虫+jieba分词+词云)
  7. 软考—信息项目管理师(信息化和信息系统二)
  8. 分分钟上手 VS Code
  9. 其实每一个人,都能靠自己的力量变成光的!
  10. godaddy 服务器位置,GoDaddy DNS服务器地址 | Godaddy美国主机中文指南