feat: 动态组件
This commit is contained in:
parent
49f9a0a4d7
commit
907a80c914
|
@ -0,0 +1,24 @@
|
||||||
|
import { spawn } from 'child_process'
|
||||||
|
const argv = [...process.argv].splice(2)
|
||||||
|
const argvs = argv.join(' ').replace(/(\S+\.js|\S+\.ts)/g, '')
|
||||||
|
const child1 = spawn(
|
||||||
|
'tailwindcss -i ./src/input.css -o ./public/output.css --watch',
|
||||||
|
[],
|
||||||
|
{
|
||||||
|
shell: true,
|
||||||
|
stdio: 'inherit'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
const child2 = spawn(
|
||||||
|
'node --no-warnings=ExperimentalWarning --loader ts-node/esm image/main.ts',
|
||||||
|
argvs.split(' '),
|
||||||
|
{
|
||||||
|
shell: true,
|
||||||
|
stdio: 'inherit'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
process.on('SIGINT', () => {
|
||||||
|
if (child1.pid) process.kill(child1.pid)
|
||||||
|
if (child2.pid) process.kill(child2.pid)
|
||||||
|
if (process.pid) process.exit()
|
||||||
|
})
|
127
image/main.ts
127
image/main.ts
|
@ -2,12 +2,11 @@ import '../src/init/require.js'
|
||||||
import '../src/init/config.js'
|
import '../src/init/config.js'
|
||||||
import '../src/init/logger.js'
|
import '../src/init/logger.js'
|
||||||
import '../src/init/redis.js'
|
import '../src/init/redis.js'
|
||||||
import './tailwindcss.js'
|
|
||||||
import Koa from 'koa'
|
import Koa from 'koa'
|
||||||
import KoaStatic from 'koa-static'
|
import KoaStatic from 'koa-static'
|
||||||
import Router from 'koa-router'
|
import Router from 'koa-router'
|
||||||
import { Component } from 'yunzai/utils'
|
import { Component } from 'yunzai/utils'
|
||||||
import { readdirSync } from 'fs'
|
import { Dirent, readdirSync } from 'fs'
|
||||||
import { join } from 'path'
|
import { join } from 'path'
|
||||||
import mount from 'koa-mount'
|
import mount from 'koa-mount'
|
||||||
|
|
||||||
|
@ -17,64 +16,89 @@ const router = new Router()
|
||||||
const Port = 8080
|
const Port = 8080
|
||||||
const PATH = process.cwd()
|
const PATH = process.cwd()
|
||||||
|
|
||||||
|
const Dynamic = async (Router: Dirent) => {
|
||||||
|
const modulePath = `file://${join(Router.parentPath, Router.name)}?update=${Date.now()}`
|
||||||
|
return (await import(modulePath))?.default
|
||||||
|
}
|
||||||
|
|
||||||
// 得到plugins目录
|
// 得到plugins目录
|
||||||
const flies = readdirSync(join(process.cwd(), 'plugins'), {
|
const flies = readdirSync(join(process.cwd(), 'plugins'), {
|
||||||
withFileTypes: true
|
withFileTypes: true
|
||||||
}).filter(flie => !flie.isFile())
|
})
|
||||||
|
.filter(flie => !flie.isFile())
|
||||||
|
.map(flie => {
|
||||||
|
const dir = flie?.path ?? flie?.parentPath
|
||||||
|
flie.parentPath = dir
|
||||||
|
return flie
|
||||||
|
}) // 增加兼容性
|
||||||
|
|
||||||
|
//
|
||||||
|
const Routers = []
|
||||||
|
|
||||||
// 解析路由
|
// 解析路由
|
||||||
for (const flie of flies) {
|
for (const flie of flies) {
|
||||||
const dir = flie?.path ?? flie?.parentPath
|
const plugins = readdirSync(join(flie?.parentPath, flie.name), {
|
||||||
if (!dir) {
|
|
||||||
console.log('flie.name', flie.name, '识别错误')
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
const plugins = readdirSync(join(dir, flie.name), {
|
|
||||||
withFileTypes: true
|
withFileTypes: true
|
||||||
}).filter(flie => flie.isFile())
|
})
|
||||||
|
.filter(
|
||||||
|
flie => flie.isFile() && /^(routes.jsx|routes.tsx)$/.test(flie.name)
|
||||||
|
)
|
||||||
|
.map(flie => {
|
||||||
|
const dir = flie?.path ?? flie?.parentPath
|
||||||
|
flie.parentPath = dir
|
||||||
|
return flie
|
||||||
|
}) // 增加兼容性
|
||||||
|
|
||||||
|
//
|
||||||
for (const plugin of plugins) {
|
for (const plugin of plugins) {
|
||||||
/**
|
const routes = await Dynamic(plugin)
|
||||||
*
|
// 不存在
|
||||||
*/
|
if (!routes) continue
|
||||||
if (/^(routes.jsx|routes.tsx)$/.test(plugin.name)) {
|
// 不是数组
|
||||||
const routes = (await import(`file://${join(plugin.path, plugin.name)}`))
|
if (!Array.isArray(routes)) continue
|
||||||
?.default
|
//
|
||||||
if (!routes) continue
|
for (const item of routes) {
|
||||||
/**
|
const url = `/${flie.name}${item.url}`
|
||||||
*
|
console.log(`http://127.0.0.1:${Port}${url}`)
|
||||||
*/
|
Routers.push({
|
||||||
if (Array.isArray(routes)) {
|
parentPath: plugin.parentPath,
|
||||||
/**
|
name: plugin.name,
|
||||||
*
|
uri: url,
|
||||||
*/
|
url: item.url
|
||||||
for (const item of routes) {
|
})
|
||||||
const url = `/${flie.name}${item.url}`
|
|
||||||
console.log(`http://127.0.0.1:${Port}${url}`)
|
|
||||||
/**
|
|
||||||
* 推送接口
|
|
||||||
*/
|
|
||||||
router.get(url, ctx => {
|
|
||||||
const options = item?.options ?? {}
|
|
||||||
const HTML = Com.create(item.element, {
|
|
||||||
...options,
|
|
||||||
html_head: options?.html_head ?? '',
|
|
||||||
file_create: false
|
|
||||||
})
|
|
||||||
// 转义路径中的所有反斜杠
|
|
||||||
const escapedPath = PATH.replace(/\\/g, '\\\\')
|
|
||||||
// 创建一个正则表达式,'g' 表示全局匹配
|
|
||||||
const regex = new RegExp(escapedPath, 'g')
|
|
||||||
ctx.body = HTML.replace(regex, '/file')
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const Router of Routers) {
|
||||||
|
router.get(Router.uri, async ctx => {
|
||||||
|
// 动态加载
|
||||||
|
const routes = await Dynamic(Router)
|
||||||
|
// 不存在
|
||||||
|
if (!routes) return
|
||||||
|
// 不是数组
|
||||||
|
if (!Array.isArray(routes)) return
|
||||||
|
// 查找
|
||||||
|
const item = routes.find(i => i.url == Router.url)
|
||||||
|
// 丢失了
|
||||||
|
if (!item) return
|
||||||
|
/**
|
||||||
|
* 渲染html
|
||||||
|
*/
|
||||||
|
const options = item?.options ?? {}
|
||||||
|
const HTML = Com.create(item.element, {
|
||||||
|
...options,
|
||||||
|
file_create: false
|
||||||
|
})
|
||||||
|
// 转义路径中的所有反斜杠
|
||||||
|
const escapedPath = PATH.replace(/\\/g, '\\\\')
|
||||||
|
// 创建一个正则表达式
|
||||||
|
const regex = new RegExp(escapedPath, 'g')
|
||||||
|
// 置换为file请求
|
||||||
|
ctx.body = HTML.replace(regex, '/file')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
app.use(mount('/file', KoaStatic(PATH)))
|
app.use(mount('/file', KoaStatic(PATH)))
|
||||||
|
|
||||||
|
@ -83,6 +107,11 @@ app.use(router.routes())
|
||||||
|
|
||||||
// listen 8000
|
// listen 8000
|
||||||
app.listen(Port, () => {
|
app.listen(Port, () => {
|
||||||
|
console.log('______________')
|
||||||
console.log('Server is running on port ' + Port)
|
console.log('Server is running on port ' + Port)
|
||||||
console.log('默认浏览器尺寸 800 X 1280 100%')
|
console.log('______________')
|
||||||
|
console.log('自行调整默认浏览器尺寸 800 X 1280 100%')
|
||||||
|
console.log('如果需要运行时重新计算className')
|
||||||
|
console.log('请确保一直打开此程序')
|
||||||
|
console.log('______________')
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
{
|
|
||||||
"watch": ["plugins"],
|
|
||||||
"ext": "tsx,jsx",
|
|
||||||
"exec": "node --no-warnings=ExperimentalWarning --loader ts-node/esm image/main.ts",
|
|
||||||
"env": {
|
|
||||||
"NODE_ENV": "development"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
import { spawn } from 'child_process'
|
|
||||||
/**
|
|
||||||
* **********
|
|
||||||
* 生成css文件
|
|
||||||
* **********
|
|
||||||
*/
|
|
||||||
// exec('')
|
|
||||||
|
|
||||||
const child = spawn(
|
|
||||||
'tailwindcss -i ./src/input.css -o ./public/output.css --watch',
|
|
||||||
[],
|
|
||||||
{
|
|
||||||
shell: true,
|
|
||||||
stdio: 'inherit'
|
|
||||||
}
|
|
||||||
)
|
|
||||||
/**
|
|
||||||
* *************
|
|
||||||
* exit
|
|
||||||
* *************
|
|
||||||
*/
|
|
||||||
process.on('SIGINT', () => {
|
|
||||||
if (child.pid) process.kill(child.pid)
|
|
||||||
if (process.pid) process.exit()
|
|
||||||
})
|
|
|
@ -16,12 +16,13 @@
|
||||||
"logs": "pm2 logs",
|
"logs": "pm2 logs",
|
||||||
"monit": "pm2 monit",
|
"monit": "pm2 monit",
|
||||||
"pm2": "pm2",
|
"pm2": "pm2",
|
||||||
"image": "nodemon --config image/nodemon.json",
|
"image": "node image/index.js",
|
||||||
"css": "tailwindcss -i ./src/input.css -o ./public/output.css",
|
"css": "tailwindcss -i ./src/input.css -o ./public/output.css",
|
||||||
"format": "prettier --write .",
|
"format": "prettier --write .",
|
||||||
"prepare": "husky"
|
"prepare": "husky"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@loadable/component": "^5.16.4",
|
||||||
"art-template": "^4.13.2",
|
"art-template": "^4.13.2",
|
||||||
"chalk": "^5.3.0",
|
"chalk": "^5.3.0",
|
||||||
"chokidar": "^3.6.0",
|
"chokidar": "^3.6.0",
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { createRequire as cRequire } from 'module'
|
import { createRequire as cRequire } from 'module'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated 已废弃
|
* @deprecated 已废弃
|
||||||
* @param basePath
|
* @param basePath
|
||||||
|
@ -6,6 +7,7 @@ import { createRequire as cRequire } from 'module'
|
||||||
export function createRequire(basePath: string) {
|
export function createRequire(basePath: string) {
|
||||||
return cRequire(basePath)
|
return cRequire(basePath)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated 已废弃
|
* @deprecated 已废弃
|
||||||
* @param path
|
* @param path
|
||||||
|
@ -16,3 +18,23 @@ export function require(path: string) {
|
||||||
return cRequire(url)(path)
|
return cRequire(url)(path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const now = () => `?update=${Date.now()}`
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ***********
|
||||||
|
* 创建动态模块
|
||||||
|
* ***********
|
||||||
|
* 动态模块每次访问都将重新加载,
|
||||||
|
* 如果动态模块内包含动态模块,
|
||||||
|
* 内部模块也会跟着重新加载,
|
||||||
|
* ***********
|
||||||
|
* 请确保你的模块是可预测
|
||||||
|
* ***********
|
||||||
|
* 请确保当前模块是可被执行的
|
||||||
|
* @param basePath
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export const createDynamic = (basePath: string) => {
|
||||||
|
return (path: string) => import(new URL(`${path}${now()}`, basePath).href)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue