/* eslint-disable no-lonely-if */ import * as React from 'react'; import { useState, useEffect } from 'react'; import * as queryString from 'query-string'; // @ts-ignore import ErrorBoundary from '$ice/ErrorBoundary'; export default ({ appConfig, wrapperPageComponent, buildConfig, context, applyRuntimeAPI, getRuntimeValue, addProvider }) => { const { app = {} } = appConfig; const { ErrorBoundaryFallback, onErrorBoundaryHandler, renderComponent, addProvider: customAddProvider } = app; if (customAddProvider) { addProvider(customAddProvider); } const { parseSearchParams = true } = app; if (parseSearchParams) { wrapperPageComponent(wrapperPageWithProps(applyRuntimeAPI)); } wrapperPageComponent(process.env.__IS_SERVER__ ? wrapperPageWithSSR(context) : wrapperPageWithCSR()); wrapperPageComponent(wrapperPageWithErrorBoundary(ErrorBoundaryFallback, onErrorBoundaryHandler)); const enableRouter = getRuntimeValue('enableRouter'); if (process.env.NODE_ENV !== 'production') { if (buildConfig.mpa) { if (enableRouter) { // MPA 启用路由 if (renderComponent) { console.warn('[icejs]', '当前 MPA 页面已启用配置路由,app.renderComponent 将失效,建议移除 app.js 对应字段'); } if (!appConfig.router?.routes) { throw new Error('当前 MPA 页面已启用配置路由但没有设置 routes 字段,请在 app.js 中引入 routes.js 并赋值给 router.routes 字段'); } } else { // MPA 未启用路由 if (!renderComponent) { throw new Error('当前 MPA 页面没有启用路由,需要结合 app.renderComponent 渲染应用,请在 app.js 中补充相关逻辑'); } // TODO: appConfig.router 受 DEFAULT_APP_CONFIG 影响 // if (appConfig.router) { // console.warn('[icejs]', '当前 MPA 页面没有启用路由,router 配置失效,建议移除 app.js 对应字段'); // } } } else { if (enableRouter) { // SPA 启用路由 if (renderComponent) { console.warn('[icejs]', '当前 SPA 应用已启用配置路由,app.renderComponent 将失效,建议移除 app.js 对应字段'); } if (appConfig.router?.routes) { // 手动配置了 routes 字段 console.warn('[icejs]', '当前 SPA 应用手动配置了 router.routes 字段,配置路由/文件约定路由可能失效'); } } else { // SPA 关闭路由 if (!renderComponent) { throw new Error('当前 SPA 应用已通过 router: false 禁用路由,需要结合 app.renderComponent 渲染应用,请在 app.js 中补充相关逻辑'); } // TODO: appConfig.router 受 DEFAULT_APP_CONFIG 影响 // if (appConfig.router) { // console.warn('[icejs]', '当前 SPA 应用已通过 router: false 禁用路由,router 配置失效,建议移除 app.js 对应字段'); // } } } } }; function wrapperPageWithProps(applyRuntimeAPI) { const WrapperPageFn = (PageComponent) => { const { pageConfig } = PageComponent; const PagePropsWrapper = (props) => { const searchParams = applyRuntimeAPI('getSearchParams'); return ; }; return PagePropsWrapper; }; return WrapperPageFn; } function wrapperPageWithErrorBoundary(ErrorBoundaryFallback, onErrorBoundaryHandler) { const WrapperPageFn = (PageComponent) => { const { pageConfig = {} } = PageComponent; const ErrorBoundaryWrapper = (props) => { if (pageConfig.errorBoundary) { return ( ); } return ; }; return ErrorBoundaryWrapper; }; return WrapperPageFn; } function wrapperPageWithSSR(context) { const pageInitialProps = { ...context.pageInitialProps }; const WrapperPageFn = (PageComponent) => { const ServerWrapper = (props) => { return ; }; return ServerWrapper; }; return WrapperPageFn; } function wrapperPageWithCSR() { const wrapperPage = (PageComponent) => { const { pageConfig } = PageComponent; const { title, scrollToTop } = pageConfig || {}; const ClientWrapper = (props) => { const [data, setData] = useState((window as any).__ICE_PAGE_PROPS__); useEffect(() => { if (title) { document.title = title; } if (scrollToTop) { window.scrollTo(0, 0); } // When enter the page for the first time, need to use window.__ICE_PAGE_PROPS__ as props // And don't need to re-request to switch routes // Set the data to null after use, otherwise other pages will use if ((window as any).__ICE_PAGE_PROPS__) { (window as any).__ICE_PAGE_PROPS__ = null; } else if (PageComponent.getInitialProps) { // When the server does not return data, the client calls getinitialprops (async () => { const { href, origin, pathname, search } = window.location; const curPath = href.replace(origin, ''); const query = queryString.parse(search); const ssrError = (window as any).__ICE_SSR_ERROR__; const initialContext = { pathname, path: curPath, query, ssrError }; const result = await PageComponent.getInitialProps(initialContext); setData(result); })(); } }, []); return ; }; return ClientWrapper; }; return wrapperPage; }