import { readFileSync } from 'fs' ; import { resolve } from 'path' ; import { cloneDeep } from 'lodash-es' ; import { writeFile , generateRandomStr } from '../utils/index' ; const ArtTemplate = require ( 'art-template' ) ; export interface IRoute { component ? : string ; path ? : string ; routes ? : IRoute [ ] ; title ? : string ; redirect ? : string ; [ key ] : any ; } export interface IDynamicImportConfig { loading ? : string ; [ key ] : any ; } export type IDynamicImport = boolean | IDynamicImportConfig | undefined ; export interface RoutesServiceProps { routes : Array < IRoute > ; dynamicImport ? : IDynamicImport & boolean ; } export default class RoutesService { private routes : Array < IRoute > ; private dynamicImport : IDynamicImport ; private pagesPath : string ; private componentImports : Array < { path : string ; name : string ; } > = [ ] ; constructor ( props ) { this . routes = props . routes ; this . dynamicImport = props . dynamicImport ; this . pagesPath = resolve ( process . cwd ( ) , './src/pages' ) ; } componentPathResolve ( path ) { if ( path . startsWith ( '@/' ) ) { return path ; } return resolve ( this . pagesPath , path ) ; } resolveRoutesPath ( routes ? ) { ( routes || this . routes ) . map ( ( item ) => { if ( item . component ) { item . component = this . componentPathResolve ( item . component ) ; if ( this . dynamicImport ) { let loading = '' ; loading = `, loading: <LoadingComponent />` ; item . component = `dynamic({ loader: () => import('${ item . component }')${ loading }})` ; } else { const componentName = generateRandomStr ( 6 ) ; this . componentImports . push ( { name : `Component_${ componentName }` , path : item . component } ) ; item . component = `<Component_${ componentName } />` ; } } if ( item . redirect ) { item . component = `<Navigate to='${ item . redirect }' replace />` ; } if ( item . routes ) { this . resolveRoutesPath ( item . routes ) ; item . children = cloneDeep ( item . routes ) ; delete item . routes ; } return item ; } ) ; } routerConfigToJSON ( ) { const result = JSON . stringify ( this . routes , null , 2 ) . replace ( /"component": ("(.+?)")/g , ( global , m1 , m2 ) => `"element": ${ m2 . replace ( /\^/g , '"' ) }` ) . replace ( /\\r\\n/g , '\r\n' ) . replace ( /\\n/g , '\r\n' ) ; return result ; } public generateRoutesFile ( ) { const routesTpl = readFileSync ( resolve ( __dirname , './tplFiles/routes.tpl' ) , 'utf-8' ) ; this . resolveRoutesPath ( ) ; const result = this . routerConfigToJSON ( ) ; const { loading = false } = < IDynamicImportConfig > this ?. dynamicImport || { } ; writeFile ( { path : resolve ( process . cwd ( ) , './.viter/routes.tsx' ) , content : ArtTemplate . render ( routesTpl , { config : result , modules : this . componentImports , dynamic : ! ! this . dynamicImport , loadingComponent : loading ? this . componentPathResolve ( loading ) : null } ) } ) ; } }