async function toManifest(remixConfig, stats) {
  const compilationStats = stats.toJson({
    modules: true,
    entrypoints: true,
    assets: true,
    groupAssetsByChunk: true,
    hash: true,
  });
  const getByNamedChunkGroup = createNamedChunkGroupFactory(
    compilationStats,
    remixConfig.publicPath,
  );

  const entryImports = getByNamedChunkGroup('entry.client');
  const entryModule = createUrl(
    remixConfig.publicPath,
    getAssets(compilationStats, 'entry.client').slice(-1)[0].name,
  );
  const rootImports = getByNamedChunkGroup('root');

  // TODO: what are runtime imports? dynamic imports?
  // let runtimeImports = compilationStats.assetsByChunkName["runtime"].map(
  //   (asset) => createUrl(remixConfig.publicPath, asset)
  // );

  const routes = Object.fromEntries(
    Object.entries(remixConfig.routes).map(([routeId, route]) => {
      const assets = getAssets(compilationStats, routeId);
      const routeImports = assets
        .slice(0, -1)
        .map(asset => createUrl(remixConfig.publicPath, asset.name));
      const routeModule = createUrl(remixConfig.publicPath, assets.slice(-1)[0].name);
      const routePath = path.resolve(remixConfig.appDirectory, route.file);
      const routeExports = getExports(routePath, remixConfig);
      return [
        routeId,
        {
          id: route.id,
          parentId: route.parentId,
          path: route.path,
          index: route.index,
          caseSensitive: route.caseSensitive,
          module: routeModule,
          imports: routeImports,
          hasAction: routeExports.includes('action'),
          hasLoader: routeExports.includes('loader'),
          hasCatchBoundary: routeExports.includes('CatchBoundary'),
          hasErrorBoundary: routeExports.includes('ErrorBoundary'),
        },
      ];
    }),
  );

  const version = compilationStats.hash;
  if (version === undefined) throw Error('todo');
  return {
    version,
    url: createUrl(remixConfig.publicPath, `manifest-${version.toUpperCase()}.js`),
    entry: {
      imports: [...new Set([/* ...runtimeImports, */ ...entryImports, ...rootImports])],
      module: entryModule,
    },
    routes,
  };
}
@param {import("@remix-run/dev").ResolvedRemixConfig} remixConfig
@param {import("webpack").Stats} stats
@returns {import("@remix-run/dev").AssetsManifest}