Compare commits
29 Commits
85f3d38faa
...
release/1.
| Author | SHA1 | Date | |
|---|---|---|---|
|
ebaa4d8851
|
|||
|
86cee4eaa5
|
|||
|
768f9bce0f
|
|||
|
eb4107a7fd
|
|||
|
264534f479
|
|||
|
c2f6b5d49e
|
|||
|
e97baaad8a
|
|||
|
a0da95fd8b
|
|||
|
d5037dc14e
|
|||
|
e17fcdb401
|
|||
|
77551804f7
|
|||
|
fc18927116
|
|||
|
c557311dbc
|
|||
|
fd4c3750fb
|
|||
|
9ca2ec8859
|
|||
|
4711f7892f
|
|||
|
254c5ab48f
|
|||
|
89cf48e449
|
|||
|
d6d5cd927c
|
|||
|
72ab390756
|
|||
|
92115d3faa
|
|||
|
21eaee22f7
|
|||
|
44e32ce4f7
|
|||
|
6302ec6ab3
|
|||
|
1c45e7250b
|
|||
|
51ee15749e
|
|||
|
bba90c6783
|
|||
|
842e167f8c
|
|||
|
d61888d2bf
|
@@ -24,6 +24,7 @@ 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 and later versions)
|
||||||
|
|
||||||
# Related projects
|
# Related projects
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
# 环境要求
|
# 环境要求
|
||||||
|
|
||||||
- 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.0-SNAPSHOT",
|
"version": "1.0.1-SNAPSHOT",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "oxygen-ui",
|
"name": "oxygen-ui",
|
||||||
"version": "1.0.0-SNAPSHOT",
|
"version": "1.0.1-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.11.3",
|
"version": "8.12.1",
|
||||||
"resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.11.3.tgz",
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz",
|
||||||
"integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==",
|
"integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"bin": {
|
"bin": {
|
||||||
"acorn": "bin/acorn"
|
"acorn": "bin/acorn"
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"name": "oxygen-ui",
|
"name": "oxygen-ui",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "1.0.0-SNAPSHOT",
|
"version": "1.0.1",
|
||||||
"description": "Oxygen Toolbox browser version",
|
"description": "Oxygen Toolbox browser version",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "FatttSnake",
|
"name": "FatttSnake",
|
||||||
|
|||||||
@@ -38,6 +38,7 @@
|
|||||||
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,6 +38,7 @@
|
|||||||
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,6 +6,7 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
|
|
||||||
.root-content {
|
.root-content {
|
||||||
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,31 @@ 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
|
||||||
@@ -43,7 +68,7 @@ export const createATA = async (): Promise<TypeHelper> => {
|
|||||||
logger: console,
|
logger: console,
|
||||||
fetcher: (input, init) => {
|
fetcher: (input, init) => {
|
||||||
try {
|
try {
|
||||||
return fetch(input, init)
|
return fetchWithQueue(input, init)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching data:', error)
|
console.error('Error fetching data:', error)
|
||||||
}
|
}
|
||||||
@@ -92,6 +117,7 @@ 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 { cssToJs, jsonToJs, addReactImport } from '@/components/Playground/files'
|
import { cssToJsFromFile, jsonToJsFromFile } 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,12 +16,7 @@ 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) => {
|
||||||
let _code = code
|
Compiler?.transform(code, loader)
|
||||||
if (['jsx', 'tsx'].includes(loader)) {
|
|
||||||
_code = addReactImport(code)
|
|
||||||
}
|
|
||||||
|
|
||||||
Compiler?.transform(_code, loader)
|
|
||||||
.then((value) => {
|
.then((value) => {
|
||||||
setCompiledCode(value.code)
|
setCompiledCode(value.code)
|
||||||
setErrorMsg('')
|
setErrorMsg('')
|
||||||
@@ -44,10 +39,10 @@ const Transform = ({ file, theme }: OutputProps) => {
|
|||||||
compile(code, 'jsx')
|
compile(code, 'jsx')
|
||||||
break
|
break
|
||||||
case 'css':
|
case 'css':
|
||||||
setCompiledCode(cssToJs(file))
|
setCompiledCode(cssToJsFromFile(file))
|
||||||
break
|
break
|
||||||
case 'json':
|
case 'json':
|
||||||
setCompiledCode(jsonToJs(file))
|
setCompiledCode(jsonToJsFromFile(file))
|
||||||
break
|
break
|
||||||
case 'xml':
|
case 'xml':
|
||||||
setCompiledCode(code)
|
setCompiledCode(code)
|
||||||
|
|||||||
@@ -1,8 +1,22 @@
|
|||||||
import esbuild, { Loader, OnLoadArgs, Plugin, PluginBuild } from 'esbuild-wasm'
|
import esbuild, {
|
||||||
|
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 { IFiles, IImportMap } from '@/components/Playground/shared'
|
import { IFile, IFiles, IImportMap } from '@/components/Playground/shared'
|
||||||
import { cssToJs, jsonToJs, addReactImport } from '@/components/Playground/files'
|
import {
|
||||||
|
addReactImport,
|
||||||
|
cssToJs,
|
||||||
|
cssToJsFromFile,
|
||||||
|
jsonToJs,
|
||||||
|
jsonToJsFromFile
|
||||||
|
} from '@/components/Playground/files'
|
||||||
|
|
||||||
class Compiler {
|
class Compiler {
|
||||||
private init = false
|
private init = false
|
||||||
@@ -26,98 +40,62 @@ class Compiler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
transform = (code: string, loader: Loader) =>
|
private waitInit = async () => {
|
||||||
new Promise<void>((resolve) => {
|
if (!this.init) {
|
||||||
|
await new Promise<void>((resolve) => {
|
||||||
|
const checkInit = () => {
|
||||||
if (this.init) {
|
if (this.init) {
|
||||||
resolve()
|
resolve()
|
||||||
return
|
} else {
|
||||||
|
setTimeout(checkInit, 100)
|
||||||
}
|
}
|
||||||
const timer = setInterval(() => {
|
|
||||||
if (this.init) {
|
|
||||||
clearInterval(timer)
|
|
||||||
resolve()
|
|
||||||
}
|
}
|
||||||
}, 100)
|
checkInit()
|
||||||
}).then(() => {
|
|
||||||
return esbuild.transform(code, { loader })
|
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
compile = (files: IFiles, importMap: IImportMap, entryPoint: string) =>
|
transform = async (code: string, loader: Loader) => {
|
||||||
new Promise<void>((resolve) => {
|
await this.waitInit()
|
||||||
if (this.init) {
|
return esbuild.transform(code, { loader })
|
||||||
resolve()
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
const timer = setInterval(() => {
|
|
||||||
if (this.init) {
|
compile = async (files: IFiles, importMap: IImportMap, entryPoint: string) => {
|
||||||
clearInterval(timer)
|
await this.waitInit()
|
||||||
resolve()
|
|
||||||
}
|
|
||||||
}, 100)
|
|
||||||
}).then(() => {
|
|
||||||
return esbuild.build({
|
return esbuild.build({
|
||||||
bundle: true,
|
bundle: true,
|
||||||
entryPoints: [entryPoint],
|
entryPoints: [entryPoint],
|
||||||
format: 'esm',
|
format: 'esm',
|
||||||
metafile: true,
|
metafile: true,
|
||||||
write: false,
|
write: false,
|
||||||
plugins: [this.fileResolverPlugin(files, importMap, entryPoint)]
|
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 = (
|
private fileResolverPlugin = (files: IFiles, importMap: IImportMap): Plugin => ({
|
||||||
files: IFiles,
|
|
||||||
importMap: IImportMap,
|
|
||||||
entryPoint: string
|
|
||||||
): Plugin => {
|
|
||||||
return {
|
|
||||||
name: 'file-resolver-plugin',
|
name: 'file-resolver-plugin',
|
||||||
setup: (build: PluginBuild) => {
|
setup: (build: PluginBuild) => {
|
||||||
build.onResolve({ filter: /.*/ }, (args: esbuild.OnResolveArgs) => {
|
build.onResolve({ filter: /.*/ }, (args: OnResolveArgs): OnResolveResult => {
|
||||||
if (entryPoint === args.path) {
|
if (args.kind === 'entry-point') {
|
||||||
return {
|
return {
|
||||||
namespace: 'OxygenToolbox',
|
namespace: 'oxygen',
|
||||||
path: args.path
|
path: args.path
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (args.path.startsWith('./') && files[args.path.substring(2)]) {
|
|
||||||
return {
|
|
||||||
namespace: 'OxygenToolbox',
|
|
||||||
path: args.path.substring(2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (args.path.startsWith('./') && files[`${args.path.substring(2)}.tsx`]) {
|
|
||||||
return {
|
|
||||||
namespace: 'OxygenToolbox',
|
|
||||||
path: `${args.path.substring(2)}.tsx`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (args.path.startsWith('./') && files[`${args.path.substring(2)}.jsx`]) {
|
|
||||||
return {
|
|
||||||
namespace: 'OxygenToolbox',
|
|
||||||
path: `${args.path.substring(2)}.jsx`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (args.path.startsWith('./') && files[`${args.path.substring(2)}.ts`]) {
|
|
||||||
return {
|
|
||||||
namespace: 'OxygenToolbox',
|
|
||||||
path: `${args.path.substring(2)}.ts`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (args.path.startsWith('./') && files[`${args.path.substring(2)}.js`]) {
|
|
||||||
return {
|
|
||||||
namespace: 'OxygenToolbox',
|
|
||||||
path: `${args.path.substring(2)}.js`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (/\.\/.*\.css/.test(args.path) && !args.resolveDir) {
|
|
||||||
throw Error(`Css '${args.path}' not found`)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (/^https?:\/\/.*/.test(args.path)) {
|
if (/^https?:\/\/.*/.test(args.path)) {
|
||||||
return {
|
return {
|
||||||
namespace: 'default',
|
namespace: 'default',
|
||||||
@@ -126,89 +104,133 @@ class Compiler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
args.path.includes('./') ||
|
args.path.startsWith('./') &&
|
||||||
args.path.includes('../') ||
|
(!args.resolveDir.length || args.resolveDir in files)
|
||||||
args.path.startsWith('/')
|
|
||||||
) {
|
) {
|
||||||
|
const suffix = ['', '.tsx', '.jsx', '.ts', '.js'].find((suffix) => {
|
||||||
|
return files[`${args.path.substring(2)}${suffix}`]
|
||||||
|
})
|
||||||
|
if (suffix !== undefined) {
|
||||||
|
return {
|
||||||
|
namespace: 'oxygen',
|
||||||
|
path: `${args.path.substring(2)}${suffix}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (['./', '../', '/'].some((prefix) => args.path.startsWith(prefix))) {
|
||||||
return {
|
return {
|
||||||
namespace: 'default',
|
namespace: 'default',
|
||||||
path: new URL(args.path, args.resolveDir.substring(1)).href
|
path: new URL(args.path, args.resolveDir.substring(1)).href
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const path = importMap.imports[args.path]
|
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) {
|
if (!path) {
|
||||||
throw Error(`Import '${args.path}' not found in Import Map`)
|
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 {
|
return {
|
||||||
namespace: 'default',
|
namespace: 'default',
|
||||||
path
|
path: pathUrl.href
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
build.onLoad({ filter: /.*\.css$/ }, (args: OnLoadArgs) => {
|
build.onLoad({ filter: /.*\.css$/ }, (args: OnLoadArgs): OnLoadResult => {
|
||||||
const contents = cssToJs(files[args.path])
|
const contents = cssToJsFromFile(files[args.path])
|
||||||
return {
|
return {
|
||||||
loader: 'js',
|
loader: 'js',
|
||||||
contents
|
contents
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
build.onLoad({ filter: /.*\.json$/ }, (args: OnLoadArgs) => {
|
build.onLoad({ filter: /.*\.json$/ }, (args: OnLoadArgs): OnLoadResult => {
|
||||||
const contents = jsonToJs(files[args.path])
|
const contents = jsonToJsFromFile(files[args.path])
|
||||||
return {
|
return {
|
||||||
loader: 'js',
|
loader: 'js',
|
||||||
contents
|
contents
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
build.onLoad({ filter: /.*/ }, async (args: OnLoadArgs) => {
|
build.onLoad(
|
||||||
if (entryPoint === args.path) {
|
{ namespace: 'oxygen', filter: /.*/ },
|
||||||
return {
|
(args: OnLoadArgs): OnLoadResult | undefined => {
|
||||||
loader: 'tsx',
|
let file: IFile | undefined
|
||||||
contents: addReactImport(files[entryPoint].value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (files[args.path]) {
|
void ['', '.tsx', '.jsx', '.ts', '.js'].forEach((suffix) => {
|
||||||
const contents = addReactImport(files[args.path].value)
|
file = file || files[`${args.path}${suffix}`]
|
||||||
if (args.path.endsWith('.jsx')) {
|
})
|
||||||
|
if (file) {
|
||||||
return {
|
return {
|
||||||
loader: 'jsx',
|
loader: (() => {
|
||||||
contents
|
switch (file.language) {
|
||||||
|
case 'javascript':
|
||||||
|
return 'jsx'
|
||||||
|
default:
|
||||||
|
return 'tsx'
|
||||||
|
}
|
||||||
|
})(),
|
||||||
|
contents: addReactImport(file.value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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)
|
build.onLoad({ filter: /.*/ }, async (args: OnLoadArgs): Promise<OnLoadResult> => {
|
||||||
|
const cached = await this.fileCache.getItem<OnLoadResult>(args.path)
|
||||||
|
|
||||||
if (cached) {
|
if (cached) {
|
||||||
return cached
|
return cached
|
||||||
}
|
}
|
||||||
|
|
||||||
const axiosResponse = await axios.get<string>(args.path)
|
const axiosResponse = await axios.get<ArrayBuffer>(args.path, {
|
||||||
const result: esbuild.OnLoadResult = {
|
responseType: 'arraybuffer'
|
||||||
loader: 'jsx',
|
})
|
||||||
contents: axiosResponse.data,
|
const contentType = axiosResponse.headers['content-type'] as string
|
||||||
resolveDir: (axiosResponse.request as XMLHttpRequest).responseURL
|
const utf8Decoder = new TextDecoder('utf-8')
|
||||||
|
const result: OnLoadResult = {
|
||||||
|
loader: (() => {
|
||||||
|
if (
|
||||||
|
contentType.includes('javascript') ||
|
||||||
|
contentType.includes('css') ||
|
||||||
|
contentType.includes('json')
|
||||||
|
) {
|
||||||
|
return 'js'
|
||||||
|
}
|
||||||
|
return 'base64'
|
||||||
|
})(),
|
||||||
|
contents: await (async () => {
|
||||||
|
if (contentType.includes('css')) {
|
||||||
|
return cssToJs(
|
||||||
|
(
|
||||||
|
await this.compileCss(
|
||||||
|
utf8Decoder.decode(axiosResponse.data),
|
||||||
|
args.path
|
||||||
|
)
|
||||||
|
).outputFiles[0].text
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (contentType.includes('json')) {
|
||||||
|
return jsonToJs(utf8Decoder.decode(axiosResponse.data))
|
||||||
|
}
|
||||||
|
return new Uint8Array(axiosResponse.data)
|
||||||
|
})(),
|
||||||
|
resolveDir: args.path
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.fileCache.setItem(args.path, result)
|
await this.fileCache.setItem(args.path, result)
|
||||||
@@ -216,8 +238,74 @@ class Compiler {
|
|||||||
return result
|
return result
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
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 {
|
||||||
|
namespace: 'default',
|
||||||
|
path: basePath
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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)
|
||||||
|
|
||||||
|
return result
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export default new Compiler()
|
export default new Compiler()
|
||||||
|
|||||||
@@ -83,21 +83,25 @@ 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 = (file: IFile) => {
|
export const jsonToJs = (code: string) => {
|
||||||
return `export default ${file.value}`
|
return `export default ${code}`
|
||||||
}
|
}
|
||||||
|
|
||||||
export const cssToJs = (file: IFile) => {
|
export const jsonToJsFromFile = (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}_${file.name}');
|
let stylesheet = document.getElementById('style_${randomId}${fileName ? `_${fileName}` : ''}');
|
||||||
if (!stylesheet) {
|
if (!stylesheet) {
|
||||||
stylesheet = document.createElement('style')
|
stylesheet = document.createElement('style')
|
||||||
stylesheet.setAttribute('id', 'style_${randomId}_${file.name}')
|
stylesheet.setAttribute('id', 'style_${randomId}_${fileName ? `_${fileName}` : ''}')
|
||||||
document.head.appendChild(stylesheet)
|
document.head.appendChild(stylesheet)
|
||||||
}
|
}
|
||||||
const styles = document.createTextNode(
|
const styles = document.createTextNode(
|
||||||
\`${file.value}\`
|
\`${code}\`
|
||||||
)
|
)
|
||||||
stylesheet.innerHTML = ''
|
stylesheet.innerHTML = ''
|
||||||
stylesheet.appendChild(styles)
|
stylesheet.appendChild(styles)
|
||||||
@@ -105,8 +109,12 @@ export const cssToJs = (file: IFile) => {
|
|||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const cssToJsFromFile = (file: IFile) => {
|
||||||
|
return cssToJs(file.value, file.name)
|
||||||
|
}
|
||||||
|
|
||||||
export const addReactImport = (code: string) => {
|
export const addReactImport = (code: string) => {
|
||||||
if (!/import\s+React/g.test(code)) {
|
if (!/^\s*import\s+React\s+/g.test(code)) {
|
||||||
return `import React from 'react';\n${code}`
|
return `import React from 'react';\n${code}`
|
||||||
}
|
}
|
||||||
return code
|
return code
|
||||||
@@ -118,18 +126,12 @@ export const tsconfigJsonDiagnosticsOptions: DiagnosticsOptions = {
|
|||||||
{
|
{
|
||||||
uri: 'tsconfig.json',
|
uri: 'tsconfig.json',
|
||||||
fileMatch: ['tsconfig.json'],
|
fileMatch: ['tsconfig.json'],
|
||||||
schema: {
|
schema: tsconfigSchema
|
||||||
type: 'object',
|
|
||||||
properties: tsconfigSchema
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
uri: 'import-map.json',
|
uri: 'import-map.json',
|
||||||
fileMatch: ['import-map.json'],
|
fileMatch: ['import-map.json'],
|
||||||
schema: {
|
schema: importMapSchema
|
||||||
type: 'object',
|
|
||||||
properties: importMapSchema
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
{
|
{
|
||||||
"imports": {
|
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"description": "Import map"
|
"additionalProperties": {"type": "string"}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -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({ imports: {} })
|
setImportMap({})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!tsconfig) {
|
if (!tsconfig) {
|
||||||
|
|||||||
@@ -14,20 +14,7 @@ export interface IFiles {
|
|||||||
[key: string]: IFile
|
[key: string]: IFile
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ITemplate {
|
export type IImportMap = Record<string, string>
|
||||||
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
|
||||||
|
|||||||
@@ -1,59 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
const App = () => {
|
|
||||||
return <></>
|
|
||||||
}
|
|
||||||
|
|
||||||
export default App
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"imports": {
|
|
||||||
"react": "https://esm.sh/react@18.2.0",
|
|
||||||
"react-dom/client": "https://esm.sh/react-dom@18.2.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
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>
|
|
||||||
)
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
{
|
|
||||||
"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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
: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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"imports": {
|
|
||||||
"react": "https://esm.sh/react@18.2.0",
|
|
||||||
"react-dom/client": "https://esm.sh/react-dom@18.2.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
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>
|
|
||||||
)
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
{
|
|
||||||
"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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
{
|
{
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"description": "Instructs the TypeScript compiler how to compile .ts files.",
|
"description": "Instructs the TypeScript compiler how to compile .ts files.",
|
||||||
@@ -71,7 +73,10 @@
|
|||||||
},
|
},
|
||||||
"declarationDir": {
|
"declarationDir": {
|
||||||
"description": "Specify the output directory for generated declaration files.",
|
"description": "Specify the output directory for generated declaration files.",
|
||||||
"type": ["string", "null"],
|
"type": [
|
||||||
|
"string",
|
||||||
|
"null"
|
||||||
|
],
|
||||||
"markdownDescription": "Specify the output directory for generated declaration files.\n\nSee more: https://www.typescriptlang.org/tsconfig#declarationDir"
|
"markdownDescription": "Specify the output directory for generated declaration files.\n\nSee more: https://www.typescriptlang.org/tsconfig#declarationDir"
|
||||||
},
|
},
|
||||||
"disableSizeLimit": {
|
"disableSizeLimit": {
|
||||||
@@ -140,7 +145,14 @@
|
|||||||
"jsx": {
|
"jsx": {
|
||||||
"description": "Specify what JSX code is generated.",
|
"description": "Specify what JSX code is generated.",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"enum": [0, 1, 2, 3, 4, 5],
|
"enum": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
4,
|
||||||
|
5
|
||||||
|
],
|
||||||
"markdownDescription": "Specify what JSX code is generated.\n\n0 = none\n\n1 = preserve\n\n2 = react\n\n3 = react-native\n\n4 = react-jsx\n\n5 = react-jsxdev"
|
"markdownDescription": "Specify what JSX code is generated.\n\n0 = none\n\n1 = preserve\n\n2 = react\n\n3 = react-native\n\n4 = react-jsx\n\n5 = react-jsxdev"
|
||||||
},
|
},
|
||||||
"keyofStringsOnly": {
|
"keyofStringsOnly": {
|
||||||
@@ -306,19 +318,33 @@
|
|||||||
"module": {
|
"module": {
|
||||||
"description": "Specify what module code is generated.",
|
"description": "Specify what module code is generated.",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"enum": [0, 1, 2, 3, 4, 5, 99],
|
"enum": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
4,
|
||||||
|
5,
|
||||||
|
99
|
||||||
|
],
|
||||||
"markdownDescription": "Specify what module code is generated.\n\n0 = None\n\n1 = CommonJS\n\n2 = AMD\n\n3 = UMD\n\n4 = System\n\n5 = ES2015\n\n99 = ESNext"
|
"markdownDescription": "Specify what module code is generated.\n\n0 = None\n\n1 = CommonJS\n\n2 = AMD\n\n3 = UMD\n\n4 = System\n\n5 = ES2015\n\n99 = ESNext"
|
||||||
},
|
},
|
||||||
"moduleResolution": {
|
"moduleResolution": {
|
||||||
"description": "Specify how TypeScript looks up a file from a given module specifier.",
|
"description": "Specify how TypeScript looks up a file from a given module specifier.",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"enum": [1, 2],
|
"enum": [
|
||||||
|
1,
|
||||||
|
2
|
||||||
|
],
|
||||||
"markdownDescription": "Specify how TypeScript looks up a file from a given module specifier.\n\n1 = Classic\n\n2 = NodeJs"
|
"markdownDescription": "Specify how TypeScript looks up a file from a given module specifier.\n\n1 = Classic\n\n2 = NodeJs"
|
||||||
},
|
},
|
||||||
"newLine": {
|
"newLine": {
|
||||||
"description": "Set the newline character for emitting files.",
|
"description": "Set the newline character for emitting files.",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"enum": [0, 1],
|
"enum": [
|
||||||
|
0,
|
||||||
|
1
|
||||||
|
],
|
||||||
"markdownDescription": "Set the newline character for emitting files.\n\n0 = CarriageReturnLineFeed\n\n1 = LineFeed"
|
"markdownDescription": "Set the newline character for emitting files.\n\n0 = CarriageReturnLineFeed\n\n1 = LineFeed"
|
||||||
},
|
},
|
||||||
"noEmit": {
|
"noEmit": {
|
||||||
@@ -560,7 +586,19 @@
|
|||||||
"description": "Set the JavaScript language version for emitted JavaScript and include compatible library declarations.",
|
"description": "Set the JavaScript language version for emitted JavaScript and include compatible library declarations.",
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 0,
|
"default": 0,
|
||||||
"enum": [0, 1, 2, 3, 4, 5, 6, 7, 99, 100, 99],
|
"enum": [
|
||||||
|
0,
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
4,
|
||||||
|
5,
|
||||||
|
6,
|
||||||
|
7,
|
||||||
|
99,
|
||||||
|
100,
|
||||||
|
99
|
||||||
|
],
|
||||||
"markdownDescription": "Set the JavaScript language version for emitted JavaScript and include compatible library declarations.\n\n0 = ES3\n\n1 = ES5\n\n2 = ES2015\n\n3 = ES2016\n\n4 = ES2017\n\n5 = ES2018\n\n6 = ES2019\n\n7 = ES2020\n\n99 = ESNext\n\n100 = JSON\n\n99 = Latest"
|
"markdownDescription": "Set the JavaScript language version for emitted JavaScript and include compatible library declarations.\n\n0 = ES3\n\n1 = ES5\n\n2 = ES2015\n\n3 = ES2016\n\n4 = ES2017\n\n5 = ES2018\n\n6 = ES2019\n\n7 = ES2020\n\n99 = ESNext\n\n100 = JSON\n\n99 = Latest"
|
||||||
},
|
},
|
||||||
"traceResolution": {
|
"traceResolution": {
|
||||||
@@ -604,7 +642,6 @@
|
|||||||
"default": false,
|
"default": false,
|
||||||
"markdownDescription": "Emit ECMAScript-standard-compliant class fields.\n\nSee more: https://www.typescriptlang.org/tsconfig#useDefineForClassFields"
|
"markdownDescription": "Emit ECMAScript-standard-compliant class fields.\n\nSee more: https://www.typescriptlang.org/tsconfig#useDefineForClassFields"
|
||||||
},
|
},
|
||||||
|
|
||||||
"allowArbitraryExtensions": {
|
"allowArbitraryExtensions": {
|
||||||
"description": "Enable importing files with any extension, provided a declaration file is present.",
|
"description": "Enable importing files with any extension, provided a declaration file is present.",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
@@ -773,12 +810,20 @@
|
|||||||
},
|
},
|
||||||
"moduleDetection": {
|
"moduleDetection": {
|
||||||
"description": "Specify how TypeScript determine a file as module.",
|
"description": "Specify how TypeScript determine a file as module.",
|
||||||
"enum": ["auto", "legacy", "force"]
|
"enum": [
|
||||||
|
"auto",
|
||||||
|
"legacy",
|
||||||
|
"force"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"importsNotUsedAsValues": {
|
"importsNotUsedAsValues": {
|
||||||
"description": "Specify emit/checking behavior for imports that are only used for types.",
|
"description": "Specify emit/checking behavior for imports that are only used for types.",
|
||||||
"default": "remove",
|
"default": "remove",
|
||||||
"enum": ["remove", "preserve", "error"]
|
"enum": [
|
||||||
|
"remove",
|
||||||
|
"preserve",
|
||||||
|
"error"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"resolvePackageJsonExports": {
|
"resolvePackageJsonExports": {
|
||||||
"description": "Use the package.json 'exports' field when resolving package imports.",
|
"description": "Use the package.json 'exports' field when resolving package imports.",
|
||||||
@@ -819,3 +864,4 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
@@ -169,18 +169,18 @@ const Base = () => {
|
|||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
),
|
),
|
||||||
width: '12em',
|
width: '14em',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
render: (_, record) => (
|
render: (_, record) => (
|
||||||
<>
|
<>
|
||||||
<AntdSpace size={'middle'}>
|
<AntdSpace size={'middle'}>
|
||||||
{!record.compiled && !Object.keys(hasEdited).length && (
|
{!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,7 +304,10 @@ 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={'请选择入口文件'}
|
||||||
@@ -1097,7 +1100,7 @@ const Base = () => {
|
|||||||
<Playground.CodeEditor
|
<Playground.CodeEditor
|
||||||
files={editingFiles[editingBaseId]}
|
files={editingFiles[editingBaseId]}
|
||||||
selectedFileName={editingFileName}
|
selectedFileName={editingFileName}
|
||||||
onSelectedFileChange={() => {}}
|
onSelectedFileChange={setEditingFileName}
|
||||||
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={() => {}}
|
onSelectedFileChange={setEditingFileName}
|
||||||
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 }]}
|
rules={[{ required: true, message: '请选择审核结果' }]}
|
||||||
>
|
>
|
||||||
<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