为 Vue SFC REPL 添加 UnoCSS

为 Vue SFC REPL 添加 UnoCSS 支持,可用于 Vue + UnoCss 的 demo 集。

preview 部署在 vue-repl-two.vercel.app

简析原项目

这里只挑选核心的目录/文件。

  • 📁codemirror - 编辑器的 codemirror 实现
  • 📁monaco - 编辑器的 monaco editor 实现,包括 vue language service 的 worker
  • 📁editor
    • FileSelector.vue - 输入标签列表
  • 📁output
    • Output.vue - 输出面板
    • Sandbox.vue - 预览沙盒
    • srcdoc.html - 预览沙盒的 srcdoc
  • store.ts - 源码文件、配置文件、编译器、编译输出等状态管理

编辑器输入源码和配置文件,通过 Vue SFC compiler 编译,输出并在 iframe 沙盒中预览。

改造方案

为了实现 UnoCSS 的输入、输出、预览,改造点如下:

  1. 添加 uno.config.ts 输入,在 store.ts 中和 tsconfig.json、import map 一并管理,监听并编译 uno.config.ts,生成 config。
  2. 构造 UnoCSS 生成器;监听源码,根据输入源码生成 uno.css,在 Output.vue 添加输出标签
  3. uno.css 插入到预览沙盒 iframe 的一个 <style> 标签中。

上述内容中,输入输出的添加比较简单,本文略,下面说说 uno.config.ts 的在线编译。

完整代码可查看笔者的 fork

在线编译 uno.config.ts

参考 UnoCSS Playground 实现,UnoCSS 编译的核心代码如下:

ts 复制代码
import { $fetch } from 'ofetch'

export async function evaluateUserConfig<U = UserConfig>(
   configStr: string,
   version: string = 'latest',
 ): Promise<U | undefined> {
   const modulesCache = globalCache
   const moduleMap =
     version === 'latest'
       ? unocssBundle
       : new Map(
           unocssBundle
             .keys()
             .map((p) => [
               p,
               () => import(/* @vite-ignore */ `https://esm.sh/${p}@${version}`),
             ]),
         )
 
   const code = configStr
     .replace(
       /import\s(.*?)\sfrom\s*(['"])unocss\2/g,
       'const $1 = await __import("unocss");',
     )
     .replace(
       /import\s*(\{[\s\S]*?\})\s*from\s*(['"])([\w@/-]+)\2/g,
       'const $1 = await __import("$3");',
     )
     .replace(
       /import\s(.*?)\sfrom\s*(['"])([\w@/-]+)\2/g,
       'const $1 = (await __import("$3")).default;',
     )
     .replace(/export default /, 'return ')
     .replace(/\bimport\s*\(/, '__import(')
 
   // bypass vite interop
   // eslint-disable-next-line no-new-func
   const _import = new Function('a', 'return import(a);')
   const __import = (name: string): any => {
     if (!modulesCache.has(name)) {
       modulesCache.set(
         name,
         moduleMap.has(name)
           ? moduleMap.get(name)!()
           : name.endsWith('.json')
             ? $fetch(CDN_BASE + name, { responseType: 'json' }).then((r) => ({
                 default: r,
               }))
             : _import(CDN_BASE + name),
       )
     }
     return modulesCache.get(name)
   }
 
   const fn = new AsyncFunction('__import', code)
   const result = await fn(__import)
 
   if (result) return result
 }

evaluateUserConfig 读取 uno.config.ts,将 import 语句解析并替换为预先准备好(或指定版本下载)的模块。

总结

本文简析了 Vue SFC REPL 项目,在此基础上通过在线编译 uno.config.ts 添加了UnoCSS 的输入、输出、预览,交互和原交互无缝融合。

下期预告: 现在的编辑器不支持 UnoCSS Token 的 hover、autocomplete、underline 等功能。下期加上。

相关推荐
这是个栗子1 分钟前
【问题解决】Vue2 与 Vue3项目中 Node.js 版本选择
前端·node.js·nvm
222you2 分钟前
SpringBeanFactory
java·服务器·前端
苏打水com3 分钟前
第十一篇:Day31-33 前端安全与性能监控——从“能用”到“安全可靠”(对标职场“系统稳定性”需求)
前端·javascript·css·vue.js·html
fpl11164 分钟前
npm :无法加载文件 D:\...\nodejs\npm.ps1,因为在此系统上禁止运行脚本
前端·vscode·npm·node.js·命令模式
LYFlied8 分钟前
LeetCode热题Top100:核心算法思想与前端实战套路
前端·算法·leetcode·面试·算法思想·算法套路·解题公式
赵庆明老师8 分钟前
NET 中,使用SignalR 调用Controller 控制器的 Hub 方法
前端·html·xhtml
zhangwenwu的前端小站10 分钟前
VUE 实现划词 问AI 翻译等功能
前端·javascript·vue.js
黑臂麒麟10 分钟前
华为云的DevUI&Form组件实战:个人信息编辑表单完整实现
前端·javascript·ui·华为云·angular.js
程序员小寒13 分钟前
前端高频面试题之手写Promise
前端·javascript·面试
粉末的沉淀24 分钟前
tauri:tauri2.0+vue3+vite打包案例
前端