mirror of https://github.com/alibaba/ice.git
feat: support remove router even if route count is greater than 1 (#6382)
* feat: support remove router even if route count is greater than 1 * fix: add test case * Update createService.ts * Update createService.ts
This commit is contained in:
parent
018238f904
commit
b691b9e96c
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
'@ice/runtime': patch
|
||||
'@ice/app': patch
|
||||
---
|
||||
|
||||
feat: support remove router even if route count is greater than 1
|
||||
|
|
@ -3,6 +3,6 @@ import { defineConfig } from '@ice/app';
|
|||
export default defineConfig(() => ({
|
||||
publicPath: '/',
|
||||
optimization: {
|
||||
router: true,
|
||||
disableRouter: true,
|
||||
},
|
||||
}));
|
||||
|
|
|
|||
|
|
@ -0,0 +1,7 @@
|
|||
const home = () => {
|
||||
return (
|
||||
<>home</>
|
||||
);
|
||||
};
|
||||
|
||||
export default home;
|
||||
|
|
@ -232,9 +232,10 @@ async function createService({ rootDir, command, commandArgs }: CreateServiceOpt
|
|||
const hasExportAppData = (await getFileExports({ rootDir, file: 'src/app' })).includes('dataLoader');
|
||||
const csr = !userConfig.ssr && !userConfig.ssg;
|
||||
|
||||
const disableRouter = userConfig?.optimization?.router && routesInfo.routesCount <= 1;
|
||||
const disableRouter = (userConfig?.optimization?.router && routesInfo.routesCount <= 1) ||
|
||||
userConfig?.optimization?.disableRouter;
|
||||
if (disableRouter) {
|
||||
logger.info('`optimization.router` is enabled and only have one route, ice build will remove react-router and history which is unnecessary.');
|
||||
logger.info('`optimization.router` is enabled, ice build will remove react-router and history which is unnecessary.');
|
||||
taskConfigs = mergeTaskConfig(taskConfigs, {
|
||||
alias: {
|
||||
'@ice/runtime/router': '@ice/runtime/single-router',
|
||||
|
|
|
|||
|
|
@ -13,9 +13,15 @@ interface SyntaxFeatures {
|
|||
|
||||
interface Optimization {
|
||||
/**
|
||||
* Optimize code by remove react-router dependencies when set to true.
|
||||
* Optimize code by remove react-router dependencies when set to true,
|
||||
* it only works when route count is 1.
|
||||
*/
|
||||
router?: boolean;
|
||||
/**
|
||||
* @private
|
||||
* Remove react-router dependencies by force, even if route count is greater than 1.
|
||||
*/
|
||||
disableRouter?: boolean;
|
||||
}
|
||||
|
||||
interface MinifyOptions {
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ interface RenderOptions {
|
|||
|
||||
async function render({ history, runtime, needHydrate }: RenderOptions) {
|
||||
const appContext = runtime.getAppContext();
|
||||
const { appConfig, loaderData, routes, basename } = appContext;
|
||||
const { appConfig, loaderData, routes, basename, routePath } = appContext;
|
||||
const appRender = runtime.getRender();
|
||||
const AppRuntimeProvider = runtime.composeAppProvider() || React.Fragment;
|
||||
const AppRouter = runtime.getAppRouter<ClientAppRouterProps>();
|
||||
|
|
@ -154,8 +154,9 @@ async function render({ history, runtime, needHydrate }: RenderOptions) {
|
|||
}
|
||||
const hydrationData = needHydrate ? { loaderData } : undefined;
|
||||
const routeModuleCache = {};
|
||||
const location = history.location ? history.location : { pathname: routePath || window.location.pathname };
|
||||
if (needHydrate) {
|
||||
const lazyMatches = matchRoutes(routes, history.location, basename).filter((m) => m.route.lazy);
|
||||
const lazyMatches = matchRoutes(routes, location, basename).filter((m) => m.route.lazy);
|
||||
if (lazyMatches?.length > 0) {
|
||||
// Load the lazy matches and update the routes before creating your router
|
||||
// so we can hydrate the SSR-rendered content synchronously.
|
||||
|
|
@ -182,8 +183,9 @@ async function render({ history, runtime, needHydrate }: RenderOptions) {
|
|||
let singleComponent = null;
|
||||
let routeData = null;
|
||||
if (process.env.ICE_CORE_ROUTER !== 'true') {
|
||||
const { Component, loader } = await loadRouteModule(routes[0], routeModuleCache);
|
||||
singleComponent = Component || routes[0].Component;
|
||||
const singleRoute = matchRoutes(routes, location, basename)[0];
|
||||
const { Component, loader } = await loadRouteModule(singleRoute.route, routeModuleCache);
|
||||
singleComponent = Component || singleRoute.route.Component;
|
||||
routeData = loader && await loader();
|
||||
}
|
||||
const renderRoot = appRender(
|
||||
|
|
|
|||
|
|
@ -42,15 +42,30 @@ export const createHistory = (): History => {
|
|||
};
|
||||
};
|
||||
|
||||
export const matchRoutes = (routes: any[]) => {
|
||||
return routes.map(item => {
|
||||
return {
|
||||
params: {},
|
||||
pathname: '',
|
||||
pathnameBase: '',
|
||||
route: item,
|
||||
const stripString = (str: string) => {
|
||||
const regexForSlash = /^\/|\/$/g;
|
||||
return str.replace(regexForSlash, '');
|
||||
};
|
||||
|
||||
export const matchRoutes = (routes: any[], location: Partial<Location> | string, basename: string) => {
|
||||
const stripedBasename = stripString(basename);
|
||||
const pathname = typeof location === 'string' ? location : location.pathname;
|
||||
let stripedPathname = stripString(pathname);
|
||||
if (stripedBasename) {
|
||||
stripedPathname = stripedPathname.replace(new RegExp(`^${stripedBasename}/`), '');
|
||||
}
|
||||
const route = routes.length === 1 ? routes[0] : routes.find(item => {
|
||||
return stripString(item.path || '') === stripedPathname;
|
||||
});
|
||||
if (!route) {
|
||||
throw new Error(`No route matched pathname: ${pathname}`);
|
||||
}
|
||||
return [{
|
||||
route,
|
||||
params: {},
|
||||
pathname,
|
||||
pathnameBase: '',
|
||||
}];
|
||||
};
|
||||
|
||||
export const Link = () => null;
|
||||
|
|
|
|||
|
|
@ -37,8 +37,54 @@ describe('single route api', () => {
|
|||
expect(createHistory().location).toBe('');
|
||||
});
|
||||
|
||||
it('matchRoutes', () => {
|
||||
expect(matchRoutes([{}])[0].pathname).toBe('');
|
||||
it('matchRoutes - single route', () => {
|
||||
const routes = [
|
||||
{
|
||||
path: 'users',
|
||||
element: <div>user</div>,
|
||||
},
|
||||
];
|
||||
const location = {
|
||||
pathname: '/test',
|
||||
};
|
||||
const matchedRoutes = matchRoutes(routes, location, '/');
|
||||
expect(matchedRoutes).toHaveLength(1);
|
||||
expect(matchedRoutes[0].route.path).toBe('users');
|
||||
});
|
||||
|
||||
it('matchRoutes - mutiple route', () => {
|
||||
const routes = [
|
||||
{
|
||||
path: 'users',
|
||||
element: <div>user</div>,
|
||||
},
|
||||
{
|
||||
path: 'posts',
|
||||
element: <div>post</div>,
|
||||
},
|
||||
];
|
||||
const location = {
|
||||
pathname: '/posts',
|
||||
};
|
||||
const matchedRoutes = matchRoutes(routes, location, '/');
|
||||
expect(matchedRoutes).toHaveLength(1);
|
||||
expect(matchedRoutes[0].route.path).toBe('posts');
|
||||
});
|
||||
|
||||
it('matchRoutes - basename', () => {
|
||||
const routes = [
|
||||
{
|
||||
path: 'users',
|
||||
element: <div>user</div>,
|
||||
},
|
||||
{
|
||||
path: 'posts',
|
||||
element: <div>post</div>,
|
||||
},
|
||||
];
|
||||
const matchedRoutes = matchRoutes(routes, '/basename/posts', '/basename');
|
||||
expect(matchedRoutes).toHaveLength(1);
|
||||
expect(matchedRoutes[0].route.path).toBe('posts');
|
||||
});
|
||||
|
||||
it('Link', () => {
|
||||
|
|
|
|||
Loading…
Reference in New Issue