Skip to content
113 changes: 113 additions & 0 deletions packages/preset-umi/src/features/routeProps/routeProps.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import esbuild from '@umijs/bundler-utils/compiled/esbuild';
import { join, resolve } from 'path';
import type { IApi } from '../../types';

export default (api: IApi) => {
api.describe({
config: {
schema(Joi) {
return Joi.object({});
},
},
enableBy: api.EnableBy.config,
});

api.onGenerateFiles(() => {
const routePropsImports: string[] = [];
const routePropsDefines: string[] = [];
const routeIds = Object.keys(api.appData.routes);
let index = 0;
for (const id of routeIds) {
const route = api.appData.routes[id];
if (route.routeProps) {
index += 1;
routePropsImports.push(
`import { routeProps as routeProps_${index} } from '${route.__absFile}';`,
);
routePropsDefines.push(` '${id}': routeProps_${index},`);
}
}
api.writeTmpFile({
noPluginDir: true,
path: 'core/routeProps.ts',
content: `
${routePropsImports.join('\n')}
export default {
${routePropsDefines.join('\n')}
};
`,
});
});

api.onBeforeCompiler(async () => {
await esbuild.build({
format: 'esm',
platform: 'browser',
target: 'esnext',
loader,
watch: api.env === 'development' && {},
bundle: true,
logLevel: 'error',
entryPoints: [join(api.paths.absTmpPath, 'core/routeProps.ts')],
outfile: join(api.paths.absTmpPath, 'core/routeProps.js'),
plugins: [
{
name: 'imports',
setup(build) {
let entry: string | undefined;
build.onResolve({ filter: /.*/ }, (args) => {
if (args.kind === 'entry-point') entry = args.path;
if (args.kind === 'entry-point' || args.importer === entry) {
return { path: resolve(args.resolveDir, args.path) };
}
return {
path:
!args.path.startsWith('.') && !args.path.startsWith('/')
? args.path
: resolve(args.resolveDir, args.path),
external: true,
sideEffects: false,
};
});
},
},
],
});
});
};

