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() | ||||
| }) | ||||
|  | @ -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,63 +16,88 @@ 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 | ||||
|     const routes = await Dynamic(plugin) | ||||
|     // 不存在
 | ||||
|     if (!routes) continue | ||||
|       /** | ||||
|        * | ||||
|        */ | ||||
|       if (Array.isArray(routes)) { | ||||
|         /** | ||||
|          * | ||||
|          */ | ||||
|     // 不是数组
 | ||||
|     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 | ||||
|      */ | ||||
|           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') | ||||
|     // 置换为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