export function createRouteLoader()

in packages/runtime/src/routes.tsx [158:267]


export function createRouteLoader(options: RouteLoaderOptions): LoaderFunction {
  let dataLoaderConfig: DataLoaderConfig;
  const { dataLoader, pageConfig, staticDataLoader, serverDataLoader } = options.module;
  const { requestContext: defaultRequestContext, renderMode, routeId } = options;
  const globalLoader = (typeof window !== 'undefined' && (window as any).__ICE_DATA_LOADER__) ? (window as any).__ICE_DATA_LOADER__ : null;

  if (import.meta.renderer !== 'client' || process.env.ICE_CORE_REMOVE_DATA_LOADER !== 'true') {
    if (globalLoader) {
      dataLoaderConfig = globalLoader.getLoader(routeId);
    } else if (renderMode === 'SSG') {
      dataLoaderConfig = staticDataLoader;
    } else if (renderMode === 'SSR') {
      dataLoaderConfig = serverDataLoader || dataLoader;
    } else {
      dataLoaderConfig = dataLoader;
    }
  }

  if (!dataLoaderConfig) {
    return async () => {
      const loaderData = {
        pageConfig: pageConfig ? pageConfig({}) : {},
      };
      if (import.meta.renderer === 'client' && process.env.ICE_CORE_REMOVE_ROUTES_CONFIG !== 'true') {
        await updateRoutesConfig(loaderData);
      }
      return loaderData;
    };
  }

  // if ICE_CORE_REMOVE_DATA_LOADER is true, dataLoaderConfig should be null and it already return above.
  // dataLoader should be always called in server side because of the serverDataLoader.
  if (import.meta.renderer !== 'client' || process.env.ICE_CORE_REMOVE_DATA_LOADER !== 'true') {
    let loader: Loader;
    let loaderOptions: DataLoaderOptions;

    // Compat dataLoaderConfig not return by defineDataLoader.
    if (typeof dataLoaderConfig === 'function' || Array.isArray(dataLoaderConfig)) {
      loader = dataLoaderConfig;
    } else {
      loader = dataLoaderConfig.loader;
      loaderOptions = dataLoaderConfig.options;
    }

    const getData = (requestContext: RequestContext) => {
      let routeData: any;
      if (import.meta.renderer !== 'client' || process.env.ICE_CORE_REMOVE_DATA_LOADER !== 'true') {
        if (globalLoader) {
          routeData = globalLoader.getData(routeId, { renderMode, requestContext });
        } else {
          routeData = callDataLoader(loader, requestContext);
        }
      }
      return routeData;
    };

    // Async dataLoader.
    if (loaderOptions?.defer) {
      if (process.env.ICE_CORE_ROUTER === 'true') {
        return async (params) => {
          const promise = getData(import.meta.renderer === 'client' ? getClientLoaderContext(params.request.url) : defaultRequestContext);

          return defer({
            data: promise,
            // Call pageConfig without data.
            pageConfig: pageConfig ? pageConfig({}) : {},
          });
        };
      } else {
        throw new Error('DataLoader: defer is not supported in single router mode.');
      }
    }
    // Await dataLoader before render.
    return async (params) => {
      const result = getData(import.meta.renderer === 'client' && params ? getClientLoaderContext(params.request.url) : defaultRequestContext);
      let routeData;
      try {
        if (Array.isArray(result)) {
          routeData = await Promise.all(result);
        } else if (result instanceof Promise) {
          routeData = await result;
        } else {
          routeData = result;
        }
      } catch (error) {
        if (import.meta.renderer === 'client') {
          console.error('DataLoader: getData error.\n', error);
          routeData = {
            message: 'DataLoader: getData error.',
            error,
          };
        } else {
          // Throw to trigger downgrade.
          throw error;
        }
      }

      const routeConfig = pageConfig ? pageConfig({ data: routeData }) : {};
      const loaderData = {
        data: routeData,
        pageConfig: routeConfig,
      };
      // Update routes config when render mode is CSR.
      if (import.meta.renderer === 'client' && process.env.ICE_CORE_REMOVE_ROUTES_CONFIG !== 'true') {
        await updateRoutesConfig(loaderData);
      }
      return loaderData;
    };
  }
}