mirror of
https://github.com/KwiTsukasa/kt-template-online-playground.git
synced 2026-05-27 16:45:45 +08:00
文档:更新编辑器项目说明
This commit is contained in:
parent
ab3a1aecc3
commit
712e26a13c
284
README.md
284
README.md
@ -1,204 +1,140 @@
|
||||
# @vue/repl
|
||||
# KT Template Online Playground
|
||||
|
||||
Vue SFC REPL as a Vue 3 component.
|
||||
`kt-template-online-playground` 是 KT Template Online 的在线编辑器。项目基于 `@vue/repl` 改造,负责编辑 Vue SFC 模板、预览运行效果、读取前台传入的组件信息,并在保存时截图上传 MinIO 后写入后端组件数据。
|
||||
|
||||
## Basic Usage
|
||||
## 技术栈
|
||||
|
||||
**Note: `@vue/repl` >= 2 now supports Monaco Editor, but also requires explicitly passing in the editor to be used for tree-shaking.**
|
||||
- Vue 3 + TypeScript
|
||||
- Vite
|
||||
- @vue/repl
|
||||
- Monaco Editor / CodeMirror
|
||||
- Axios
|
||||
- MinIO 上传接口
|
||||
- pnpm
|
||||
|
||||
```ts
|
||||
// vite.config.ts
|
||||
import { defineConfig } from 'vite'
|
||||
export default defineConfig({
|
||||
optimizeDeps: {
|
||||
exclude: ['@vue/repl'],
|
||||
},
|
||||
// ...
|
||||
})
|
||||
## 功能概览
|
||||
|
||||
- 在线编辑 Vue 单文件组件。
|
||||
- 实时编译并在 iframe 预览运行结果。
|
||||
- 支持从 URL hash 恢复编辑器文件状态。
|
||||
- 读取 URL query 初始化组件 `id`、`name`、`type`、`componentType`。
|
||||
- 保存时自动截取预览区图片,上传到 MinIO,并把图片地址写入组件 `image` 字段。
|
||||
- 根据是否存在 `id` 自动调用新增或编辑接口。
|
||||
|
||||
## 目录结构
|
||||
|
||||
```text
|
||||
src
|
||||
api/ # axios 封装和组件/字典/MinIO 接口
|
||||
editor/ # 文件列表、编辑器容器、编辑器适配
|
||||
output/ # 预览、沙箱、SSR 输出
|
||||
monaco/ # Monaco 语言服务和资源加载
|
||||
codemirror/ # CodeMirror 编辑器
|
||||
template/ # 默认模板
|
||||
PlaygroundHeader.vue # 组件表单、截图上传、保存入口
|
||||
Repl.vue # 编辑器主体
|
||||
store.ts # REPL 文件状态、序列化和反序列化
|
||||
index.ts # 包导出入口
|
||||
test/main.ts # 本地 Playground 页面入口
|
||||
```
|
||||
|
||||
### With CodeMirror Editor
|
||||
## 环境变量
|
||||
|
||||
Basic editing experience with no intellisense. Lighter weight, fewer network requests, better for embedding use cases.
|
||||
仓库只提交 `.env.example`,真实 `.env.development` 和 `.env.production` 保留在本地。
|
||||
|
||||
```vue
|
||||
<script setup>
|
||||
import { Repl } from '@vue/repl'
|
||||
import CodeMirror from '@vue/repl/codemirror-editor'
|
||||
// import '@vue/repl/style.css'
|
||||
// ^ no longer needed after 3.0
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Repl :editor="CodeMirror" />
|
||||
</template>
|
||||
```env
|
||||
VITE_APP_API_BASE=/api
|
||||
VITE_APP_PROXY=http://localhost:48085/
|
||||
```
|
||||
|
||||
### With Monaco Editor
|
||||
关键变量:
|
||||
|
||||
With Volar support, autocomplete, type inference, and semantic highlighting. Heavier bundle, loads dts files from CDN, better for standalone use cases.
|
||||
| 变量 | 说明 |
|
||||
| --- | --- |
|
||||
| `VITE_APP_API_BASE` | 前端请求前缀,默认 `/api` |
|
||||
| `VITE_APP_PROXY` | 后端服务地址,Vite dev server 会把 `/api` 代理到这里 |
|
||||
|
||||
```vue
|
||||
<script setup>
|
||||
import { Repl } from '@vue/repl'
|
||||
import Monaco from '@vue/repl/monaco-editor'
|
||||
// import '@vue/repl/style.css'
|
||||
// ^ no longer needed after 3.0
|
||||
</script>
|
||||
## 启动
|
||||
|
||||
<template>
|
||||
<Repl :editor="Monaco" />
|
||||
</template>
|
||||
项目 `.node-version` 为 `lts/*`。Windows 下如别名不可用,先用 `nvm ls` 查看已安装 LTS,再切到具体版本。
|
||||
|
||||
```bash
|
||||
pnpm install
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
## Advanced Usage
|
||||
常用命令:
|
||||
|
||||
Customize the behavior of the REPL by manually initializing the store.
|
||||
|
||||
See [v4 Migration Guide](https://github.com/vuejs/repl/releases/tag/v4.0.0)
|
||||
|
||||
```vue
|
||||
<script setup>
|
||||
import { watchEffect, ref } from 'vue'
|
||||
import { Repl, useStore, useVueImportMap } from '@vue/repl'
|
||||
import Monaco from '@vue/repl/monaco-editor'
|
||||
|
||||
// retrieve some configuration options from the URL
|
||||
const query = new URLSearchParams(location.search)
|
||||
|
||||
const {
|
||||
importMap: builtinImportMap,
|
||||
vueVersion,
|
||||
productionMode,
|
||||
} = useVueImportMap({
|
||||
// specify the default URL to import Vue runtime from in the sandbox
|
||||
// default is the CDN link from jsdelivr.com with version matching Vue's version
|
||||
// from peerDependency
|
||||
runtimeDev: 'cdn link to vue.runtime.esm-browser.js',
|
||||
runtimeProd: 'cdn link to vue.runtime.esm-browser.prod.js',
|
||||
serverRenderer: 'cdn link to server-renderer.esm-browser.js',
|
||||
})
|
||||
|
||||
const store = useStore(
|
||||
{
|
||||
// pre-set import map
|
||||
builtinImportMap,
|
||||
vueVersion,
|
||||
// starts on the output pane (mobile only) if the URL has a showOutput query
|
||||
showOutput: ref(query.has('showOutput')),
|
||||
// starts on a different tab on the output pane if the URL has a outputMode query
|
||||
// and default to the "preview" tab
|
||||
outputMode: ref(query.get('outputMode') || 'preview'),
|
||||
},
|
||||
// initialize repl with previously serialized state
|
||||
location.hash,
|
||||
)
|
||||
|
||||
// persist state to URL hash
|
||||
watchEffect(() => history.replaceState({}, '', store.serialize()))
|
||||
|
||||
// use a specific version of Vue
|
||||
vueVersion.value = '3.2.8'
|
||||
// production mode is enabled
|
||||
productionMode.value = true
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Repl :store="store" :editor="Monaco" :showCompileOutput="true" />
|
||||
</template>
|
||||
```bash
|
||||
pnpm dev # 本地 Playground 页面
|
||||
pnpm typecheck # 类型检查
|
||||
pnpm build # 构建库产物
|
||||
pnpm build-preview
|
||||
pnpm lint
|
||||
```
|
||||
|
||||
Use only the Preview without the editor
|
||||
## URL 数据约定
|
||||
|
||||
```vue
|
||||
<script setup>
|
||||
import { ref } from 'vue'
|
||||
import { Sandbox, useStore } from '@vue/repl'
|
||||
Playground 同时使用 query 和 hash:
|
||||
|
||||
// retrieve some configuration options from the URL
|
||||
const query = new URLSearchParams(location.search)
|
||||
- `query` 保存组件业务信息:`id`、`name`、`type`、`componentType`。
|
||||
- `hash` 保存 `store.serialize()` 生成的编辑器文件状态。
|
||||
- 保存成功后会用 `history.replaceState` 同步 query 和最新 hash。
|
||||
|
||||
const store = useStore(
|
||||
{
|
||||
// custom vue version
|
||||
vueVersion: ref(query.get('vue')),
|
||||
},
|
||||
// initialize repl with previously serialized state
|
||||
location.hash,
|
||||
)
|
||||
</script>
|
||||
前台跳转示例:
|
||||
|
||||
<template>
|
||||
<Sandbox :store="store" />
|
||||
</template>
|
||||
```text
|
||||
http://localhost:5173/?id=xxx&name=基础折线图&type=1&componentType=1#...
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>Configuration options for resource links. (replace CDN resources)</summary>
|
||||
## 保存流程
|
||||
|
||||
```ts
|
||||
export type ResourceLinkConfigs = {
|
||||
/** URL for ES Module Shims. */
|
||||
esModuleShims?: string
|
||||
/** Function that generates the Vue compiler URL based on the version. */
|
||||
vueCompilerUrl?: (version: string) => string
|
||||
/** Function that generates the TypeScript library URL based on the version. */
|
||||
typescriptLib?: (version: string) => string
|
||||
`PlaygroundHeader.vue` 是保存入口:
|
||||
|
||||
/** [monaco] Function that generates a URL to fetch the latest version of a package. */
|
||||
pkgLatestVersionUrl?: (pkgName: string) => string
|
||||
/** [monaco] Function that generates a URL to browse a package directory. */
|
||||
pkgDirUrl?: (pkgName: string, pkgVersion: string, pkgPath: string) => string
|
||||
/** [monaco] Function that generates a URL to fetch the content of a file from a package. */
|
||||
pkgFileTextUrl?: (
|
||||
pkgName: string,
|
||||
pkgVersion: string | undefined,
|
||||
pkgPath: string,
|
||||
) => string
|
||||
}
|
||||
1. 从 query 读取组件信息。
|
||||
2. 请求 `/dict/getDictByKey` 和 `/dict/getComponentDictByType` 初始化类型下拉。
|
||||
3. 通过当前 iframe 预览内容生成截图。
|
||||
4. 调用 `/minio/upload` 上传截图,获取返回的 `url`。
|
||||
5. 组装 `name`、`type`、`componentType`、`image`、`template`。
|
||||
6. 有 `id` 时调用 `/component/update`,没有 `id` 时调用 `/component/save`。
|
||||
7. 新增成功后把后端返回的 `id` 写回 query。
|
||||
|
||||
## 接口约定
|
||||
|
||||
接口集中在 `src/api`:
|
||||
|
||||
- `request.ts`:axios 实例,统一处理 `code !== 200` 的错误。
|
||||
- `component.ts`:新增和编辑组件。
|
||||
- `dict.ts`:组件类型字典。
|
||||
- `minio.ts`:截图文件上传。
|
||||
|
||||
当前主要接口:
|
||||
|
||||
| 方法 | 地址 | 用途 |
|
||||
| --- | --- | --- |
|
||||
| `GET` | `/dict/getDictByKey` | 查询一级类型 |
|
||||
| `GET` | `/dict/getComponentDictByType` | 查询二级类型 |
|
||||
| `POST` | `/minio/upload` | 上传预览截图 |
|
||||
| `POST` | `/component/save` | 新增组件 |
|
||||
| `POST` | `/component/update` | 编辑组件 |
|
||||
|
||||
## 开发约定
|
||||
|
||||
- 保持 query 和 hash 分工,不要让 `store.serialize()` 覆盖 `location.search`。
|
||||
- 保存前必须先上传截图,`image` 字段使用 MinIO 返回的 URL。
|
||||
- 业务请求新增时统一放到 `src/api`,组件里调用封装后的函数。
|
||||
- 编辑器核心逻辑来自 `@vue/repl`,调整时优先保持原有 Store、Preview、Editor 分层。
|
||||
|
||||
## 轻量验证
|
||||
|
||||
常规改动优先执行:
|
||||
|
||||
```bash
|
||||
pnpm typecheck
|
||||
```
|
||||
|
||||
**unpkg**
|
||||
涉及保存或预览交互时再启动开发服务检查明显报错:
|
||||
|
||||
```ts
|
||||
const store = useStore({
|
||||
resourceLinks: ref({
|
||||
esModuleShims:
|
||||
'https://unpkg.com/es-module-shims@1.5.18/dist/es-module-shims.wasm.js',
|
||||
vueCompilerUrl: (version) =>
|
||||
`https://unpkg.com/@vue/compiler-sfc@${version}/dist/compiler-sfc.esm-browser.js`,
|
||||
typescriptLib: (version) =>
|
||||
`https://unpkg.com/typescript@${version}/lib/typescript.js`,
|
||||
pkgLatestVersionUrl: (pkgName) =>
|
||||
`https://unpkg.com/${pkgName}@latest/package.json`,
|
||||
pkgDirUrl: (pkgName, pkgVersion, pkgPath) =>
|
||||
`https://unpkg.com/${pkgName}@${pkgVersion}/${pkgPath}/?meta`,
|
||||
pkgFileTextUrl: (pkgName, pkgVersion, pkgPath) =>
|
||||
`https://unpkg.com/${pkgName}@${pkgVersion || 'latest'}/${pkgPath}`,
|
||||
}),
|
||||
})
|
||||
```bash
|
||||
pnpm dev
|
||||
```
|
||||
|
||||
**npmmirror**
|
||||
|
||||
```ts
|
||||
const store = useStore({
|
||||
resourceLinks: ref({
|
||||
esModuleShims:
|
||||
'https://registry.npmmirror.com/es-module-shims/1.5.18/files/dist/es-module-shims.wasm.js',
|
||||
vueCompilerUrl: (version) =>
|
||||
`https://registry.npmmirror.com/@vue/compiler-sfc/${version}/files/dist/compiler-sfc.esm-browser.js`,
|
||||
typescriptLib: (version) =>
|
||||
`https://registry.npmmirror.com/typescript/${version}/files/lib/typescript.js`,
|
||||
|
||||
pkgLatestVersionUrl: (pkgName) =>
|
||||
`https://registry.npmmirror.com/${pkgName}/latest/files/package.json`,
|
||||
pkgDirUrl: (pkgName, pkgVersion, pkgPath) =>
|
||||
`https://registry.npmmirror.com/${pkgName}/${pkgVersion}/files/${pkgPath}/?meta`,
|
||||
pkgFileTextUrl: (pkgName, pkgVersion, pkgPath) =>
|
||||
`https://registry.npmmirror.com/${pkgName}/${pkgVersion || 'latest'}/files/${pkgPath}`,
|
||||
}),
|
||||
})
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user