Compare commits
1 Commits
v1.0.2
...
3a94c90251
| Author | SHA1 | Date | |
|---|---|---|---|
|
3a94c90251
|
@@ -24,7 +24,6 @@ This project is a front-end web UI of Oxygen Toolbox and needs to be used with t
|
|||||||
# Requires
|
# Requires
|
||||||
|
|
||||||
- Web Server (e.g. Nginx, Apache httpd)
|
- Web Server (e.g. Nginx, Apache httpd)
|
||||||
- [API of Oxygen Toolbox](https://github.com/FatttSnake/oxygen-api) (v1.0.0 or later versions)
|
|
||||||
|
|
||||||
# Related projects
|
# Related projects
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,6 @@
|
|||||||
# 环境要求
|
# 环境要求
|
||||||
|
|
||||||
- Web 服务器(如 Nginx, Apache httpd)
|
- Web 服务器(如 Nginx, Apache httpd)
|
||||||
- [API of Oxygen Toolbox](https://github.com/FatttSnake/oxygen-api) (v1.0.0 或更高版本)
|
|
||||||
|
|
||||||
# 关联项目
|
# 关联项目
|
||||||
|
|
||||||
|
|||||||
10
package-lock.json
generated
10
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "oxygen-ui",
|
"name": "oxygen-ui",
|
||||||
"version": "1.0.1-SNAPSHOT",
|
"version": "1.0.0-SNAPSHOT",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "oxygen-ui",
|
"name": "oxygen-ui",
|
||||||
"version": "1.0.1-SNAPSHOT",
|
"version": "1.0.0-SNAPSHOT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ant-design/icons": "^5.3.7",
|
"@ant-design/icons": "^5.3.7",
|
||||||
"@dnd-kit/core": "^6.1.0",
|
"@dnd-kit/core": "^6.1.0",
|
||||||
@@ -2153,9 +2153,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/acorn": {
|
"node_modules/acorn": {
|
||||||
"version": "8.12.1",
|
"version": "8.11.3",
|
||||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz",
|
"resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.11.3.tgz",
|
||||||
"integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==",
|
"integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"acorn": "bin/acorn"
|
"acorn": "bin/acorn"
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
"name": "oxygen-ui",
|
"name": "oxygen-ui",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "1.0.2",
|
"version": "1.0.1-SNAPSHOT",
|
||||||
"description": "Oxygen Toolbox browser version",
|
"description": "Oxygen Toolbox browser version",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "FatttSnake",
|
"name": "FatttSnake",
|
||||||
"email": "fatttsnake@fatweb.top",
|
"email": "fatttsnake@fatweb.top",
|
||||||
"url": "https://fatweb.top"
|
"url": "https://fatweb.top"
|
||||||
|
|||||||
@@ -78,7 +78,6 @@
|
|||||||
.author {
|
.author {
|
||||||
display: flex;
|
display: flex;
|
||||||
margin-top: auto;
|
margin-top: auto;
|
||||||
padding-top: 8px;
|
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
justify-content: end;
|
justify-content: end;
|
||||||
padding-bottom: 10px;
|
padding-bottom: 10px;
|
||||||
|
|||||||
@@ -38,7 +38,6 @@
|
|||||||
opacity: 0.6;
|
opacity: 0.6;
|
||||||
box-shadow: 2px 2px 10px 0 rgba(0,0,0,0.2);
|
box-shadow: 2px 2px 10px 0 rgba(0,0,0,0.2);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
z-index: 1000;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,6 @@
|
|||||||
opacity: 0.6;
|
opacity: 0.6;
|
||||||
box-shadow: 2px 2px 10px 0 rgba(0,0,0,0.2);
|
box-shadow: 2px 2px 10px 0 rgba(0,0,0,0.2);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
z-index: 1000;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
.root-content {
|
.root-content {
|
||||||
position: relative;
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
> .card-box, > div {
|
> .card-box, > div {
|
||||||
width: 180px;
|
width: 180px;
|
||||||
min-height: 290px;
|
height: 290px;
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,7 +102,7 @@
|
|||||||
|
|
||||||
> .card-box, > div {
|
> .card-box, > div {
|
||||||
width: 180px;
|
width: 180px;
|
||||||
min-height: 290px;
|
height: 290px;
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
|
|
||||||
> div {
|
> div {
|
||||||
width: 180px;
|
width: 180px;
|
||||||
min-height: 290px;
|
height: 290px;
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -70,7 +70,7 @@
|
|||||||
|
|
||||||
> div {
|
> div {
|
||||||
width: 180px;
|
width: 180px;
|
||||||
min-height: 290px;
|
height: 290px;
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,31 +36,6 @@ export const createATA = async (): Promise<TypeHelper> => {
|
|||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||||
const ts = await import('https://esm.sh/typescript@5.3.3')
|
const ts = await import('https://esm.sh/typescript@5.3.3')
|
||||||
|
|
||||||
const maxConcurrentRequests = 50
|
|
||||||
let activeRequests = 0
|
|
||||||
const requestQueue: Array<() => void> = []
|
|
||||||
const fetchWithQueue = (input: RequestInfo | URL, init?: RequestInit | undefined) =>
|
|
||||||
new Promise<Response>((resolve, reject) => {
|
|
||||||
const attemptRequest = () => {
|
|
||||||
if (activeRequests < maxConcurrentRequests) {
|
|
||||||
activeRequests++
|
|
||||||
fetch(input, init)
|
|
||||||
.then((response) => resolve(response))
|
|
||||||
.catch((error) => reject(error))
|
|
||||||
.finally(() => {
|
|
||||||
activeRequests--
|
|
||||||
if (requestQueue.length > 0) {
|
|
||||||
requestQueue.shift()?.()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
requestQueue.push(attemptRequest)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
attemptRequest()
|
|
||||||
})
|
|
||||||
|
|
||||||
const ata = setupTypeAcquisition({
|
const ata = setupTypeAcquisition({
|
||||||
projectName: 'monaco-ts',
|
projectName: 'monaco-ts',
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||||
@@ -68,7 +43,7 @@ export const createATA = async (): Promise<TypeHelper> => {
|
|||||||
logger: console,
|
logger: console,
|
||||||
fetcher: (input, init) => {
|
fetcher: (input, init) => {
|
||||||
try {
|
try {
|
||||||
return fetchWithQueue(input, init)
|
return fetch(input, init)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching data:', error)
|
console.error('Error fetching data:', error)
|
||||||
}
|
}
|
||||||
@@ -117,7 +92,6 @@ export const createATA = async (): Promise<TypeHelper> => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-misused-promises
|
|
||||||
acquireType,
|
acquireType,
|
||||||
addListener,
|
addListener,
|
||||||
removeListener,
|
removeListener,
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ export const useEditor = () => {
|
|||||||
const selection = input.options ? input.options.selection : null
|
const selection = input.options ? input.options.selection : null
|
||||||
if (selection) {
|
if (selection) {
|
||||||
if (
|
if (
|
||||||
typeof selection?.endLineNumber === 'number' &&
|
typeof selection.endLineNumber === 'number' &&
|
||||||
typeof selection?.endColumn === 'number'
|
typeof selection.endColumn === 'number'
|
||||||
) {
|
) {
|
||||||
editor.setSelection(selection)
|
editor.setSelection(selection)
|
||||||
editor.revealRangeInCenter(selection, ScrollType.Immediate)
|
editor.revealRangeInCenter(selection, ScrollType.Immediate)
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ const Preview = ({
|
|||||||
Compiler.compile(files, importMap, entryPoint)
|
Compiler.compile(files, importMap, entryPoint)
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
setCompiledCode(
|
setCompiledCode(
|
||||||
`(()=>{${preExpansionCode}})();\n(()=>{${result.outputFiles[0].text}})();\n(()=>{${postExpansionCode}})();`
|
`${preExpansionCode}\n${result.outputFiles[0].text}\n${postExpansionCode}`
|
||||||
)
|
)
|
||||||
setErrorMsg('')
|
setErrorMsg('')
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import MonacoEditor from '@monaco-editor/react'
|
|||||||
import { Loader } from 'esbuild-wasm'
|
import { Loader } from 'esbuild-wasm'
|
||||||
import '@/components/Playground/Output/Transform/transform.scss'
|
import '@/components/Playground/Output/Transform/transform.scss'
|
||||||
import { IFile, ITheme } from '@/components/Playground/shared'
|
import { IFile, ITheme } from '@/components/Playground/shared'
|
||||||
import { cssToJsFromFile, jsonToJsFromFile } from '@/components/Playground/files'
|
import { cssToJs, jsonToJs, addReactImport } from '@/components/Playground/files'
|
||||||
import Compiler from '@/components/Playground/compiler'
|
import Compiler from '@/components/Playground/compiler'
|
||||||
import { MonacoEditorConfig } from '@/components/Playground/CodeEditor/Editor/monacoConfig'
|
import { MonacoEditorConfig } from '@/components/Playground/CodeEditor/Editor/monacoConfig'
|
||||||
|
|
||||||
@@ -16,7 +16,12 @@ const Transform = ({ file, theme }: OutputProps) => {
|
|||||||
const [errorMsg, setErrorMsg] = useState('')
|
const [errorMsg, setErrorMsg] = useState('')
|
||||||
|
|
||||||
const compile = (code: string, loader: Loader) => {
|
const compile = (code: string, loader: Loader) => {
|
||||||
Compiler?.transform(code, loader)
|
let _code = code
|
||||||
|
if (['jsx', 'tsx'].includes(loader)) {
|
||||||
|
_code = addReactImport(code)
|
||||||
|
}
|
||||||
|
|
||||||
|
Compiler?.transform(_code, loader)
|
||||||
.then((value) => {
|
.then((value) => {
|
||||||
setCompiledCode(value.code)
|
setCompiledCode(value.code)
|
||||||
setErrorMsg('')
|
setErrorMsg('')
|
||||||
@@ -39,10 +44,10 @@ const Transform = ({ file, theme }: OutputProps) => {
|
|||||||
compile(code, 'jsx')
|
compile(code, 'jsx')
|
||||||
break
|
break
|
||||||
case 'css':
|
case 'css':
|
||||||
setCompiledCode(cssToJsFromFile(file))
|
setCompiledCode(cssToJs(file))
|
||||||
break
|
break
|
||||||
case 'json':
|
case 'json':
|
||||||
setCompiledCode(jsonToJsFromFile(file))
|
setCompiledCode(jsonToJs(file))
|
||||||
break
|
break
|
||||||
case 'xml':
|
case 'xml':
|
||||||
setCompiledCode(code)
|
setCompiledCode(code)
|
||||||
|
|||||||
@@ -1,22 +1,8 @@
|
|||||||
import esbuild, {
|
import esbuild, { Loader, OnLoadArgs, Plugin, PluginBuild } from 'esbuild-wasm'
|
||||||
Loader,
|
|
||||||
OnLoadArgs,
|
|
||||||
OnLoadResult,
|
|
||||||
OnResolveArgs,
|
|
||||||
OnResolveResult,
|
|
||||||
Plugin,
|
|
||||||
PluginBuild
|
|
||||||
} from 'esbuild-wasm'
|
|
||||||
import localforage from 'localforage'
|
import localforage from 'localforage'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import { IFile, IFiles, IImportMap } from '@/components/Playground/shared'
|
import { IFiles, IImportMap } from '@/components/Playground/shared'
|
||||||
import {
|
import { cssToJs, jsonToJs, addReactImport } from '@/components/Playground/files'
|
||||||
addReactImport,
|
|
||||||
cssToJs,
|
|
||||||
cssToJsFromFile,
|
|
||||||
jsonToJs,
|
|
||||||
jsonToJsFromFile
|
|
||||||
} from '@/components/Playground/files'
|
|
||||||
|
|
||||||
class Compiler {
|
class Compiler {
|
||||||
private init = false
|
private init = false
|
||||||
@@ -40,273 +26,198 @@ class Compiler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private waitInit = async () => {
|
transform = (code: string, loader: Loader) =>
|
||||||
if (!this.init) {
|
new Promise<void>((resolve) => {
|
||||||
await new Promise<void>((resolve) => {
|
if (this.init) {
|
||||||
const checkInit = () => {
|
resolve()
|
||||||
if (this.init) {
|
return
|
||||||
resolve()
|
}
|
||||||
} else {
|
const timer = setInterval(() => {
|
||||||
setTimeout(checkInit, 100)
|
if (this.init) {
|
||||||
}
|
clearInterval(timer)
|
||||||
|
resolve()
|
||||||
}
|
}
|
||||||
checkInit()
|
}, 100)
|
||||||
|
}).then(() => {
|
||||||
|
return esbuild.transform(code, { loader })
|
||||||
|
})
|
||||||
|
|
||||||
|
compile = (files: IFiles, importMap: IImportMap, entryPoint: string) =>
|
||||||
|
new Promise<void>((resolve) => {
|
||||||
|
if (this.init) {
|
||||||
|
resolve()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const timer = setInterval(() => {
|
||||||
|
if (this.init) {
|
||||||
|
clearInterval(timer)
|
||||||
|
resolve()
|
||||||
|
}
|
||||||
|
}, 100)
|
||||||
|
}).then(() => {
|
||||||
|
return esbuild.build({
|
||||||
|
bundle: true,
|
||||||
|
entryPoints: [entryPoint],
|
||||||
|
format: 'esm',
|
||||||
|
metafile: true,
|
||||||
|
write: false,
|
||||||
|
plugins: [this.fileResolverPlugin(files, importMap, entryPoint)]
|
||||||
})
|
})
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
transform = async (code: string, loader: Loader) => {
|
|
||||||
await this.waitInit()
|
|
||||||
return esbuild.transform(code, { loader, target: 'es2015' })
|
|
||||||
}
|
|
||||||
|
|
||||||
compile = async (files: IFiles, importMap: IImportMap, entryPoint: string) => {
|
|
||||||
await this.waitInit()
|
|
||||||
return esbuild.build({
|
|
||||||
bundle: true,
|
|
||||||
entryPoints: [entryPoint],
|
|
||||||
format: 'esm',
|
|
||||||
target: 'es2015',
|
|
||||||
metafile: true,
|
|
||||||
write: false,
|
|
||||||
plugins: [this.fileResolverPlugin(files, importMap)]
|
|
||||||
})
|
})
|
||||||
}
|
|
||||||
|
|
||||||
compileCss = async (cssCode: string, basePath: string) => {
|
|
||||||
await this.waitInit()
|
|
||||||
return esbuild.build({
|
|
||||||
bundle: true,
|
|
||||||
entryPoints: [basePath],
|
|
||||||
write: false,
|
|
||||||
plugins: [this.cssCodeResolverPlugin(cssCode, basePath)]
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
stop = () => {
|
stop = () => {
|
||||||
void esbuild.stop()
|
void esbuild.stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fileResolverPlugin = (files: IFiles, importMap: IImportMap): Plugin => ({
|
private fileResolverPlugin = (
|
||||||
name: 'file-resolver-plugin',
|
files: IFiles,
|
||||||
setup: (build: PluginBuild) => {
|
importMap: IImportMap,
|
||||||
build.onResolve({ filter: /.*/ }, (args: OnResolveArgs): OnResolveResult => {
|
entryPoint: string
|
||||||
if (args.kind === 'entry-point') {
|
): Plugin => {
|
||||||
return {
|
return {
|
||||||
namespace: 'oxygen',
|
name: 'file-resolver-plugin',
|
||||||
path: args.path
|
setup: (build: PluginBuild) => {
|
||||||
}
|
build.onResolve({ filter: /.*/ }, (args: esbuild.OnResolveArgs) => {
|
||||||
}
|
if (entryPoint === args.path) {
|
||||||
if (/^https?:\/\/.*/.test(args.path)) {
|
|
||||||
return {
|
|
||||||
namespace: 'default',
|
|
||||||
path: args.path
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
args.path.startsWith('./') &&
|
|
||||||
(!args.resolveDir.length || args.resolveDir in files)
|
|
||||||
) {
|
|
||||||
const suffix = ['', '.tsx', '.jsx', '.ts', '.js'].find((suffix) => {
|
|
||||||
return files[`${args.path.substring(2)}${suffix}`]
|
|
||||||
})
|
|
||||||
if (suffix !== undefined) {
|
|
||||||
return {
|
return {
|
||||||
namespace: 'oxygen',
|
namespace: 'OxygenToolbox',
|
||||||
path: `${args.path.substring(2)}${suffix}`
|
path: args.path
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
if (args.path.startsWith('./') && files[args.path.substring(2)]) {
|
||||||
if (['./', '../', '/'].some((prefix) => args.path.startsWith(prefix))) {
|
|
||||||
return {
|
|
||||||
namespace: 'default',
|
|
||||||
path: new URL(args.path, args.resolveDir.substring(1)).href
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let path = importMap[args.path]
|
|
||||||
let tempPath = args.path
|
|
||||||
while (!path && tempPath.includes('/')) {
|
|
||||||
tempPath = tempPath.substring(0, tempPath.lastIndexOf('/'))
|
|
||||||
if (importMap[tempPath]) {
|
|
||||||
const suffix = args.path.replace(tempPath, '')
|
|
||||||
const importUrl = new URL(importMap[tempPath])
|
|
||||||
path = `${importUrl.origin}${importUrl.pathname}${suffix}${importUrl.search}`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!path) {
|
|
||||||
throw Error(`Import '${args.path}' not found in Import Map`)
|
|
||||||
}
|
|
||||||
const pathUrl = new URL(path)
|
|
||||||
const externals = pathUrl.searchParams.get('external')?.split(',') ?? []
|
|
||||||
Object.keys(importMap).forEach((item) => {
|
|
||||||
if (!(item in externals)) {
|
|
||||||
externals.push(item)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
pathUrl.searchParams.set('external', externals.join(','))
|
|
||||||
return {
|
|
||||||
namespace: 'default',
|
|
||||||
path: pathUrl.href
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
build.onLoad({ filter: /.*\.css$/ }, (args: OnLoadArgs): OnLoadResult => {
|
|
||||||
const contents = cssToJsFromFile(files[args.path])
|
|
||||||
return {
|
|
||||||
loader: 'js',
|
|
||||||
contents
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
build.onLoad({ filter: /.*\.json$/ }, (args: OnLoadArgs): OnLoadResult => {
|
|
||||||
const contents = jsonToJsFromFile(files[args.path])
|
|
||||||
return {
|
|
||||||
loader: 'js',
|
|
||||||
contents
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
build.onLoad(
|
|
||||||
{ namespace: 'oxygen', filter: /.*/ },
|
|
||||||
(args: OnLoadArgs): OnLoadResult | undefined => {
|
|
||||||
let file: IFile | undefined
|
|
||||||
|
|
||||||
void ['', '.tsx', '.jsx', '.ts', '.js'].forEach((suffix) => {
|
|
||||||
file = file || files[`${args.path}${suffix}`]
|
|
||||||
})
|
|
||||||
if (file) {
|
|
||||||
return {
|
return {
|
||||||
loader: (() => {
|
namespace: 'OxygenToolbox',
|
||||||
switch (file.language) {
|
path: args.path.substring(2)
|
||||||
case 'javascript':
|
|
||||||
return 'jsx'
|
|
||||||
default:
|
|
||||||
return 'tsx'
|
|
||||||
}
|
|
||||||
})(),
|
|
||||||
contents: addReactImport(file.value)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
if (args.path.startsWith('./') && files[`${args.path.substring(2)}.tsx`]) {
|
||||||
)
|
return {
|
||||||
|
namespace: 'OxygenToolbox',
|
||||||
build.onLoad({ filter: /.*/ }, async (args: OnLoadArgs): Promise<OnLoadResult> => {
|
path: `${args.path.substring(2)}.tsx`
|
||||||
const cached = await this.fileCache.getItem<OnLoadResult>(args.path)
|
|
||||||
|
|
||||||
if (cached) {
|
|
||||||
return cached
|
|
||||||
}
|
|
||||||
|
|
||||||
const axiosResponse = await axios.get<ArrayBuffer>(args.path, {
|
|
||||||
responseType: 'arraybuffer'
|
|
||||||
})
|
|
||||||
const contentType = axiosResponse.headers['content-type'] as string
|
|
||||||
const utf8Decoder = new TextDecoder('utf-8')
|
|
||||||
const result: OnLoadResult = {
|
|
||||||
loader: (() => {
|
|
||||||
if (
|
|
||||||
contentType.includes('javascript') ||
|
|
||||||
contentType.includes('css') ||
|
|
||||||
contentType.includes('json')
|
|
||||||
) {
|
|
||||||
return 'js'
|
|
||||||
}
|
}
|
||||||
return 'base64'
|
}
|
||||||
})(),
|
if (args.path.startsWith('./') && files[`${args.path.substring(2)}.jsx`]) {
|
||||||
contents: await (async () => {
|
return {
|
||||||
if (contentType.includes('css')) {
|
namespace: 'OxygenToolbox',
|
||||||
return cssToJs(
|
path: `${args.path.substring(2)}.jsx`
|
||||||
(
|
|
||||||
await this.compileCss(
|
|
||||||
utf8Decoder.decode(axiosResponse.data),
|
|
||||||
args.path
|
|
||||||
)
|
|
||||||
).outputFiles[0].text
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
if (contentType.includes('json')) {
|
}
|
||||||
return jsonToJs(utf8Decoder.decode(axiosResponse.data))
|
if (args.path.startsWith('./') && files[`${args.path.substring(2)}.ts`]) {
|
||||||
|
return {
|
||||||
|
namespace: 'OxygenToolbox',
|
||||||
|
path: `${args.path.substring(2)}.ts`
|
||||||
}
|
}
|
||||||
return new Uint8Array(axiosResponse.data)
|
}
|
||||||
})(),
|
if (args.path.startsWith('./') && files[`${args.path.substring(2)}.js`]) {
|
||||||
resolveDir: args.path
|
return {
|
||||||
}
|
namespace: 'OxygenToolbox',
|
||||||
|
path: `${args.path.substring(2)}.js`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (/\.\/.*\.css/.test(args.path) && !args.resolveDir) {
|
||||||
|
throw Error(`Css '${args.path}' not found`)
|
||||||
|
}
|
||||||
|
|
||||||
await this.fileCache.setItem(args.path, result)
|
if (/^https?:\/\/.*/.test(args.path)) {
|
||||||
|
return {
|
||||||
|
namespace: 'default',
|
||||||
|
path: args.path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return result
|
if (
|
||||||
})
|
args.path.includes('./') ||
|
||||||
}
|
args.path.includes('../') ||
|
||||||
})
|
args.path.startsWith('/')
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
namespace: 'default',
|
||||||
|
path: new URL(args.path, args.resolveDir.substring(1)).href
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const path = importMap.imports[args.path]
|
||||||
|
|
||||||
|
if (!path) {
|
||||||
|
throw Error(`Import '${args.path}' not found in Import Map`)
|
||||||
|
}
|
||||||
|
|
||||||
private cssCodeResolverPlugin = (cssCode: string, basePath: string): Plugin => ({
|
|
||||||
name: 'css-code-resolver-plugin',
|
|
||||||
setup: (build: PluginBuild) => {
|
|
||||||
build.onResolve({ filter: /.*/ }, (args: OnResolveArgs): OnResolveResult => {
|
|
||||||
if (args.kind === 'entry-point') {
|
|
||||||
return {
|
return {
|
||||||
namespace: 'default',
|
namespace: 'default',
|
||||||
path: basePath
|
path
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return {
|
|
||||||
namespace: 'default',
|
|
||||||
path: args.resolveDir.length
|
|
||||||
? new URL(args.path, args.resolveDir.substring(1)).href
|
|
||||||
: new URL(args.path, basePath).href
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
build.onLoad({ filter: /.*/ }, async (args: OnLoadArgs): Promise<OnLoadResult> => {
|
|
||||||
if (args.path === basePath) {
|
|
||||||
return {
|
|
||||||
loader: 'css',
|
|
||||||
contents: cssCode,
|
|
||||||
resolveDir: basePath
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const cached = await this.fileCache.getItem<OnLoadResult>(args.path)
|
|
||||||
|
|
||||||
if (cached) {
|
|
||||||
return cached
|
|
||||||
}
|
|
||||||
|
|
||||||
const axiosResponse = await axios.get<ArrayBuffer>(args.path, {
|
|
||||||
responseType: 'arraybuffer'
|
|
||||||
})
|
})
|
||||||
const contentType = axiosResponse.headers['content-type'] as string
|
|
||||||
const utf8Decoder = new TextDecoder('utf-8')
|
|
||||||
const result: OnLoadResult = {
|
|
||||||
loader: (() => {
|
|
||||||
if (contentType.includes('css')) {
|
|
||||||
return 'js'
|
|
||||||
}
|
|
||||||
return 'dataurl'
|
|
||||||
})(),
|
|
||||||
contents: await (async () => {
|
|
||||||
if (contentType.includes('css')) {
|
|
||||||
return cssToJs(
|
|
||||||
(
|
|
||||||
await this.compileCss(
|
|
||||||
utf8Decoder.decode(axiosResponse.data),
|
|
||||||
args.path
|
|
||||||
)
|
|
||||||
).outputFiles[0].text
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return new Uint8Array(axiosResponse.data)
|
|
||||||
})(),
|
|
||||||
resolveDir: args.path
|
|
||||||
}
|
|
||||||
|
|
||||||
await this.fileCache.setItem(args.path, result)
|
build.onLoad({ filter: /.*\.css$/ }, (args: OnLoadArgs) => {
|
||||||
|
const contents = cssToJs(files[args.path])
|
||||||
|
return {
|
||||||
|
loader: 'js',
|
||||||
|
contents
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
return result
|
build.onLoad({ filter: /.*\.json$/ }, (args: OnLoadArgs) => {
|
||||||
})
|
const contents = jsonToJs(files[args.path])
|
||||||
|
return {
|
||||||
|
loader: 'js',
|
||||||
|
contents
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
build.onLoad({ filter: /.*/ }, async (args: OnLoadArgs) => {
|
||||||
|
if (entryPoint === args.path) {
|
||||||
|
return {
|
||||||
|
loader: 'tsx',
|
||||||
|
contents: addReactImport(files[entryPoint].value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (files[args.path]) {
|
||||||
|
const contents = addReactImport(files[args.path].value)
|
||||||
|
if (args.path.endsWith('.jsx')) {
|
||||||
|
return {
|
||||||
|
loader: 'jsx',
|
||||||
|
contents
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (args.path.endsWith('.ts')) {
|
||||||
|
return {
|
||||||
|
loader: 'ts',
|
||||||
|
contents
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (args.path.endsWith('.js')) {
|
||||||
|
return {
|
||||||
|
loader: 'js',
|
||||||
|
contents
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
loader: 'tsx',
|
||||||
|
contents
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const cached = await this.fileCache.getItem<esbuild.OnLoadResult>(args.path)
|
||||||
|
|
||||||
|
if (cached) {
|
||||||
|
return cached
|
||||||
|
}
|
||||||
|
|
||||||
|
const axiosResponse = await axios.get<string>(args.path)
|
||||||
|
const result: esbuild.OnLoadResult = {
|
||||||
|
loader: 'jsx',
|
||||||
|
contents: axiosResponse.data,
|
||||||
|
resolveDir: (axiosResponse.request as XMLHttpRequest).responseURL
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.fileCache.setItem(args.path, result)
|
||||||
|
|
||||||
|
return result
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default new Compiler()
|
export default new Compiler()
|
||||||
|
|||||||
@@ -83,25 +83,21 @@ export const jsToBlob = (code: string) => {
|
|||||||
return URL.createObjectURL(new Blob([code], { type: 'application/javascript' }))
|
return URL.createObjectURL(new Blob([code], { type: 'application/javascript' }))
|
||||||
}
|
}
|
||||||
|
|
||||||
export const jsonToJs = (code: string) => {
|
export const jsonToJs = (file: IFile) => {
|
||||||
return `export default ${code}`
|
return `export default ${file.value}`
|
||||||
}
|
}
|
||||||
|
|
||||||
export const jsonToJsFromFile = (file: IFile) => {
|
export const cssToJs = (file: IFile) => {
|
||||||
return jsonToJs(file.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
export const cssToJs = (code: string, fileName?: string) => {
|
|
||||||
const randomId = new Date().getTime()
|
const randomId = new Date().getTime()
|
||||||
return `(() => {
|
return `(() => {
|
||||||
let stylesheet = document.getElementById('style_${randomId}${fileName ? `_${fileName}` : ''}');
|
let stylesheet = document.getElementById('style_${randomId}_${file.name}');
|
||||||
if (!stylesheet) {
|
if (!stylesheet) {
|
||||||
stylesheet = document.createElement('style')
|
stylesheet = document.createElement('style')
|
||||||
stylesheet.setAttribute('id', 'style_${randomId}_${fileName ? `_${fileName}` : ''}')
|
stylesheet.setAttribute('id', 'style_${randomId}_${file.name}')
|
||||||
document.head.appendChild(stylesheet)
|
document.head.appendChild(stylesheet)
|
||||||
}
|
}
|
||||||
const styles = document.createTextNode(
|
const styles = document.createTextNode(
|
||||||
\`${code}\`
|
\`${file.value}\`
|
||||||
)
|
)
|
||||||
stylesheet.innerHTML = ''
|
stylesheet.innerHTML = ''
|
||||||
stylesheet.appendChild(styles)
|
stylesheet.appendChild(styles)
|
||||||
@@ -109,12 +105,8 @@ export const cssToJs = (code: string, fileName?: string) => {
|
|||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
export const cssToJsFromFile = (file: IFile) => {
|
|
||||||
return cssToJs(file.value, file.name)
|
|
||||||
}
|
|
||||||
|
|
||||||
export const addReactImport = (code: string) => {
|
export const addReactImport = (code: string) => {
|
||||||
if (!/^\s*import\s+React\s+/g.test(code)) {
|
if (!/import\s+React/g.test(code)) {
|
||||||
return `import React from 'react';\n${code}`
|
return `import React from 'react';\n${code}`
|
||||||
}
|
}
|
||||||
return code
|
return code
|
||||||
@@ -126,12 +118,18 @@ export const tsconfigJsonDiagnosticsOptions: DiagnosticsOptions = {
|
|||||||
{
|
{
|
||||||
uri: 'tsconfig.json',
|
uri: 'tsconfig.json',
|
||||||
fileMatch: ['tsconfig.json'],
|
fileMatch: ['tsconfig.json'],
|
||||||
schema: tsconfigSchema
|
schema: {
|
||||||
|
type: 'object',
|
||||||
|
properties: tsconfigSchema
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
uri: 'import-map.json',
|
uri: 'import-map.json',
|
||||||
fileMatch: ['import-map.json'],
|
fileMatch: ['import-map.json'],
|
||||||
schema: importMapSchema
|
schema: {
|
||||||
|
type: 'object',
|
||||||
|
properties: importMapSchema
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
{
|
{
|
||||||
|
"imports": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": {"type": "string"}
|
"description": "Import map"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -34,7 +34,7 @@ const Playground = ({
|
|||||||
try {
|
try {
|
||||||
setImportMap(JSON.parse(importMapRaw) as IImportMap)
|
setImportMap(JSON.parse(importMapRaw) as IImportMap)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
setImportMap({})
|
setImportMap({ imports: {} })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!tsconfig) {
|
if (!tsconfig) {
|
||||||
|
|||||||
@@ -14,7 +14,20 @@ export interface IFiles {
|
|||||||
[key: string]: IFile
|
[key: string]: IFile
|
||||||
}
|
}
|
||||||
|
|
||||||
export type IImportMap = Record<string, string>
|
export interface ITemplate {
|
||||||
|
name: string
|
||||||
|
tsconfig: ITsconfig
|
||||||
|
importMap: IImportMap
|
||||||
|
files: IFiles
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ITemplates {
|
||||||
|
[key: string]: ITemplate
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IImportMap {
|
||||||
|
imports: Record<string, string>
|
||||||
|
}
|
||||||
|
|
||||||
export interface ITsconfig {
|
export interface ITsconfig {
|
||||||
compilerOptions: CompilerOptions
|
compilerOptions: CompilerOptions
|
||||||
|
|||||||
59
src/components/Playground/templates.ts
Normal file
59
src/components/Playground/templates.ts
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
import { ITemplates } from '@/components/Playground/shared'
|
||||||
|
import { ENTRY_FILE_NAME, MAIN_FILE_NAME } from '@/components/Playground/files'
|
||||||
|
|
||||||
|
import baseTsconfig from '@/components/Playground/templates/base/tsconfig.json'
|
||||||
|
import baseImportMap from '@/components/Playground/templates/base/import-map.json'
|
||||||
|
import baseMain from '@/components/Playground/templates/base/main.tsx?raw'
|
||||||
|
import baseApp from '@/components/Playground/templates/base/App.tsx?raw'
|
||||||
|
|
||||||
|
import demoTsconfig from '@/components/Playground/templates/demo/tsconfig.json'
|
||||||
|
import demoImportMap from '@/components/Playground/templates/demo/import-map.json'
|
||||||
|
import demoMain from '@/components/Playground/templates/demo/main.tsx?raw'
|
||||||
|
import demoApp from '@/components/Playground/templates/demo/App.tsx?raw'
|
||||||
|
import demoAppCSS from '@/components/Playground/templates/demo/App.css?raw'
|
||||||
|
|
||||||
|
const templates: ITemplates = {
|
||||||
|
base: {
|
||||||
|
name: '基础',
|
||||||
|
tsconfig: baseTsconfig,
|
||||||
|
importMap: baseImportMap,
|
||||||
|
files: {
|
||||||
|
[ENTRY_FILE_NAME]: {
|
||||||
|
name: ENTRY_FILE_NAME,
|
||||||
|
language: 'typescript',
|
||||||
|
value: baseMain,
|
||||||
|
hidden: true
|
||||||
|
},
|
||||||
|
[MAIN_FILE_NAME]: {
|
||||||
|
name: MAIN_FILE_NAME,
|
||||||
|
language: 'typescript',
|
||||||
|
value: baseApp
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
demo: {
|
||||||
|
name: 'Demo',
|
||||||
|
tsconfig: demoTsconfig,
|
||||||
|
importMap: demoImportMap,
|
||||||
|
files: {
|
||||||
|
[ENTRY_FILE_NAME]: {
|
||||||
|
name: ENTRY_FILE_NAME,
|
||||||
|
language: 'typescript',
|
||||||
|
value: demoMain,
|
||||||
|
hidden: true
|
||||||
|
},
|
||||||
|
[MAIN_FILE_NAME]: {
|
||||||
|
name: MAIN_FILE_NAME,
|
||||||
|
language: 'typescript',
|
||||||
|
value: demoApp
|
||||||
|
},
|
||||||
|
['App.css']: {
|
||||||
|
name: 'App.css',
|
||||||
|
language: 'css',
|
||||||
|
value: demoAppCSS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default templates
|
||||||
5
src/components/Playground/templates/base/App.tsx
Normal file
5
src/components/Playground/templates/base/App.tsx
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
const App = () => {
|
||||||
|
return <></>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default App
|
||||||
6
src/components/Playground/templates/base/import-map.json
Normal file
6
src/components/Playground/templates/base/import-map.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"imports": {
|
||||||
|
"react": "https://esm.sh/react@18.2.0",
|
||||||
|
"react-dom/client": "https://esm.sh/react-dom@18.2.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/components/Playground/templates/base/main.tsx
Normal file
10
src/components/Playground/templates/base/main.tsx
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import ReactDOM from 'react-dom/client'
|
||||||
|
|
||||||
|
import App from './App'
|
||||||
|
|
||||||
|
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||||
|
<React.StrictMode>
|
||||||
|
<App />
|
||||||
|
</React.StrictMode>
|
||||||
|
)
|
||||||
21
src/components/Playground/templates/base/tsconfig.json
Normal file
21
src/components/Playground/templates/base/tsconfig.json
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": 7,
|
||||||
|
"useDefineForClassFields": true,
|
||||||
|
"module": 99,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"moduleResolution": 2,
|
||||||
|
"allowImportingTsExtensions": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"noEmit": true,
|
||||||
|
"jsx": 4,
|
||||||
|
"strict": true,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"noUnusedParameters": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"composite": true,
|
||||||
|
"types": ["node"],
|
||||||
|
"allowSyntheticDefaultImports": true
|
||||||
|
}
|
||||||
|
}
|
||||||
65
src/components/Playground/templates/demo/App.css
Normal file
65
src/components/Playground/templates/demo/App.css
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
:root {
|
||||||
|
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
font-weight: 400;
|
||||||
|
line-height: 1.5;
|
||||||
|
color: rgb(255 255 255 / 87%);
|
||||||
|
text-rendering: optimizelegibility;
|
||||||
|
text-size-adjust: 100%;
|
||||||
|
background-color: #242424;
|
||||||
|
color-scheme: light dark;
|
||||||
|
font-synthesis: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#root {
|
||||||
|
max-width: 1280px;
|
||||||
|
padding: 2rem;
|
||||||
|
margin: 0 auto;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
display: flex;
|
||||||
|
min-width: 320px;
|
||||||
|
min-height: 100vh;
|
||||||
|
margin: 0;
|
||||||
|
place-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 3.2em;
|
||||||
|
line-height: 1.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
padding: 0.6em 1.2em;
|
||||||
|
font-family: inherit;
|
||||||
|
font-size: 1em;
|
||||||
|
font-weight: 500;
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: #1a1a1a;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
border-radius: 8px;
|
||||||
|
transition: border-color 0.25s;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover {
|
||||||
|
border-color: #646cff;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:focus,
|
||||||
|
button:focus-visible {
|
||||||
|
outline: 4px auto -webkit-focus-ring-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: light) {
|
||||||
|
:root {
|
||||||
|
color: #213547;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
}
|
||||||
|
}
|
||||||
17
src/components/Playground/templates/demo/App.tsx
Normal file
17
src/components/Playground/templates/demo/App.tsx
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import { useState } from 'react'
|
||||||
|
import './App.css'
|
||||||
|
|
||||||
|
const App = () => {
|
||||||
|
const [count, setCount] = useState(0)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h1>Hello World</h1>
|
||||||
|
<div className="card">
|
||||||
|
<button onClick={() => setCount((count) => count + 1)}>count is {count}</button>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default App
|
||||||
6
src/components/Playground/templates/demo/import-map.json
Normal file
6
src/components/Playground/templates/demo/import-map.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"imports": {
|
||||||
|
"react": "https://esm.sh/react@18.2.0",
|
||||||
|
"react-dom/client": "https://esm.sh/react-dom@18.2.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/components/Playground/templates/demo/main.tsx
Normal file
10
src/components/Playground/templates/demo/main.tsx
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import ReactDOM from 'react-dom/client'
|
||||||
|
|
||||||
|
import App from './App'
|
||||||
|
|
||||||
|
ReactDOM.createRoot(document.getElementById('root')!).render(
|
||||||
|
<React.StrictMode>
|
||||||
|
<App />
|
||||||
|
</React.StrictMode>
|
||||||
|
)
|
||||||
21
src/components/Playground/templates/demo/tsconfig.json
Normal file
21
src/components/Playground/templates/demo/tsconfig.json
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": 7,
|
||||||
|
"useDefineForClassFields": true,
|
||||||
|
"module": 99,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"moduleResolution": 2,
|
||||||
|
"allowImportingTsExtensions": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"noEmit": true,
|
||||||
|
"jsx": 4,
|
||||||
|
"strict": true,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"noUnusedParameters": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"composite": true,
|
||||||
|
"types": ["node"],
|
||||||
|
"allowSyntheticDefaultImports": true
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -169,18 +169,18 @@ const Base = () => {
|
|||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
width: '14em',
|
width: '12em',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
render: (_, record) => (
|
render: (_, record) => (
|
||||||
<>
|
<>
|
||||||
<AntdSpace size={'middle'}>
|
<AntdSpace size={'middle'}>
|
||||||
{!Object.keys(hasEdited).length && (
|
{!record.compiled && !Object.keys(hasEdited).length && (
|
||||||
<Permission operationCode={['system:tool:modify:base']}>
|
<Permission operationCode={['system:tool:modify:base']}>
|
||||||
<a
|
<a
|
||||||
style={{ color: COLOR_PRODUCTION }}
|
style={{ color: COLOR_PRODUCTION }}
|
||||||
onClick={handleOnCompileBtnClick(record)}
|
onClick={handleOnCompileBtnClick(record)}
|
||||||
>
|
>
|
||||||
{record.compiled ? '重新编译' : '编译'}
|
编译
|
||||||
</a>
|
</a>
|
||||||
</Permission>
|
</Permission>
|
||||||
)}
|
)}
|
||||||
@@ -304,10 +304,7 @@ const Base = () => {
|
|||||||
![
|
![
|
||||||
IMPORT_MAP_FILE_NAME,
|
IMPORT_MAP_FILE_NAME,
|
||||||
TS_CONFIG_FILE_NAME
|
TS_CONFIG_FILE_NAME
|
||||||
].includes(value) &&
|
].includes(value)
|
||||||
!value.endsWith('.d.ts') &&
|
|
||||||
!value.endsWith('.css') &&
|
|
||||||
!value.endsWith('.json')
|
|
||||||
)
|
)
|
||||||
.map((value) => ({ value, label: value }))}
|
.map((value) => ({ value, label: value }))}
|
||||||
placeholder={'请选择入口文件'}
|
placeholder={'请选择入口文件'}
|
||||||
@@ -1100,7 +1097,7 @@ const Base = () => {
|
|||||||
<Playground.CodeEditor
|
<Playground.CodeEditor
|
||||||
files={editingFiles[editingBaseId]}
|
files={editingFiles[editingBaseId]}
|
||||||
selectedFileName={editingFileName}
|
selectedFileName={editingFileName}
|
||||||
onSelectedFileChange={setEditingFileName}
|
onSelectedFileChange={() => {}}
|
||||||
onChangeFileContent={handleOnChangeFileContent}
|
onChangeFileContent={handleOnChangeFileContent}
|
||||||
showFileSelector={false}
|
showFileSelector={false}
|
||||||
tsconfig={tsconfig}
|
tsconfig={tsconfig}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ const Execute = () => {
|
|||||||
const output = result.outputFiles[0].text
|
const output = result.outputFiles[0].text
|
||||||
setCompiledCode('')
|
setCompiledCode('')
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setCompiledCode(`(() => {${output}})();\n(() => {${baseDist}})();`)
|
setCompiledCode(`${output}\n${baseDist}`)
|
||||||
}, 100)
|
}, 100)
|
||||||
})
|
})
|
||||||
.catch((reason) => {
|
.catch((reason) => {
|
||||||
|
|||||||
@@ -1044,7 +1044,7 @@ const Template = () => {
|
|||||||
<Playground.CodeEditor
|
<Playground.CodeEditor
|
||||||
files={editingFiles[editingTemplateId]}
|
files={editingFiles[editingTemplateId]}
|
||||||
selectedFileName={editingFileName}
|
selectedFileName={editingFileName}
|
||||||
onSelectedFileChange={setEditingFileName}
|
onSelectedFileChange={() => {}}
|
||||||
onChangeFileContent={handleOnChangeFileContent}
|
onChangeFileContent={handleOnChangeFileContent}
|
||||||
showFileSelector={false}
|
showFileSelector={false}
|
||||||
tsconfig={tsconfig}
|
tsconfig={tsconfig}
|
||||||
|
|||||||
@@ -219,7 +219,7 @@ const Tools = () => {
|
|||||||
<AntdForm.Item
|
<AntdForm.Item
|
||||||
name={'pass'}
|
name={'pass'}
|
||||||
style={{ marginTop: 10 }}
|
style={{ marginTop: 10 }}
|
||||||
rules={[{ required: true, message: '请选择审核结果' }]}
|
rules={[{ required: true }]}
|
||||||
>
|
>
|
||||||
<AntdRadio.Group>
|
<AntdRadio.Group>
|
||||||
<AntdRadio value={true}>通过</AntdRadio>
|
<AntdRadio value={true}>通过</AntdRadio>
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ const Create = () => {
|
|||||||
.compile(files, importMap, template.entryPoint)
|
.compile(files, importMap, template.entryPoint)
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
const output = result.outputFiles[0].text
|
const output = result.outputFiles[0].text
|
||||||
setCompiledCode(`(() => {${output}})();\n(() => {${baseDist}})();`)
|
setCompiledCode(`${output}\n${baseDist}`)
|
||||||
})
|
})
|
||||||
.catch((reason) => {
|
.catch((reason) => {
|
||||||
void message.error(`编译失败:${reason}`)
|
void message.error(`编译失败:${reason}`)
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ const View = () => {
|
|||||||
const output = result.outputFiles[0].text
|
const output = result.outputFiles[0].text
|
||||||
setCompiledCode('')
|
setCompiledCode('')
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setCompiledCode(`(() => {${output}})();\n(() => {${baseDist}})();`)
|
setCompiledCode(`${output}\n${baseDist}`)
|
||||||
}, 100)
|
}, 100)
|
||||||
})
|
})
|
||||||
.catch((reason) => {
|
.catch((reason) => {
|
||||||
@@ -49,7 +49,7 @@ const View = () => {
|
|||||||
const dist = base64ToStr(toolVo.dist.data!)
|
const dist = base64ToStr(toolVo.dist.data!)
|
||||||
setCompiledCode('')
|
setCompiledCode('')
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
setCompiledCode(`(() => {${dist}})();\n(() => {${baseDist}})();`)
|
setCompiledCode(`${dist}\n${baseDist}`)
|
||||||
}, 100)
|
}, 100)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
void message.error('载入工具失败')
|
void message.error('载入工具失败')
|
||||||
|
|||||||
Reference in New Issue
Block a user