add demo
This commit is contained in:
parent
7173d39a17
commit
ad3fe496ef
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "browser-apps",
|
"name": "browser-apps",
|
||||||
"version": "0.0.1",
|
"version": "0.0.2",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@ -29,6 +29,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@build/tailwind": "1.0.2-alpha-2",
|
"@build/tailwind": "1.0.2-alpha-2",
|
||||||
|
"@kevisual/types": "^0.0.3",
|
||||||
"@types/lodash-es": "^4.17.12",
|
"@types/lodash-es": "^4.17.12",
|
||||||
"@types/react": "^19.0.1",
|
"@types/react": "^19.0.1",
|
||||||
"@types/umami": "^2.10.0",
|
"@types/umami": "^2.10.0",
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { QueryRouterServer } from '@kevisual/router/browser';
|
import { QueryRouterServer } from '@kevisual/router/browser';
|
||||||
import { useContextKey } from '@kevisual/store/config';
|
import { useContextKey } from '@kevisual/store/config';
|
||||||
import { useConfigKey } from '@kevisual/store/config';
|
|
||||||
import { EventEmitter } from 'eventemitter3';
|
import { EventEmitter } from 'eventemitter3';
|
||||||
|
|
||||||
export const app = useContextKey('app', () => {
|
export const app = useContextKey('app', () => {
|
||||||
|
29
src/main.tsx
29
src/main.tsx
@ -8,33 +8,36 @@ import './page/index.css';
|
|||||||
import './main.css';
|
import './main.css';
|
||||||
|
|
||||||
import { Page } from '@kevisual/store/page';
|
import { Page } from '@kevisual/store/page';
|
||||||
import { AiChat } from './page/AiChat';
|
import { useContextKey } from '@kevisual/store/config';
|
||||||
|
|
||||||
const main = () => {
|
const main = () => {
|
||||||
start();
|
start();
|
||||||
};
|
};
|
||||||
main();
|
main();
|
||||||
|
|
||||||
const page = new Page({
|
const page = useContextKey('page', () => {
|
||||||
|
return new Page({
|
||||||
path: '',
|
path: '',
|
||||||
key: '',
|
key: '',
|
||||||
basename: '',
|
basename: '',
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
page.addPage('/', 'home');
|
page.addPage('/', 'home');
|
||||||
page.addPage('/ai', 'ai');
|
page.addPage('/ai', 'ai');
|
||||||
|
page.addPage('/list', 'list');
|
||||||
|
|
||||||
page.subscribe('home', (page) => {
|
page.subscribe('home', async (page) => {
|
||||||
const div = document.createElement('div');
|
const module = await import('./routes/home.ts');
|
||||||
|
module?.route(page);
|
||||||
div.className = 'text-4xl text-center p-4 bg-blue-200';
|
|
||||||
div.innerHTML = 'Browser Apps';
|
|
||||||
|
|
||||||
document.body.appendChild(div);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
page.subscribe('ai', (page) => {
|
page.subscribe('ai', async (page) => {
|
||||||
const aiChat = AiChat();
|
const module = await import('./routes/ai.ts');
|
||||||
console.log(aiChat);
|
module?.route();
|
||||||
document.body.appendChild(aiChat);
|
});
|
||||||
|
|
||||||
|
page.subscribe('list', async (page) => {
|
||||||
|
const module = await import('./routes/list.ts');
|
||||||
|
module?.route();
|
||||||
});
|
});
|
||||||
|
7
src/routes/ai.ts
Normal file
7
src/routes/ai.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import { AiChat } from '../page/AiChat';
|
||||||
|
|
||||||
|
export const route = () => {
|
||||||
|
const aiChat = AiChat();
|
||||||
|
console.log(aiChat);
|
||||||
|
document.body.appendChild(aiChat);
|
||||||
|
};
|
92
src/routes/home.ts
Normal file
92
src/routes/home.ts
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
import { QueryRouterServer } from '@kevisual/router/browser';
|
||||||
|
import { useContextKey } from '@kevisual/store/config';
|
||||||
|
type InitFn = () => any;
|
||||||
|
type InitModule = {
|
||||||
|
init?: boolean;
|
||||||
|
loaded?: boolean;
|
||||||
|
fn?: InitFn;
|
||||||
|
key?: string;
|
||||||
|
};
|
||||||
|
class UseInit {
|
||||||
|
modules = new Map<string, InitModule>();
|
||||||
|
callbacks = new Map<string, InitFn>();
|
||||||
|
constructor() {}
|
||||||
|
async run(fn: InitFn, key: string, force = false) {
|
||||||
|
if (this.modules.has(key)) {
|
||||||
|
const module = this.modules.get(key)!;
|
||||||
|
if (module.init) {
|
||||||
|
if (force) {
|
||||||
|
await module.fn?.();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await module.fn?.();
|
||||||
|
module.init = true;
|
||||||
|
} else {
|
||||||
|
this.modules.set(key, {
|
||||||
|
init: true,
|
||||||
|
fn,
|
||||||
|
key,
|
||||||
|
});
|
||||||
|
await fn();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const module = useContextKey<UseInit>('module', () => {
|
||||||
|
return new UseInit();
|
||||||
|
});
|
||||||
|
const app = useContextKey<QueryRouterServer>('app');
|
||||||
|
|
||||||
|
const loadApps = async () => {
|
||||||
|
app
|
||||||
|
.route({
|
||||||
|
path: 'dev',
|
||||||
|
key: 'preview-container',
|
||||||
|
})
|
||||||
|
.define(async (ctx) => {
|
||||||
|
const data = ctx.query?.data || {};
|
||||||
|
const code = data.code || '';
|
||||||
|
if (!code) {
|
||||||
|
ctx.throw?.(400, 'code is required');
|
||||||
|
}
|
||||||
|
const url = URL.createObjectURL(new Blob([code], { type: 'application/javascript' }));
|
||||||
|
console.log('dev route');
|
||||||
|
const module = await import(url);
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
if (module?.render) {
|
||||||
|
module.render();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.addTo(app);
|
||||||
|
};
|
||||||
|
export const route = async (page?: any) => {
|
||||||
|
console.log('home route page', page);
|
||||||
|
console.log('home route app', app);
|
||||||
|
const div = document.createElement('div');
|
||||||
|
|
||||||
|
div.className = 'text-4xl text-center p-4 bg-blue-200';
|
||||||
|
div.innerHTML = 'Browser Apps';
|
||||||
|
div.onclick = () => {
|
||||||
|
location.href = '/list';
|
||||||
|
};
|
||||||
|
document.body.appendChild(div);
|
||||||
|
module.run(() => {
|
||||||
|
loadApps();
|
||||||
|
}, 'home');
|
||||||
|
const res = await app.call({
|
||||||
|
path: 'dev',
|
||||||
|
key: 'preview-container',
|
||||||
|
payload: {
|
||||||
|
data: {
|
||||||
|
code: `
|
||||||
|
export const render = () => {
|
||||||
|
const div = document.createElement('div');
|
||||||
|
div.className = 'text-4xl text-center p-4 bg-blue-200';
|
||||||
|
div.innerHTML = 'Browser Apps Preview';
|
||||||
|
document.body.appendChild(div);
|
||||||
|
}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
console.log('res', res);
|
||||||
|
};
|
13
src/routes/list.ts
Normal file
13
src/routes/list.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { useContextKey } from '@kevisual/store/config';
|
||||||
|
import { Page } from '@kevisual/store/page';
|
||||||
|
|
||||||
|
export const route = () => {
|
||||||
|
console.log('list route');
|
||||||
|
const div = document.createElement('div');
|
||||||
|
div.className = 'text-4xl text-center p-4 bg-blue-200';
|
||||||
|
div.innerHTML = 'Browser Apps List';
|
||||||
|
div.onclick = () => {
|
||||||
|
location.href = '/';
|
||||||
|
};
|
||||||
|
document.body.appendChild(div);
|
||||||
|
};
|
@ -4,10 +4,12 @@ import path from 'path';
|
|||||||
import tailwindcss from 'tailwindcss';
|
import tailwindcss from 'tailwindcss';
|
||||||
import autoprefixer from 'autoprefixer';
|
import autoprefixer from 'autoprefixer';
|
||||||
import nesting from 'tailwindcss/nesting';
|
import nesting from 'tailwindcss/nesting';
|
||||||
|
import pkgs from './package.json' with { type: 'json' };
|
||||||
|
const version = pkgs.version || '0.0.1';
|
||||||
|
const isDev = process.env.NODE_ENV === 'development';
|
||||||
|
console.log('isDev', isDev);
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
root: '.',
|
root: '.',
|
||||||
// plugins: [react()],
|
|
||||||
css: {
|
css: {
|
||||||
postcss: {
|
postcss: {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@ -26,15 +28,29 @@ export default defineConfig({
|
|||||||
// '@kevisual/router/browser': 'https://kevisual.xiongxiao.me/system/lib/router-browser.js', // 将本地路径替换为远程 URL
|
// '@kevisual/router/browser': 'https://kevisual.xiongxiao.me/system/lib/router-browser.js', // 将本地路径替换为远程 URL
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
base: './',
|
||||||
build: {
|
build: {
|
||||||
minify: false,
|
minify: false,
|
||||||
outDir: './dist',
|
outDir: './dist',
|
||||||
rollupOptions: {
|
rollupOptions: {
|
||||||
external: ['react', 'react-dom'],
|
external: ['react'],
|
||||||
|
output: {
|
||||||
|
chunkFileNames: (chunkInfo) => {
|
||||||
|
if(isDev) {
|
||||||
|
return '[name].js';
|
||||||
|
}
|
||||||
|
if (chunkInfo.facadeModuleId && chunkInfo.facadeModuleId.includes('/routes/')) {
|
||||||
|
// 对以 routes/ 开头的代码分块使用不带 hash 的命名
|
||||||
|
return `routes/[name]-${version}.js`;
|
||||||
|
}
|
||||||
|
// 其他代码分块继续使用 hash
|
||||||
|
return '[name].[hash].js';
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
optimizeDeps: {
|
optimizeDeps: {
|
||||||
exclude: ['react', 'react-dom'], // 排除 react 和 react-dom 以避免打包
|
exclude: ['react'], // 排除 react 和 react-dom 以避免打包
|
||||||
},
|
},
|
||||||
esbuild: {
|
esbuild: {
|
||||||
jsxFactory: 'h',
|
jsxFactory: 'h',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user