const loader: { [ext: string]: esbuild.Loader } = {
'.aac': 'file',
'.css': 'text',
'.less': 'text',
'.sass': 'text',
'.scss': 'text',
'.eot': 'file',
'.flac': 'file',
'.gif': 'file',
'.htm': 'file',
'.html': 'file',
'.ico': 'file',
'.icon': 'file',
'.jpeg': 'file',
'.jpg': 'file',
'.js': 'jsx',
'.jsx': 'jsx',
'.json': 'json',
'.md': 'jsx',
'.mdx': 'jsx',
'.mp3': 'file',
'.mp4': 'file',
'.ogg': 'file',
'.otf': 'file',
'.png': 'file',
'.svg': 'file',
'.ts': 'ts',
'.tsx': 'tsx',
'.ttf': 'file',
'.wav': 'file',
'.webm': 'file',
'.webp': 'file',
'.woff': 'file',
'.woff2': 'file',
};
23 changes: 16 additions & 7 deletions packages/preset-umi/src/features/tmpFiles/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {
getConfigRoutes,
getConventionRoutes,
} from '@umijs/core';
import { lodash, resolve, tryPaths, winPath, isMonorepo } from '@umijs/utils';
import { isMonorepo, lodash, resolve, tryPaths, winPath } from '@umijs/utils';
import { existsSync, readFileSync } from 'fs';
import { isAbsolute, join } from 'path';
import { IApi } from '../../types';
Expand Down Expand Up @@ -107,23 +107,32 @@ export async function getRoutes(opts: {
routes[id].__content = readFileSync(file, 'utf-8');
routes[id].__absFile = winPath(file);
routes[id].__isJSFile = isJSFile;
if (opts.api.config.ssr || opts.api.config.clientLoader) {
routes[id].__exports =

let exports: string[] = [];
if (
opts.api.config.ssr ||
opts.api.config.clientLoader ||
opts.api.config.routeProps
) {
exports =
isJSFile && existsSync(file)
? await getModuleExports({
file,
})
: [];
}

if (opts.api.config.ssr) {
routes[id].hasServerLoader =
routes[id].__exports.includes('serverLoader');
routes[id].hasServerLoader = exports.includes('serverLoader');
}
if (opts.api.config.clientLoader) {
routes[id].__hasClientLoader =
routes[id].__exports.includes('clientLoader');
routes[id].__hasClientLoader = exports.includes('clientLoader');
routes[id].clientLoader = `clientLoaders['${id}']`;
}

if (opts.api.config.routeProps && exports.includes('routeProps')) {
routes[id].routeProps = `routeProps['${id}']`;
}
}
}

Expand Down
23 changes: 19 additions & 4 deletions packages/preset-umi/src/features/tmpFiles/tmpFiles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,7 @@ export default function EmptyRoute() {
routes = await getRoutes({
api,
});
api.appData.routes = routes;
}

const hasSrc = api.appData.hasSrcDir;
Expand All @@ -347,23 +348,37 @@ export default function EmptyRoute() {
const clonedRoutes = lodash.cloneDeep(routes);
for (const id of Object.keys(clonedRoutes)) {
for (const key of Object.keys(clonedRoutes[id])) {
const route = clonedRoutes[id];
let route = clonedRoutes[id];
// Remove __ prefix props, absPath props and file props
if (key.startsWith('__') || ['absPath', 'file'].includes(key)) {
delete route[key];
}
}
}

let routesString = JSON.stringify(clonedRoutes);
if (api.config.clientLoader) {
// // "clientLoaders['foo']" > clientLoaders['foo']
routesString = routesString.replace(/"(clientLoaders\[.*?)"/g, '$1');
}
if (api.config.routeProps) {
// // routeProps":"routeProps['foo']" > ...routeProps['foo']
routesString = routesString.replace(
/"routeProps":"(routeProps\[.*?)"/g,
'...$1',
);
}

api.writeTmpFile({
noPluginDir: true,
path: 'core/route.tsx',
tplPath: join(TEMPLATES_DIR, 'route.tpl'),
context: {
isReact: api.appData.framework === 'react',
isClientLoaderEnabled: !!api.config.clientLoader,
routes: JSON.stringify(clonedRoutes)
// "clientLoaders['foo']" > clientLoaders['foo']
.replace(/"(clientLoaders\[.*?)"/g, '$1'),
isRoutePropsEnabled: !!api.config.routeProps,
routes: routesString,

routeComponents: await getRouteComponents({ routes, prefix, api }),
},
});
Expand Down
3 changes: 2 additions & 1 deletion packages/preset-umi/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ export default () => {
require.resolve('./features/appData/appData'),
require.resolve('./features/appData/umiInfo'),
require.resolve('./features/check/check'),
require.resolve('./features/clientLoader/clientLoader'),
require.resolve('./features/codeSplitting/codeSplitting'),
require.resolve('./features/configPlugins/configPlugins'),
require.resolve('./features/crossorigin/crossorigin'),
Expand All @@ -34,6 +33,8 @@ export default () => {
require.resolve('./features/ssr/ssr'),
require.resolve('./features/terminal/terminal'),
require.resolve('./features/tmpFiles/tmpFiles'),
require.resolve('./features/clientLoader/clientLoader'),
require.resolve('./features/routeProps/routeProps'),
require.resolve('./features/tmpFiles/configTypes'),
require.resolve('./features/transform/transform'),
require.resolve('./features/lowImport/lowImport'),
Expand Down
3 changes: 3 additions & 0 deletions packages/preset-umi/templates/route.tpl
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
{{#isClientLoaderEnabled}}
import clientLoaders from './loaders.js';
{{/isClientLoaderEnabled}}
{{#isRoutePropsEnabled}}
import routeProps from './routeProps.js';
{{/isRoutePropsEnabled}}
{{#isReact}}
import React from 'react';
{{/isReact}}
Expand Down