diff --git a/packages/client-utils/src/preload.ts b/packages/client-utils/src/preload.ts index 7499e76c7..cbc9bf5c4 100644 --- a/packages/client-utils/src/preload.ts +++ b/packages/client-utils/src/preload.ts @@ -4,16 +4,25 @@ import { pathToRegexp } from 'path-to-regexp' declare const window: IWindow -const preloadComponent = async (Routes: ReactClientESMFeRouteItem[]) => { +const preloadComponent = async (Routes: ReactClientESMFeRouteItem[], BASE_NAME?: string) => { // 预加载当前页面对应的组件 - const pathName = location.pathname for (const route of Routes) { const { component, path } = route let activeComponent = component if (window.__USE_VITE__) { route.component = (await activeComponent()).default } else { - if (activeComponent.preload && pathToRegexp(path).test(pathName)) { + let pathname = location.pathname + if (BASE_NAME) { + pathname = path.replace(BASE_NAME, '') + if (path.startsWith('//')) { + pathname = path.replace('//', '/') + } + if (!path.startsWith('/')) { + pathname = `/${pathname}` + } + } + if (activeComponent.preload && pathToRegexp(path).test(pathname)) { // 针对 react-loadble 包裹的组件 activeComponent = (await activeComponent.preload()).default } diff --git a/packages/plugin-react/src/entry/client-entry.tsx b/packages/plugin-react/src/entry/client-entry.tsx index 17e8f1684..99d0e0b3b 100644 --- a/packages/plugin-react/src/entry/client-entry.tsx +++ b/packages/plugin-react/src/entry/client-entry.tsx @@ -8,7 +8,7 @@ import { IWindow, LayoutProps, ReactClientESMFeRouteItem, ReactClientRoutesType import * as Routes from 'ssr-temporary-routes' import { AppContext } from './context' -const { FeRoutes, layoutFetch, App } = Routes as ReactClientRoutesType +const { FeRoutes, layoutFetch, App, BASE_NAME } = Routes as ReactClientRoutesType declare const module: any declare const window: IWindow @@ -18,9 +18,10 @@ const clientRender = async (): Promise => { return props.children! } // 客户端渲染||hydrate - const routes = await preloadComponent(FeRoutes) + const routes = await preloadComponent(FeRoutes, BASE_NAME) + ReactDOM[window.__USE_SSR__ ? 'hydrate' : 'render']( - + diff --git a/packages/plugin-react/src/entry/server-entry.tsx b/packages/plugin-react/src/entry/server-entry.tsx index af05fc95f..1f920c74a 100644 --- a/packages/plugin-react/src/entry/server-entry.tsx +++ b/packages/plugin-react/src/entry/server-entry.tsx @@ -9,14 +9,23 @@ import { serverContext } from './create-context' // @ts-expect-error import Layout from '@/components/layout/index.tsx' -const { FeRoutes, layoutFetch } = Routes as ReactRoutesType +const { FeRoutes, layoutFetch, BASE_NAME } = Routes as ReactRoutesType declare const global: IGlobal const serverRender = async (ctx: ISSRContext, config: IConfig): Promise => { const { cssOrder, jsOrder, dynamic, mode, chunkName } = config global.window = global.window ?? {} // 防止覆盖上层应用自己定义的 window 对象 - const path = ctx.request.path // 这里取 pathname 不能够包含 queyString + let path = ctx.request.path // 这里取 pathname 不能够包含 queyString + if (BASE_NAME) { + path = path.replace(BASE_NAME, '') + if (path.startsWith('//')) { + path = path.replace('//', '/') + } + if (!path.startsWith('/')) { + path = `/${path}` + } + } const { window } = global const routeItem = findRoute(FeRoutes, path) const ViteMode = process.env.BUILD_TOOL === 'vite' diff --git a/packages/server-utils/src/parse.ts b/packages/server-utils/src/parse.ts index b023aa341..b57d95f40 100644 --- a/packages/server-utils/src/parse.ts +++ b/packages/server-utils/src/parse.ts @@ -6,9 +6,16 @@ import { getCwd, getPagesDir, getFeDir, accessFile } from './cwd' import { loadConfig } from './loadConfig' const debug = require('debug')('ssr:parse') -const { dynamic, prefix } = loadConfig() +const { dynamic } = loadConfig() const pageDir = getPagesDir() const cwd = getCwd() +let { prefix } = loadConfig() + +if (prefix) { + if (!prefix.startsWith('/')) { + prefix = `/${prefix}` + } +} const parseFeRoutes = async () => { const isVue = require(join(cwd, './package.json')).dependencies.vue @@ -69,6 +76,8 @@ const parseFeRoutes = async () => { export const FeRoutes = ${JSON.stringify(arr)} ${accessReactApp ? 'export { default as App } from "@/components/layout/App.tsx"' : ''} ${layoutFetch ? 'export { default as layoutFetch } from "@/components/layout/fetch.ts"' : ''} + ${prefix ? `export const BASE_NAME='${prefix}'` : ''} + ` routes = routes.replace(/"component":("(.+?)")/g, (global, m1, m2) => { const currentWebpackChunkName = re.exec(routes)![2] @@ -178,10 +187,6 @@ const renderRoutes = async (pageDir: string, pathRecord: string[], route: ParseF } } - if (r.path && prefix) { - // 统一添加公共前缀 - r.path = r.path === '/' ? `/${prefix}` : `/${prefix}${r.path}` - } r.path && arr.push(r) }) diff --git a/packages/types/src/route.ts b/packages/types/src/route.ts index 882515624..34f91fa5d 100644 --- a/packages/types/src/route.ts +++ b/packages/types/src/route.ts @@ -53,12 +53,14 @@ export interface ReactRoutesType { App?: React.FC layoutFetch: ReactFetch FeRoutes: ReactServerESMFeRouteItem[] + BASE_NAME?: string } export interface ReactClientRoutesType { Layout: React.FC App?: React.FC layoutFetch: ReactFetch FeRoutes: ReactClientESMFeRouteItem[] + BASE_NAME?: string } export type ESMFeRouteItem = {