2 Commits f2829c82d5 ... e3af8f430b

Author SHA1 Message Date
  tuonian e3af8f430b minor: 验证功能-qiankun 3 months ago
  tuonian 1edf882491 minor: 验证功能-qiankun 3 months ago

+ 4 - 0
frontend/README.md

@@ -155,3 +155,7 @@ wails build -webview2=embed
 ## 带debug
 wails build -webview2=embed -debug
 ```
+
+## 微应用支持
+### vite支持qiankun
+- 参考: https://github.com/lishaobos/vite-plugin-legacy-qiankun?tab=readme-ov-file

+ 0 - 0
frontend/dist/assets/bg-df7c9fe1.jpg → frontend/dist/assets/bg-BL8qTlvt.jpg


+ 0 - 0
frontend/dist/assets/ic_home-b1ed3048.svg → frontend/dist/assets/ic_home-CEHAik-C.svg


File diff suppressed because it is too large
+ 0 - 0
frontend/dist/assets/index-6a157cc6.css


File diff suppressed because it is too large
+ 1 - 0
frontend/dist/assets/index-C4bOgrFY.js


File diff suppressed because it is too large
+ 0 - 0
frontend/dist/assets/index-Du21pBjA.css


File diff suppressed because it is too large
+ 0 - 0
frontend/dist/assets/index-bfcad9eb.js


File diff suppressed because it is too large
+ 0 - 0
frontend/dist/assets/index-legacy-C9bzCwDK.js


File diff suppressed because it is too large
+ 0 - 0
frontend/dist/assets/polyfills-legacy-onNG-a16.js


File diff suppressed because it is too large
+ 0 - 0
frontend/dist/cdn/ace-builds-1.23.0-legacy.js


File diff suppressed because it is too large
+ 0 - 0
frontend/dist/cdn/ace-builds-1.23.0.js


File diff suppressed because it is too large
+ 0 - 0
frontend/dist/cdn/react-all-18.2.0-legacy.js


File diff suppressed because it is too large
+ 1 - 1
frontend/dist/cdn/react-all-18.2.0.js


File diff suppressed because it is too large
+ 0 - 0
frontend/dist/cdn/rich-legacy.js


File diff suppressed because it is too large
+ 0 - 2
frontend/dist/cdn/rich.js


+ 55 - 46
frontend/dist/index.html

@@ -1,48 +1,57 @@
-<!DOCTYPE html><html lang="en"><head>
-    <meta charset="UTF-8">
-    <link rel="icon" type="image/svg+xml" href="/nginx-ui/vite.svg">
-    <meta name="viewport" content="width=device-width, initial-scale=1.0">
-    <title>NginxUI</title>
-    <script type="application/javascript" src="/nginx-ui/config.js"></script>
-    <script crossorigin="">import('/nginx-ui/assets/index-bfcad9eb.js').finally(() => {
-            
-    const qiankunLifeCycle = window.moudleQiankunAppLifeCycles && window.moudleQiankunAppLifeCycles['nginx-ui'];
-    if (qiankunLifeCycle) {
-      window.proxy.vitemount((props) => qiankunLifeCycle.mount(props));
-      window.proxy.viteunmount((props) => qiankunLifeCycle.unmount(props));
-      window.proxy.vitebootstrap(() => qiankunLifeCycle.bootstrap());
-      window.proxy.viteupdate((props) => qiankunLifeCycle.update(props));
-    }
-  
-          })</script>
-    <link rel="modulepreload" crossorigin="" href="/nginx-ui/cdn/ace-builds-1.23.0.js">
-    <link rel="modulepreload" crossorigin="" href="/nginx-ui/cdn/react-all-18.2.0.js">
-    <link rel="stylesheet" href="/nginx-ui/assets/index-6a157cc6.css">
-  </head>
-  <body>
-    <div id="nginx_ui_root"></div>
-    
-  
-
+<!DOCTYPE html>
+<html lang="en">
+  <head>
 <script>
-  const createDeffer = (hookName) => {
-    const d = new Promise((resolve, reject) => {
-      window.proxy && (window.proxy[`vite${hookName}`] = resolve)
-    })
-    return props => d.then(fn => fn(props));
-  }
-  const bootstrap = createDeffer('bootstrap');
-  const mount = createDeffer('mount');
-  const unmount = createDeffer('unmount');
-  const update = createDeffer('update');
+(function (){
+const global = (0, eval)('window')
+const name = 'nginx-ui'
+
+    const proxy = global.proxy
+    let publicPath = (proxy && proxy.__INJECTED_PUBLIC_PATH_BY_QIANKUN__) || ''
+    publicPath = publicPath.slice(0, publicPath.length - 1)
+    global.legacyQiankun = global.legacyQiankun || {}
+    global.legacyQiankun[name] = global.legacyQiankun[name] || {}
+    Object.assign(global.legacyQiankun[name], {
+      proxy,
+      publicPath,
+      '__INJECTED_PUBLIC_PATH_BY_QIANKUN__': proxy && proxy.__INJECTED_PUBLIC_PATH_BY_QIANKUN__,
+      '__POWERED_BY_QIANKUN__': proxy && proxy.__INJECTED_PUBLIC_PATH_BY_QIANKUN__,
+    })})()
+</script>
+    <meta charset="UTF-8" />
+    <link rel="icon" type="image/svg+xml" href="/nginx-ui/vite.svg" />
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+    <title>NginxUI</title>
+    <script type="application/javascript" src="/nginx-ui/config.js"></script>
+    <!-- replace by vite-plugin-legacy-qiankun <script type="module" crossorigin src="/nginx-ui/assets/index-C4bOgrFY.js"></script> -->
+    <link rel="modulepreload" crossorigin href="/nginx-ui/cdn/ace-builds-1.23.0.js">
+    <link rel="modulepreload" crossorigin href="/nginx-ui/cdn/react-all-18.2.0.js">
+    <link rel="stylesheet" crossorigin href="/nginx-ui/assets/index-Du21pBjA.css">
+    <!-- replace by vite-plugin-legacy-qiankun <script type="module">import.meta.url;import("_").catch(()=>1);(async function*(){})().next();if(location.protocol!="file:"){window.__vite_is_modern_browser=true}</script> -->
+    <!-- replace by vite-plugin-legacy-qiankun <script type="module">!function(){if(window.__vite_is_modern_browser)return;console.warn("vite: loading legacy chunks, syntax error above and the same error below should be ignored");var e=document.getElementById("vite-legacy-polyfill"),n=document.createElement("script");n.src=e.src,n.onload=function(){System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))},document.body.appendChild(n)}();</script> -->
+  </head>
+  <body>
+    <div id="nginx_ui_root"></div>

+    <script >!function(){var e=document,t=e.createElement("script");if(!("noModule"in t)&&"onbeforeload"in t){var n=!1;e.addEventListener("beforeload",(function(e){if(e.target===t)n=!0;else if(!e.target.hasAttribute("nomodule")||!n)return;e.preventDefault()}),!0),t.type="module",t.src=".",e.head.appendChild(t),t.remove()}}();</script>
+    <script  crossorigin id="vite-legacy-polyfill" src="/nginx-ui/assets/polyfills-legacy-onNG-a16.js"></script>
+    <script>
+(function (){
+const global = (0, eval)('window')
+const name = 'nginx-ui'
+global.legacyQiankun[name].dynamicImport = System.import(!global.legacyQiankun[name].__POWERED_BY_QIANKUN__ ? '/nginx-ui/assets/index-legacy-C9bzCwDK.js' : new URL('/nginx-ui/assets/index-legacy-C9bzCwDK.js', global.legacyQiankun[name].__POWERED_BY_QIANKUN__).toString())})()
+</script>
+  <script>
+(function (){
+const global = (0, eval)('window')
+const name = 'nginx-ui'
 
-  ;(global => {
-    global.qiankunName = 'nginx-ui';
-    global['nginx-ui'] = {
-      bootstrap,
-      mount,
-      unmount,
-      update
-    };
-  })(window);
-</script></body></html>
+    const app = global.legacyQiankun[name]
+    if (!app.proxy) return
+    window[name] = {
+      bootstrap: (...args) => app.dynamicImport.then(() => app.lifecyle.bootstrap(...args)),
+      mount: (...args) => app.dynamicImport.then(() => app.lifecyle.mount(...args)),
+      unmount: (...args) => app.dynamicImport.then(() => app.lifecyle.unmount(...args)),
+      update: (...args) => app.dynamicImport.then(() => app.lifecyle.update(...args)),
+    }})()
+</script></body>
+</html>

+ 9 - 6
frontend/package.json

@@ -1,7 +1,7 @@
 {
-  "name": "nginx-ui-react",
+  "name": "nginx-ui",
   "private": false,
-  "version": "0.1.1",
+  "version": "0.1.2",
   "license": "MIT",
   "author": {
     "email": "976056042@qq.com",
@@ -21,8 +21,9 @@
     "@mdx-js/mdx": "^2.0.0-rc.2",
     "@mdx-js/react": "^2.3.0",
     "@mdx-js/rollup": "^2.3.0",
-    "@micro-zoe/micro-app": "^1.0.0-rc.13",
     "@reduxjs/toolkit": "^1.9.5",
+    "@vitejs/plugin-legacy": "^6.0.0",
+    "@vitejs/plugin-react": "^4.3.4",
     "antd": "4.x",
     "artt-template": "^4.13.6",
     "auto-antd": "^0.1.11",
@@ -36,6 +37,7 @@
     "less": "^4.1.3",
     "lodash": "^4.17.21",
     "npm": "^9.8.0",
+    "qiankun": "^2.10.16",
     "query-string": "^8.1.0",
     "react": "^18.2.0",
     "react-dom": "^18.2.0",
@@ -44,8 +46,9 @@
     "react-router-dom": "^6.14.0",
     "redux-persist": "^6.0.0",
     "sass": "^1.80.3",
+    "terser": "^5.37.0",
     "vite-plugin-cdn-import": "^1.0.1",
-    "wujie-react": "^1.0.22"
+    "vite-plugin-legacy-qiankun": "^0.0.12"
   },
   "devDependencies": {
     "@types/events": "^3.0.0",
@@ -55,13 +58,13 @@
     "@types/react-dom": "^18.0.11",
     "@typescript-eslint/eslint-plugin": "^5.59.0",
     "@typescript-eslint/parser": "^5.59.0",
-    "@vitejs/plugin-react-swc": "^3.0.0",
+    "@vitejs/plugin-react-swc": "^3.7.2",
     "consola": "^3.1.0",
     "eslint": "^8.38.0",
     "eslint-plugin-react-hooks": "^4.6.0",
     "eslint-plugin-react-refresh": "^0.3.4",
     "typescript": "^5.0.2",
-    "vite": "^4.3.9",
+    "vite": "5.4.6",
     "vite-plugin-md": "^0.21.5",
     "vite-plugin-mdx": "^3.5.11",
     "vite-plugin-qiankun": "^1.0.15",

+ 0 - 4
frontend/src/components/app/index.less

@@ -1,4 +0,0 @@
-.micro-app-container{
-  width: 100%;
-  height: 100%;
-}

+ 0 - 48
frontend/src/components/app/index.tsx

@@ -1,48 +0,0 @@
-
-import {useEffect, useRef} from "react";
-import {startApp,startOptions } from "wujie";
-import {Settings} from "../../api/settings.ts";
-import './index.less'
-
-type IProps = {
-    app: Settings.Route
-    config: Partial<startOptions>
-}
-
-export const MicroApp = ({app, config}: IProps) => {
-
-    const domRef = useRef<HTMLDivElement>(null);
-    const destroyRef = useRef<any>()
-
-    const handleStartApp = () => {
-        if (!domRef.current) {
-            return
-        }
-        console.log('startApp', app.path)
-        startApp({
-            name: app.id,
-            url: app.path,
-            alive: true,
-            ...config,
-            el: domRef.current,
-        }).then(func=>{
-            destroyRef.current = func
-        }).catch(err=>{
-            console.log('startApp error ',err)
-        })
-    }
-
-    useEffect(() => {
-        handleStartApp()
-    }, [domRef.current]);
-
-    useEffect(() => {
-        console.log('MicroApp mounted')
-        return () => {
-            console.log('MicroApp unmounted')
-        }
-    }, []);
-
-    return <div id={'micro_app_'+app.id} className="micro-app-container" ref={domRef} />;
-
-}

+ 1 - 4
frontend/src/main.tsx

@@ -4,11 +4,8 @@ import './adapter/index.js'
 import App from './App.tsx'
 import './index.css'
 import './styles/index.less'
-import renderWithQiankun from "vite-plugin-qiankun/es/helper";
+import renderWithQiankun from "vite-plugin-qiankun/dist/helper";
 import './components/form/index.ts'
-import microApp from '@micro-zoe/micro-app'
-
-microApp.start()
 
 let root: Root | null
 

+ 2 - 6
frontend/src/pages/ldap/user/list/index.tsx

@@ -4,7 +4,6 @@ import {LDAP, LDAPApis} from "../../../../api/ldap.ts";
 import {ICurdConfig} from "../../../../components/curd/types.ts";
 import {Alert, Button} from "antd";
 import './index.less'
-import {Link} from "react-router-dom";
 import {useRouteLoaderData} from "react-router";
 import {SyncOutlined} from "@ant-design/icons";
 import {isNull, Message} from "auto-antd";
@@ -258,12 +257,9 @@ export const List = () => {
         })
     }
 
-    const operationRender = (record: LDAP.User, _: number) => {
-
+    const operationRender = () => {
         return (<>
-            <Button size="small">
-                <Link to={`server/${record.id}/user`}>重置密码</Link>
-            </Button>
+
         </>)
     }
 

+ 49 - 42
frontend/src/pages/microApp/index.tsx

@@ -5,15 +5,20 @@ import {ErrorComponent} from "../../components/error/Error.tsx";
 import {useAppDispatch, useAppSelector} from "../../store";
 import {LoadingText} from "../../components/loading";
 import {settingsActions} from "../../store/slice/settings.ts";
-// import {startApp} from "wujie";
+import {loadMicroApp, addGlobalUncaughtErrorHandler, removeGlobalUncaughtErrorHandler} from 'qiankun'
+import type {MicroApp} from "qiankun";
 
 // 腾讯无界: https://wujie-micro.github.io/doc/guide/start.html
+// https://qiankun.umijs.org/zh/guide/tutorial#%E4%B8%BB%E5%BA%94%E7%94%A8
 export const MicroAppPage = () => {
 
+    const isMounted = useRef(false)
     const params = useParams<{ id: string }>()
     const [error, setError] = useState<any>()
     const [loading, setLoading] = useState(true)
 
+    const microApp = useRef<MicroApp>()
+
     const routeMap = useAppSelector(state => state.user.routeMap)
     const dispatch = useAppDispatch();
     const domRef = useRef<HTMLDivElement>(null);
@@ -26,47 +31,48 @@ export const MicroAppPage = () => {
         dispatch(settingsActions.setFullScreen(full))
     }
 
-    // const destroyRef = useRef<any>()
-    // const onActivated = (e: any) => {
-    //     console.log('activated', e)
-    // }
-    //
-    // const onLoadFail = (url: any, e: any) => {
-    //     setLoading(false)
-    //     console.log('load fail', url)
-    //     setError(e)
-    // }
-    // const afterMounted = () => {
-    //     console.log('afterMounted', app)
-    // }
-
-    // const handleStartApp = () => {
-    //     if (!domRef.current || !app) {
-    //         return
-    //     }
-    //     console.log('startApp', app.path)
-    //     startApp({
-    //         name: app.id,
-    //         url: app.path,
-    //         alive: true,
-    //         el: domRef.current,
-    //         beforeMount: () => setLoading(true),
-    //         afterMount: afterMounted,
-    //         loadError: onLoadFail,
-    //         activated: onActivated,
-    //         degrade: true,
-    //         sync: true,
-    //     }).then(func=>{
-    //         destroyRef.current = func
-    //     }).catch(err=>{
-    //         console.log('startApp error ',err)
-    //     })
-    // }
+    useEffect(() => {
+        if (!domRef.current || !app) return;
+        console.log('app',app)
+        if (microApp.current){
+            console.log('MicroApp has init')
+            // return;
+        }
+        microApp.current = loadMicroApp({
+            name: app.id,
+            entry: app.path,
+            container: domRef.current,
+            props: {
+                root: `#micro-app-${app?.id}`
+            },
+        }, {
+            sandbox: false,
+            autoStart: true,
+        })
+        microApp.current.mountPromise.then(()=>{
+            console.log('MicroApp mounted')
+        }).catch(error=>{
+            setError(error)
+            console.log('mount error',error)
+        }).finally(()=>{
+            setLoading(false)
+        })
+    }, [app]);
 
     useEffect(() => {
+        isMounted.current = true;
         setFullScreen(true)
+        const errorHandler = (error: any) => {
+            console.log('load micro app fail',error)
+        }
+        addGlobalUncaughtErrorHandler(errorHandler)
         return ()=>{
+            isMounted.current = false
+            console.log('unload micro app',app?.id)
             setFullScreen(false)
+            removeGlobalUncaughtErrorHandler(errorHandler)
+            microApp.current?.unmount()
+            microApp.current = undefined
         }
     }, []);
 
@@ -74,13 +80,14 @@ export const MicroAppPage = () => {
     //     handleStartApp()
     // }, [domRef.current,app]);
 
-    return (<div id={'micro_app_'+app?.id} className="micro-app">
+    return (<div className="micro-app">
         <LoadingText loading={loading} text="加载中,请稍后..."/>
         {error ?<ErrorComponent noRedirect={true} error={error}/>: null}
-        <div className="micro-app-container" ref={domRef}>
-            <iframe src={app?.path} style={{width:'100%',height:'100%'}}
-                    onLoad={() => setLoading(false)}
-                    onError={e=>setError(e)}/>
+        <div id={`micro-app-${app?.id}`} className="micro-app-container" ref={domRef}>
+            {/*<iframe src={app?.path} style={{width:'100%',height:'100%'}}*/}
+            {/*        onLoad={() => setLoading(false)}*/}
+            {/*        onError={e=>setError(e)}/>*/}
+            {/*<micro-app name='my-app' url='http://localhost:3000/'></micro-app>*/}
         </div>
     </div>)
 }

+ 2 - 1
frontend/tsconfig.json

@@ -19,7 +19,8 @@
     "noUnusedLocals": true,
     "noUnusedParameters": true,
     "noFallthroughCasesInSwitch": true,
-    "allowSyntheticDefaultImports": true
+    "allowSyntheticDefaultImports": true,
+    "noImplicitAny": true
   },
   "include": ["src","docs"],
   "references": [{ "path": "./tsconfig.node.json" }]

+ 16 - 8
frontend/vite.config.ts

@@ -1,12 +1,12 @@
 import { defineConfig, loadEnv } from 'vite'
-import react from '@vitejs/plugin-react-swc'
+import react from '@vitejs/plugin-react'
 import {AntdResolve, createStyleImportPlugin} from "vite-plugin-style-import";
 // eslint-disable-next-line @typescript-eslint/ban-ts-comment
-// @ts-ignore
-import qiankun from 'vite-plugin-qiankun'
 import mdx from '@mdx-js/rollup'
 import * as path from 'path'
 import fse from 'fs-extra'
+import legacy from '@vitejs/plugin-legacy' // need this
+import { legacyQiankun } from 'vite-plugin-legacy-qiankun'
 
 
 const readDepInfo = (module: string) => {
@@ -37,10 +37,11 @@ export default defineConfig(({command, mode})=>{
       createStyleImportPlugin({
         resolves: [AntdResolve()]
       }),
-      qiankun('nginx-ui',{
-        useDevMode: mode != 'production'
-      }),
-
+        legacy(),
+        legacyQiankun({
+          name: 'nginx-ui',
+          devSandbox: true,
+        })
     ],
     css: {
       preprocessorOptions: {
@@ -64,11 +65,18 @@ export default defineConfig(({command, mode})=>{
             rewrite: path => path.replace(/^\/api/,"")
           }
         } : {
+          "/api/rdm/":{
+            // target: 'http://10.10.0.1:8080',
+            // target: 'http://10.10.0.1:38085',
+            target: 'http://127.0.0.1:38085',
+            rewrite: path => path.replace(/^\/api/,""),
+            ws: true
+          },
           "/api":{
             // target: 'http://10.10.0.1:8080',
             target: 'http://127.0.0.1:8080',
             rewrite: path => path.replace(/^\/api/,"")
-          }
+          },
         }
       }
     },

File diff suppressed because it is too large
+ 882 - 89
frontend/yarn.lock


Some files were not shown because too many files changed in this diff