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/logger.js'
|
||||
import '../src/init/redis.js'
|
||||
import './tailwindcss.js'
|
||||
import Koa from 'koa'
|
||||
import KoaStatic from 'koa-static'
|
||||
import Router from 'koa-router'
|
||||
import { Component } from 'yunzai/utils'
|
||||
import { readdirSync } from 'fs'
|
||||
import { Dirent, readdirSync } from 'fs'
|
||||
import { join } from 'path'
|
||||
import mount from 'koa-mount'
|
||||
|
||||
|
@ -17,64 +16,89 @@ const router = new Router()
|
|||
const Port = 8080
|
||||
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目录
|
||||
const flies = readdirSync(join(process.cwd(), 'plugins'), {
|
||||
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) {
|
||||
const dir = flie?.path ?? flie?.parentPath
|
||||
if (!dir) {
|
||||
console.log('flie.name', flie.name, '识别错误')
|
||||
continue
|
||||
}
|
||||
/**
|
||||
*
|
||||
*/
|
||||
const plugins = readdirSync(join(dir, flie.name), {
|
||||
const plugins = readdirSync(join(flie?.parentPath, flie.name), {
|
||||
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) {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
if (/^(routes.jsx|routes.tsx)$/.test(plugin.name)) {
|
||||
const routes = (await import(`file://${join(plugin.path, plugin.name)}`))
|
||||
?.default
|
||||
if (!routes) continue
|
||||
/**
|
||||
*
|
||||
*/
|
||||
if (Array.isArray(routes)) {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
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')
|
||||
})
|
||||
}
|
||||
}
|
||||
const routes = await Dynamic(plugin)
|
||||
// 不存在
|
||||
if (!routes) continue
|
||||
// 不是数组
|
||||
if (!Array.isArray(routes)) continue
|
||||
//
|
||||
for (const item of routes) {
|
||||
const url = `/${flie.name}${item.url}`
|
||||
console.log(`http://127.0.0.1:${Port}${url}`)
|
||||
Routers.push({
|
||||
parentPath: plugin.parentPath,
|
||||
name: plugin.name,
|
||||
uri: url,
|
||||
url: item.url
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
app.use(mount('/file', KoaStatic(PATH)))
|
||||
|
||||
|
@ -83,6 +107,11 @@ app.use(router.routes())
|
|||
|
||||
// listen 8000
|
||||
app.listen(Port, () => {
|
||||
console.log('______________')
|
||||
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",
|
||||
"monit": "pm2 monit",
|
||||
"pm2": "pm2",
|
||||
"image": "nodemon --config image/nodemon.json",
|
||||
"image": "node image/index.js",
|
||||
"css": "tailwindcss -i ./src/input.css -o ./public/output.css",
|
||||
"format": "prettier --write .",
|
||||
"prepare": "husky"
|
||||
},
|
||||
"dependencies": {
|
||||
"@loadable/component": "^5.16.4",
|
||||
"art-template": "^4.13.2",
|
||||
"chalk": "^5.3.0",
|
||||
"chokidar": "^3.6.0",
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { createRequire as cRequire } from 'module'
|
||||
|
||||
/**
|
||||
* @deprecated 已废弃
|
||||
* @param basePath
|
||||
|
@ -6,6 +7,7 @@ import { createRequire as cRequire } from 'module'
|
|||
export function createRequire(basePath: string) {
|
||||
return cRequire(basePath)
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated 已废弃
|
||||
* @param path
|
||||
|
@ -16,3 +18,23 @@ export function require(path: string) {
|
|||
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