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

相关推荐
七灵微12 分钟前
ES6入门---第三单元 模块七: Proxy的使用+Reflect的使用
javascript·vue.js·es6
travel_wsy21 分钟前
webrtc 视频直播
前端·vue.js·音视频·webrtc
zybsjn32 分钟前
开发 Chrome 扩展中的侧边栏图标设置实录(Manifest V3)
前端·chrome
weixin_4284984941 分钟前
在Star-CCM+中实现UDF并引用场数据和网格数据
java·前端
小猫猫改bug2 小时前
threejs 添加css3d标签 vue3
前端·javascript·css3
前端小巷子2 小时前
CSS3 过渡与动画
前端·css·css3
m0_zj2 小时前
58.[前端开发-前端工程化]Day05-webpack-Git安装-配置-Git命令
前端·webpack·node.js
GanGuaGua2 小时前
CSS:字体和文本样式
前端·css
Attacking-Coder2 小时前
前端面试宝典---JavaScript import 与 Node.js require 的区别
前端·javascript·node.js
切糕师学AI2 小时前
vue 中如何使用region?
前端·javascript·vue.js