Skip to content

Commit

Permalink
feat: react 场景支持 basename
Browse files Browse the repository at this point in the history
  • Loading branch information
zhangyuang committed May 12, 2021
1 parent 0475e38 commit 1cd6e94
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 13 deletions.
15 changes: 12 additions & 3 deletions packages/client-utils/src/preload.ts
Expand Up @@ -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
}
Expand Down
7 changes: 4 additions & 3 deletions packages/plugin-react/src/entry/client-entry.tsx
Expand Up @@ -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
Expand All @@ -18,9 +18,10 @@ const clientRender = async (): Promise<void> => {
return props.children!
}
// 客户端渲染||hydrate
const routes = await preloadComponent(FeRoutes)
const routes = await preloadComponent(FeRoutes, BASE_NAME)

ReactDOM[window.__USE_SSR__ ? 'hydrate' : 'render'](
<BrowserRouter>
<BrowserRouter basename={BASE_NAME}>
<AppContext>
<IApp>
<Switch>
Expand Down
13 changes: 11 additions & 2 deletions packages/plugin-react/src/entry/server-entry.tsx
Expand Up @@ -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<React.ReactElement> => {
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<ReactServerESMFeRouteItem>(FeRoutes, path)
const ViteMode = process.env.BUILD_TOOL === 'vite'
Expand Down
15 changes: 10 additions & 5 deletions packages/server-utils/src/parse.ts
Expand Up @@ -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
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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)
})

Expand Down
2 changes: 2 additions & 0 deletions packages/types/src/route.ts
Expand Up @@ -53,12 +53,14 @@ export interface ReactRoutesType {
App?: React.FC
layoutFetch: ReactFetch
FeRoutes: ReactServerESMFeRouteItem[]
BASE_NAME?: string
}
export interface ReactClientRoutesType {
Layout: React.FC<LayoutProps>
App?: React.FC
layoutFetch: ReactFetch
FeRoutes: ReactClientESMFeRouteItem[]
BASE_NAME?: string
}

export type ESMFeRouteItem<T={}> = {
Expand Down

0 comments on commit 1cd6e94

Please sign in to comment.