mirror of https://github.com/alibaba/ice.git
Compare commits
12 Commits
393437a8a7
...
8ced7adf79
Author | SHA1 | Date |
---|---|---|
|
8ced7adf79 | |
|
2742ac4678 | |
|
fcc25dc3fd | |
|
8e27933423 | |
|
8bc00a2115 | |
|
b03194e046 | |
|
89fec6198d | |
|
cb35145ff3 | |
|
3280dbf433 | |
|
7fdb3ae845 | |
|
f048b31327 | |
|
a5d13dcfd3 |
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
'@ice/runtime': patch
|
||||
---
|
||||
|
||||
fix: duplicate css
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
'@ice/app': patch
|
||||
---
|
||||
|
||||
feat: support lazy compile of routes
|
|
@ -48,7 +48,9 @@ Please see our [CONTRIBUTING.md](/.github/CONTRIBUTING.md)
|
|||
|
||||
Contributors can contact us to join the Contributor Group.
|
||||
|
||||
<a href="https://github.com/alibaba/ice/graphs/contributors"><img src="https://alibaba.github.io/ice/ice.png" /></a>
|
||||
<a href="https://openomy.com/alibaba/ice" target="_blank" style="display: block; width: 100%;" align="center">
|
||||
<img src="https://openomy.com/svg?repo=alibaba/ice&chart=bubble&latestMonth=6" target="_blank" alt="Contribution Leaderboard" style="display: block; width: 100%;" />
|
||||
</a>
|
||||
|
||||
## Community
|
||||
|
||||
|
|
|
@ -6,9 +6,11 @@ import type { Config } from '@ice/shared-config/types';
|
|||
import createMockMiddleware from '../../middlewares/mock/createMiddleware.js';
|
||||
import createRenderMiddleware from '../../middlewares/renderMiddleware.js';
|
||||
import createDataLoaderMiddleware from '../../middlewares/dataLoaderMiddleware.js';
|
||||
import createProxyModuleMiddleware from '../../middlewares/proxyModuleMiddleware.js';
|
||||
import type { UserConfig } from '../../types/userConfig.js';
|
||||
import type RouteManifest from '../../utils/routeManifest.js';
|
||||
import type { GetAppConfig } from '../../types/plugin.js';
|
||||
import type Generator from '../../service/runtimeGenerator.js';
|
||||
|
||||
interface SetupOptions {
|
||||
userConfig: UserConfig;
|
||||
|
@ -18,7 +20,9 @@ interface SetupOptions {
|
|||
excuteServerEntry: () => Promise<any>;
|
||||
mock: boolean;
|
||||
rootDir: string;
|
||||
open?: boolean | string;
|
||||
dataLoaderCompiler?: Compiler;
|
||||
generator?: Generator;
|
||||
}
|
||||
|
||||
function setupMiddlewares(middlewares: Parameters<DevServerConfiguration['setupMiddlewares']>[0], {
|
||||
|
@ -30,8 +34,10 @@ function setupMiddlewares(middlewares: Parameters<DevServerConfiguration['setupM
|
|||
mock,
|
||||
rootDir,
|
||||
dataLoaderCompiler,
|
||||
generator,
|
||||
open,
|
||||
}: SetupOptions) {
|
||||
const { ssr, ssg } = userConfig;
|
||||
const { ssr, ssg, routes } = userConfig;
|
||||
let renderMode: RenderMode;
|
||||
// If ssr is set to true, use ssr for preview.
|
||||
if (ssr) {
|
||||
|
@ -56,6 +62,21 @@ function setupMiddlewares(middlewares: Parameters<DevServerConfiguration['setupM
|
|||
middlewares.unshift(dataLoaderMiddleware);
|
||||
}
|
||||
|
||||
if (routes?.lazyCompile) {
|
||||
const proxyModuleMiddleware = createProxyModuleMiddleware({
|
||||
manifest: routeManifest.getNestedRoute(),
|
||||
rootDir,
|
||||
generator,
|
||||
defaultPath: typeof open === 'string' ? open : '/',
|
||||
});
|
||||
// @ts-ignore property of name is exist.
|
||||
const staticIndex = middlewares.findIndex(({ name }) => name === 'express-static');
|
||||
middlewares.splice(
|
||||
staticIndex, 0,
|
||||
proxyModuleMiddleware,
|
||||
);
|
||||
}
|
||||
|
||||
// @ts-ignore property of name is exist.
|
||||
const insertIndex = middlewares.findIndex(({ name }) => name === 'serve-index');
|
||||
middlewares.splice(
|
||||
|
|
|
@ -18,6 +18,7 @@ async function bundler(
|
|||
routeManifest,
|
||||
appConfig,
|
||||
hasDataLoader,
|
||||
generator,
|
||||
} = options;
|
||||
let compiler: MultiCompiler;
|
||||
let dataLoaderCompiler: Compiler;
|
||||
|
@ -63,6 +64,7 @@ async function bundler(
|
|||
hooksAPI,
|
||||
taskConfigs,
|
||||
rspackConfigs,
|
||||
generator,
|
||||
};
|
||||
if (command === 'start') {
|
||||
// @ts-expect-error dev-server has been pre-packed, so it will have different type.
|
||||
|
|
|
@ -16,6 +16,7 @@ const start = async ({
|
|||
compiler,
|
||||
appConfig,
|
||||
hooksAPI,
|
||||
generator,
|
||||
}: BuildOptions, dataLoaderCompiler?: Compiler) => {
|
||||
const { rootDir, applyHook, commandArgs, userConfig, extendsPluginAPI: { excuteServerEntry } } = context;
|
||||
const customMiddlewares = rspackConfigs[0].devServer?.setupMiddlewares;
|
||||
|
@ -32,8 +33,10 @@ const start = async ({
|
|||
taskConfig: webTaskConfig,
|
||||
excuteServerEntry,
|
||||
mock: commandArgs.mock,
|
||||
open: commandArgs.open,
|
||||
rootDir,
|
||||
dataLoaderCompiler,
|
||||
generator,
|
||||
});
|
||||
return customMiddlewares ? customMiddlewares(builtInMiddlewares, devServer) : builtInMiddlewares;
|
||||
},
|
||||
|
|
|
@ -8,6 +8,7 @@ import type { ServerCompiler, GetAppConfig, GetRoutesConfig, GetDataloaderConfig
|
|||
import type { UserConfig } from '../types/userConfig.js';
|
||||
import type RouteManifest from '../utils/routeManifest.js';
|
||||
import type ServerRunner from '../service/ServerRunner.js';
|
||||
import type Generator from '../service/runtimeGenerator.js';
|
||||
|
||||
export type Context = DefaultContext<Config, ExtendsPluginAPI>;
|
||||
|
||||
|
@ -19,9 +20,11 @@ export interface BuildOptions {
|
|||
appConfig: BundlerOptions['appConfig'];
|
||||
hooksAPI: BundlerOptions['hooksAPI'];
|
||||
taskConfigs: BundlerOptions['taskConfigs'];
|
||||
generator: Generator;
|
||||
}
|
||||
|
||||
export interface BundlerOptions {
|
||||
generator: Generator;
|
||||
taskConfigs: TaskConfig<Config>[];
|
||||
spinner: ora.Ora;
|
||||
hooksAPI: {
|
||||
|
|
|
@ -27,6 +27,7 @@ export async function startDevServer(
|
|||
routeManifest,
|
||||
userConfig,
|
||||
appConfig,
|
||||
generator,
|
||||
} = options;
|
||||
const routePaths = routeManifest.getFlattenRoute().sort((a, b) =>
|
||||
// Sort by length, shortest path first.
|
||||
|
@ -40,12 +41,14 @@ export async function startDevServer(
|
|||
...defaultDevServerConfig,
|
||||
setupMiddlewares: (middlewares, devServer) => {
|
||||
const builtInMiddlewares = getMiddlewares(middlewares, {
|
||||
generator,
|
||||
userConfig,
|
||||
routeManifest,
|
||||
getAppConfig: hooksAPI.getAppConfig,
|
||||
taskConfig: webTaskConfig,
|
||||
excuteServerEntry,
|
||||
mock: commandArgs.mock,
|
||||
open: commandArgs.open,
|
||||
rootDir,
|
||||
});
|
||||
return customMiddlewares ? customMiddlewares(builtInMiddlewares, devServer) : builtInMiddlewares;
|
||||
|
|
|
@ -40,6 +40,7 @@ import rspackBundler from './bundler/rspack/index.js';
|
|||
import getDefaultTaskConfig from './plugins/task.js';
|
||||
import { multipleServerEntry, renderMultiEntry } from './utils/multipleEntry.js';
|
||||
import hasDocument from './utils/hasDocument.js';
|
||||
import { addLeadingSlash } from './utils/slash.js';
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
|
@ -66,6 +67,10 @@ async function createService({ rootDir, command, commandArgs }: CreateServiceOpt
|
|||
templates: [coreTemplate],
|
||||
});
|
||||
|
||||
if (commandArgs.open) {
|
||||
commandArgs.open = typeof commandArgs.open === 'string' ? addLeadingSlash(commandArgs.open) : commandArgs.open;
|
||||
}
|
||||
|
||||
const { addWatchEvent, removeWatchEvent } = createWatch({
|
||||
watchDir: rootDir,
|
||||
command,
|
||||
|
@ -221,6 +226,7 @@ async function createService({ rootDir, command, commandArgs }: CreateServiceOpt
|
|||
const { userConfig } = ctx;
|
||||
const { routes: routesConfig, server, syntaxFeatures, polyfill } = userConfig;
|
||||
|
||||
|
||||
const coreEnvKeys = getCoreEnvKeys();
|
||||
|
||||
const routesInfo = await generateRoutesInfo(rootDir, routesConfig, routeManifest.getRoutesDefinitions());
|
||||
|
@ -252,6 +258,7 @@ async function createService({ rootDir, command, commandArgs }: CreateServiceOpt
|
|||
const { routeImports, routeDefinition } = getRoutesDefinition({
|
||||
manifest: routesInfo.routes,
|
||||
lazy,
|
||||
compileRoutes: routesConfig?.lazyCompile && command === 'start' ? [commandArgs.open || '/'] : undefined,
|
||||
});
|
||||
const loaderExports = hasExportAppData || Boolean(routesInfo.loaders);
|
||||
const hasDataLoader = Boolean(userConfig.dataLoader) && loaderExports;
|
||||
|
@ -301,6 +308,9 @@ async function createService({ rootDir, command, commandArgs }: CreateServiceOpt
|
|||
generator.addRenderFile('core/entry.server.ts.ejs', FALLBACK_ENTRY, { hydrate: false });
|
||||
}
|
||||
|
||||
if (routesConfig?.lazyCompile && command === 'start') {
|
||||
generator.addRenderFile('core/empty.tsx.ejs', 'empty.tsx');
|
||||
}
|
||||
if (typeof userConfig.dataLoader === 'object' && userConfig.dataLoader.fetcher) {
|
||||
const {
|
||||
packageName,
|
||||
|
@ -401,6 +411,7 @@ async function createService({ rootDir, command, commandArgs }: CreateServiceOpt
|
|||
userConfig,
|
||||
configFile,
|
||||
hasDataLoader,
|
||||
generator,
|
||||
};
|
||||
try {
|
||||
if (command === 'test') {
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import type { ExpressRequestHandler, Middleware } from 'webpack-dev-server';
|
||||
import type { NestedRouteManifest } from '@ice/route-manifest';
|
||||
import { getRoutesDefinition } from '../routes.js';
|
||||
import { RUNTIME_TMP_DIR } from '../constant.js';
|
||||
import type Generator from '../service/runtimeGenerator.js';
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
interface Options {
|
||||
manifest: NestedRouteManifest[];
|
||||
generator: Generator;
|
||||
rootDir: string;
|
||||
defaultPath: string;
|
||||
}
|
||||
|
||||
export default function createRenderMiddleware(options: Options): Middleware {
|
||||
const {
|
||||
manifest,
|
||||
generator,
|
||||
rootDir,
|
||||
defaultPath,
|
||||
} = options;
|
||||
const accessedPath = new Set<string>(defaultPath);
|
||||
|
||||
const middleware: ExpressRequestHandler = async function (req, res, next) {
|
||||
if (req.path === '/proxy-module') {
|
||||
if (!accessedPath.has(req.query.pathname)) {
|
||||
accessedPath.add(req.query.pathname);
|
||||
const { routeImports, routeDefinition } = getRoutesDefinition({
|
||||
manifest,
|
||||
lazy: true,
|
||||
compileRoutes: Array.from(accessedPath),
|
||||
});
|
||||
const templateDir = path.join(__dirname, '../../templates/core/');
|
||||
generator.renderFile(
|
||||
path.join(templateDir, 'routes.tsx.ejs'),
|
||||
path.join(rootDir, RUNTIME_TMP_DIR, 'routes.tsx'),
|
||||
{ routeImports, routeDefinition },
|
||||
);
|
||||
}
|
||||
|
||||
res.send('');
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
name: 'proxy-module',
|
||||
middleware,
|
||||
};
|
||||
}
|
|
@ -69,10 +69,11 @@ interface GetDefinationOptions {
|
|||
lazy?: boolean;
|
||||
depth?: number;
|
||||
matchRoute?: (route: NestedRouteManifest) => boolean;
|
||||
compileRoutes?: string[];
|
||||
}
|
||||
|
||||
export function getRoutesDefinition(options: GetDefinationOptions) {
|
||||
const { manifest, lazy = false, depth = 0, matchRoute = () => true } = options;
|
||||
const { manifest, lazy = false, depth = 0, matchRoute = () => true, compileRoutes } = options;
|
||||
const routeImports: string[] = [];
|
||||
const routeDefinition = manifest.reduce((prev, route) => {
|
||||
if (!matchRoute(route)) {
|
||||
|
@ -80,10 +81,13 @@ export function getRoutesDefinition(options: GetDefinationOptions) {
|
|||
}
|
||||
const { children, path: routePath, index, componentName, file, id, layout, exports } = route;
|
||||
const componentPath = id.startsWith('__') ? file : getFilePath(file);
|
||||
|
||||
const proxyModule = './empty';
|
||||
let loadStatement = '';
|
||||
if (lazy) {
|
||||
loadStatement = `import(/* webpackChunkName: "p_${componentName}" */ '${formatPath(componentPath)}')`;
|
||||
const filePath = compileRoutes && !layout
|
||||
? (compileRoutes.includes(`/${routePath || ''}`) ? componentPath : proxyModule)
|
||||
: componentPath;
|
||||
loadStatement = `import(/* webpackChunkName: "p_${componentName}" */ '${formatPath(filePath)}')`;
|
||||
} else {
|
||||
const routeSpecifier = formatRouteSpecifier(id);
|
||||
routeImports.push(`import * as ${routeSpecifier} from '${formatPath(componentPath)}';`);
|
||||
|
@ -128,6 +132,7 @@ export function getRoutesDefinition(options: GetDefinationOptions) {
|
|||
lazy,
|
||||
depth: depth + 1,
|
||||
matchRoute,
|
||||
compileRoutes,
|
||||
});
|
||||
routeImports.push(...res.routeImports);
|
||||
routeProperties.push(`children: [${res.routeDefinition}]`);
|
||||
|
|
|
@ -167,6 +167,10 @@ export interface UserConfig {
|
|||
* inject initial route path for each route html.
|
||||
*/
|
||||
injectInitialEntry?: boolean;
|
||||
/**
|
||||
* Enable lazy compile for routes.
|
||||
*/
|
||||
lazyCompile?: boolean;
|
||||
};
|
||||
/**
|
||||
* Add ice.js plugin to customize framework config.
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
export const addLeadingSlash = (path: string) => {
|
||||
return path.charAt(0) === '/' ? path : `/${path}`;
|
||||
};
|
|
@ -0,0 +1,12 @@
|
|||
import { useEffect } from 'react';
|
||||
import { useLocation } from 'ice';
|
||||
|
||||
const ProxyModule = () => {
|
||||
const location = useLocation();
|
||||
useEffect(() => {
|
||||
fetch(`/proxy-module?pathname=${location.pathname}`);
|
||||
}, []);
|
||||
return <></>;
|
||||
};
|
||||
|
||||
export default ProxyModule;
|
|
@ -57,7 +57,7 @@
|
|||
},
|
||||
"peerDependencies": {
|
||||
"@ice/app": "^3.6.4",
|
||||
"@ice/runtime": "^1.5.6"
|
||||
"@ice/runtime": "^1.5.7"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
|
|
@ -51,7 +51,7 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@ice/app": "^3.6.4",
|
||||
"@ice/runtime": "^1.5.6",
|
||||
"@ice/runtime": "^1.5.7",
|
||||
"webpack": "^5.88.0"
|
||||
},
|
||||
"repository": {
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
# @ice/runtime
|
||||
|
||||
## 1.5.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- 4ff29969c: feat: add SuspenseWrappers to Runtime
|
||||
|
||||
## 1.5.6
|
||||
|
||||
### Patch Changes
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@ice/runtime",
|
||||
"version": "1.5.6",
|
||||
"version": "1.5.7",
|
||||
"description": "Runtime module for ice.js",
|
||||
"type": "module",
|
||||
"types": "./esm/index.d.ts",
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import * as React from 'react';
|
||||
import type { WindowContext, RouteMatch, AssetsManifest } from './types.js';
|
||||
import { useAppContext, useAppData } from './AppContext.js';
|
||||
import { getMeta, getTitle, getLinks, getScripts } from './routesConfig.js';
|
||||
import { getLinks, getMeta, getScripts, getTitle } from './routesConfig.js';
|
||||
import type { AssetsManifest, RouteMatch, WindowContext } from './types.js';
|
||||
import getCurrentRoutePath from './utils/getCurrentRoutePath.js';
|
||||
|
||||
interface DocumentContext {
|
||||
|
@ -81,7 +81,15 @@ export const Links: LinksType = (props: LinksProps) => {
|
|||
const routeLinks = getLinks(matches, loaderData);
|
||||
const pageAssets = getPageAssets(matches, assetsManifest);
|
||||
const entryAssets = getEntryAssets(assetsManifest);
|
||||
const styles = entryAssets.concat(pageAssets).filter(path => path.indexOf('.css') > -1);
|
||||
let styles = entryAssets.concat(pageAssets).filter(path => path.indexOf('.css') > -1);
|
||||
|
||||
// Unique styles for duplicate CSS files.
|
||||
const cssSet = {};
|
||||
styles = styles.filter((style) => {
|
||||
if (cssSet[style]) return false;
|
||||
cssSet[style] = true;
|
||||
return true;
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
|
@ -135,7 +135,8 @@ export function withSuspense(Component) {
|
|||
return (props: SuspenseProps) => {
|
||||
const { fallback, id, ...componentProps } = props;
|
||||
|
||||
const [suspenseState, updateSuspenseData] = React.useState({
|
||||
|
||||
const [suspenseState, updateSuspenseData] = React.useState<SuspenseState>({
|
||||
id: id,
|
||||
data: null,
|
||||
done: false,
|
||||
|
@ -156,24 +157,47 @@ export function withSuspense(Component) {
|
|||
updateSuspenseData(newState);
|
||||
}
|
||||
|
||||
return (
|
||||
<React.Suspense fallback={fallback || null}>
|
||||
|
||||
// Get SuspenseWrappers from app context
|
||||
const { SuspenseWrappers = [] } = useAppContext();
|
||||
|
||||
// Compose SuspenseWrappers
|
||||
const composeSuspenseWrappers = React.useCallback(
|
||||
(children: React.ReactNode) => {
|
||||
if (!SuspenseWrappers.length) return children;
|
||||
|
||||
return SuspenseWrappers.reduce((WrappedComponent, wrapperConfig) => {
|
||||
const { Wrapper } = wrapperConfig;
|
||||
return <Wrapper id={id}>{WrappedComponent}</Wrapper>;
|
||||
}, children);
|
||||
},
|
||||
[SuspenseWrappers, id],
|
||||
);
|
||||
|
||||
const wrappedComponent = (
|
||||
<>
|
||||
<InlineScript
|
||||
id={`suspense-parse-start-${id}`}
|
||||
script={`(${DISPATCH_SUSPENSE_EVENT_STRING})('ice-suspense-parse-start','${id}');`}
|
||||
/>
|
||||
<SuspenseContext.Provider value={suspenseState}>
|
||||
<Component {...componentProps} />
|
||||
<InlineScript
|
||||
id={`suspense-parse-data-${id}`}
|
||||
script={`(${DISPATCH_SUSPENSE_EVENT_STRING})('ice-suspense-parse-data','${id}');`}
|
||||
/>
|
||||
<Data id={id} />
|
||||
</SuspenseContext.Provider>
|
||||
<Component {...componentProps} />
|
||||
<InlineScript
|
||||
id={`suspense-parse-data-${id}`}
|
||||
script={`(${DISPATCH_SUSPENSE_EVENT_STRING})('ice-suspense-parse-data','${id}');`}
|
||||
/>
|
||||
<Data id={id} />
|
||||
<InlineScript
|
||||
id={`suspense-parse-end-${id}`}
|
||||
script={`(${DISPATCH_SUSPENSE_EVENT_STRING})('ice-suspense-parse-end','${id}');`}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
return (
|
||||
<React.Suspense fallback={fallback || null}>
|
||||
<SuspenseContext.Provider value={suspenseState}>
|
||||
{composeSuspenseWrappers(wrappedComponent)}
|
||||
</SuspenseContext.Provider>
|
||||
</React.Suspense>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -12,7 +12,9 @@ import type {
|
|||
SetAppRouter,
|
||||
AddProvider,
|
||||
AddWrapper,
|
||||
AddSuspenseWrapper,
|
||||
RouteWrapperConfig,
|
||||
SuspenseWrapperConfig,
|
||||
SetRender,
|
||||
AppRouterProps,
|
||||
ComponentWithChildren,
|
||||
|
@ -33,6 +35,8 @@ class Runtime {
|
|||
|
||||
private RouteWrappers: RouteWrapperConfig[];
|
||||
|
||||
private SuspenseWrappers: SuspenseWrapperConfig[];
|
||||
|
||||
private render: Renderer;
|
||||
|
||||
private responseHandlers: ResponseHandler[];
|
||||
|
@ -46,6 +50,7 @@ class Runtime {
|
|||
return root;
|
||||
};
|
||||
this.RouteWrappers = [];
|
||||
this.SuspenseWrappers = [];
|
||||
this.runtimeOptions = runtimeOptions;
|
||||
this.responseHandlers = [];
|
||||
this.getAppRouter = this.getAppRouter.bind(this);
|
||||
|
@ -55,6 +60,7 @@ class Runtime {
|
|||
return {
|
||||
...this.appContext,
|
||||
RouteWrappers: this.RouteWrappers,
|
||||
SuspenseWrappers: this.SuspenseWrappers,
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -72,6 +78,8 @@ class Runtime {
|
|||
|
||||
public getWrappers = () => this.RouteWrappers;
|
||||
|
||||
public getSuspenseWrappers = () => this.SuspenseWrappers;
|
||||
|
||||
public loadModule(module: RuntimePlugin | StaticRuntimePlugin | CommonJsRuntime) {
|
||||
let runtimeAPI: RuntimeAPI = {
|
||||
addProvider: this.addProvider,
|
||||
|
@ -80,6 +88,7 @@ class Runtime {
|
|||
getAppRouter: this.getAppRouter,
|
||||
setRender: this.setRender,
|
||||
addWrapper: this.addWrapper,
|
||||
addSuspenseWrapper: this.addSuspenseWrapper,
|
||||
appContext: this.appContext,
|
||||
setAppRouter: this.setAppRouter,
|
||||
useData: process.env.ICE_CORE_ROUTER === 'true' ? useData : useSingleRouterData,
|
||||
|
@ -122,6 +131,12 @@ class Runtime {
|
|||
});
|
||||
};
|
||||
|
||||
private addSuspenseWrapper: AddSuspenseWrapper = (Wrapper) => {
|
||||
this.SuspenseWrappers.push({
|
||||
Wrapper,
|
||||
});
|
||||
};
|
||||
|
||||
public setAppRouter: SetAppRouter = (AppRouter) => {
|
||||
this.AppRouter = AppRouter;
|
||||
};
|
||||
|
|
|
@ -117,6 +117,7 @@ export interface AppContext {
|
|||
loaderData?: LoadersData;
|
||||
routeModules?: RouteModules;
|
||||
RouteWrappers?: RouteWrapperConfig[];
|
||||
SuspenseWrappers?: SuspenseWrapperConfig[];
|
||||
routePath?: string;
|
||||
matches?: RouteMatch[];
|
||||
routes?: RouteItem[];
|
||||
|
@ -187,16 +188,26 @@ export interface RouteWrapperConfig {
|
|||
|
||||
export type AppProvider = ComponentWithChildren<any>;
|
||||
export type RouteWrapper = ComponentType<any>;
|
||||
|
||||
export type SuspenseWrapper = ComponentWithChildren<{
|
||||
id: string;
|
||||
}>;
|
||||
|
||||
export type ResponseHandler = (
|
||||
req: IncomingMessage,
|
||||
res: ServerResponse,
|
||||
) => any | Promise<any>;
|
||||
|
||||
export interface SuspenseWrapperConfig {
|
||||
Wrapper: SuspenseWrapper;
|
||||
}
|
||||
|
||||
export type SetAppRouter = <T>(AppRouter: ComponentType<T>) => void;
|
||||
export type GetAppRouter = () => AppProvider;
|
||||
export type AddProvider = (Provider: AppProvider) => void;
|
||||
export type SetRender = (render: Renderer) => void;
|
||||
export type AddWrapper = (wrapper: RouteWrapper, forLayout?: boolean) => void;
|
||||
export type AddSuspenseWrapper = (wrapper: SuspenseWrapper) => void;
|
||||
export type AddResponseHandler = (handler: ResponseHandler) => void;
|
||||
export type GetResponseHandlers = () => ResponseHandler[];
|
||||
|
||||
|
@ -227,6 +238,7 @@ export interface RuntimeAPI {
|
|||
getResponseHandlers: GetResponseHandlers;
|
||||
setRender: SetRender;
|
||||
addWrapper: AddWrapper;
|
||||
addSuspenseWrapper: AddSuspenseWrapper;
|
||||
appContext: AppContext;
|
||||
useData: UseData;
|
||||
useConfig: UseConfig;
|
||||
|
|
|
@ -2160,7 +2160,7 @@ importers:
|
|||
specifier: ^3.6.4
|
||||
version: link:../ice
|
||||
'@ice/runtime':
|
||||
specifier: ^1.5.6
|
||||
specifier: ^1.5.7
|
||||
version: link:../runtime
|
||||
webpack:
|
||||
specifier: ^5.88.0
|
||||
|
|
Loading…
Reference in New Issue