为 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 等功能。下期加上。

相关推荐
zczlsy1137 分钟前
webpack介绍
前端·webpack·node.js
六个点39 分钟前
关于vue的面试考点总结🤯
前端·vue.js·面试
浪遏1 小时前
今晚揭开单例模式的面纱~
前端·设计模式·面试
千里码aicood1 小时前
【2025】基于springboot+vue的汽车销售试驾平台(源码、万字文档、图文修改、调试答疑)
vue.js·spring boot·汽车
驯龙高手_追风2 小时前
谷歌Chrome或微软Edge浏览器修改网页任意内容
前端·chrome·edge
luckyext2 小时前
Postman发送GET请求示例及注意事项
前端·后端·物联网·测试工具·小程序·c#·postman
小满zs2 小时前
React第三十章(css原子化)
前端·react.js
一直在学习的小白~3 小时前
前端项目中创建自动化部署脚本,用于 Jenkins 触发 npm run publish 来完成远程部署
前端·自动化·jenkins
Perfect—完美3 小时前
Vue 3 事件总线详解:构建组件间高效通信的桥梁
前端·javascript·vue.js
二川bro3 小时前
模拟类似 DeepSeek 的对话
前端·人工智能