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(() => ({ | export default defineConfig(() => ({ | ||||||
|   publicPath: '/', |   publicPath: '/', | ||||||
|   optimization: { |   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 hasExportAppData = (await getFileExports({ rootDir, file: 'src/app' })).includes('dataLoader'); | ||||||
|   const csr = !userConfig.ssr && !userConfig.ssg; |   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) { |   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, { |     taskConfigs = mergeTaskConfig(taskConfigs, { | ||||||
|       alias: { |       alias: { | ||||||
|         '@ice/runtime/router': '@ice/runtime/single-router', |         '@ice/runtime/router': '@ice/runtime/single-router', | ||||||
|  |  | ||||||
|  | @ -13,9 +13,15 @@ interface SyntaxFeatures { | ||||||
| 
 | 
 | ||||||
| interface Optimization { | 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; |   router?: boolean; | ||||||
|  |   /** | ||||||
|  |    * @private | ||||||
|  |    * Remove react-router dependencies by force, even if route count is greater than 1. | ||||||
|  |    */ | ||||||
|  |   disableRouter?: boolean; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| interface MinifyOptions { | interface MinifyOptions { | ||||||
|  |  | ||||||
|  | @ -139,7 +139,7 @@ interface RenderOptions { | ||||||
| 
 | 
 | ||||||
| async function render({ history, runtime, needHydrate }: RenderOptions) { | async function render({ history, runtime, needHydrate }: RenderOptions) { | ||||||
|   const appContext = runtime.getAppContext(); |   const appContext = runtime.getAppContext(); | ||||||
|   const { appConfig, loaderData, routes, basename } = appContext; |   const { appConfig, loaderData, routes, basename, routePath } = appContext; | ||||||
|   const appRender = runtime.getRender(); |   const appRender = runtime.getRender(); | ||||||
|   const AppRuntimeProvider = runtime.composeAppProvider() || React.Fragment; |   const AppRuntimeProvider = runtime.composeAppProvider() || React.Fragment; | ||||||
|   const AppRouter = runtime.getAppRouter<ClientAppRouterProps>(); |   const AppRouter = runtime.getAppRouter<ClientAppRouterProps>(); | ||||||
|  | @ -154,8 +154,9 @@ async function render({ history, runtime, needHydrate }: RenderOptions) { | ||||||
|   } |   } | ||||||
|   const hydrationData = needHydrate ? { loaderData } : undefined; |   const hydrationData = needHydrate ? { loaderData } : undefined; | ||||||
|   const routeModuleCache = {}; |   const routeModuleCache = {}; | ||||||
|  |   const location = history.location ? history.location : { pathname: routePath || window.location.pathname }; | ||||||
|   if (needHydrate) { |   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) { |     if (lazyMatches?.length > 0) { | ||||||
|       // Load the lazy matches and update the routes before creating your router
 |       // Load the lazy matches and update the routes before creating your router
 | ||||||
|       // so we can hydrate the SSR-rendered content synchronously.
 |       // so we can hydrate the SSR-rendered content synchronously.
 | ||||||
|  | @ -182,8 +183,9 @@ async function render({ history, runtime, needHydrate }: RenderOptions) { | ||||||
|   let singleComponent = null; |   let singleComponent = null; | ||||||
|   let routeData = null; |   let routeData = null; | ||||||
|   if (process.env.ICE_CORE_ROUTER !== 'true') { |   if (process.env.ICE_CORE_ROUTER !== 'true') { | ||||||
|     const { Component, loader } = await loadRouteModule(routes[0], routeModuleCache); |     const singleRoute = matchRoutes(routes, location, basename)[0]; | ||||||
|     singleComponent = Component || routes[0].Component; |     const { Component, loader } = await loadRouteModule(singleRoute.route, routeModuleCache); | ||||||
|  |     singleComponent = Component || singleRoute.route.Component; | ||||||
|     routeData = loader && await loader(); |     routeData = loader && await loader(); | ||||||
|   } |   } | ||||||
|   const renderRoot = appRender( |   const renderRoot = appRender( | ||||||
|  |  | ||||||
|  | @ -42,15 +42,30 @@ export const createHistory = (): History => { | ||||||
|   }; |   }; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| export const matchRoutes = (routes: any[]) => { | const stripString = (str: string) => { | ||||||
|   return routes.map(item => { |   const regexForSlash = /^\/|\/$/g; | ||||||
|     return { |   return str.replace(regexForSlash, ''); | ||||||
|       params: {}, | }; | ||||||
|       pathname: '', | 
 | ||||||
|       pathnameBase: '', | export const matchRoutes = (routes: any[], location: Partial<Location> | string, basename: string) => { | ||||||
|       route: item, |   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; | export const Link = () => null; | ||||||
|  |  | ||||||
|  | @ -37,8 +37,54 @@ describe('single route api', () => { | ||||||
|     expect(createHistory().location).toBe(''); |     expect(createHistory().location).toBe(''); | ||||||
|   }); |   }); | ||||||
| 
 | 
 | ||||||
|   it('matchRoutes', () => { |   it('matchRoutes - single route', () => { | ||||||
|     expect(matchRoutes([{}])[0].pathname).toBe(''); |     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', () => { |   it('Link', () => { | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue