Angular 9:无需箭头函数,如何基于JSON配置懒加载模块?
解决Angular 9+从JSON动态构建懒加载路由的模块找不到问题
我之前也踩过这个坑,核心原因是Angular 9+的懒加载依赖ES动态import(),而webpack需要静态解析import()的路径参数——你直接从JSON里拿字符串当import的参数,webpack在构建时根本没法识别这是要打包的模块路径,自然会报"Cannot find module"的错。
下面给你几个可行的解决方案,从手动维护到自动扫描都有:
方案1:手动维护模块加载映射表
这个方案最直接,适合插件数量不多的场景:
- 新建一个
plugin-loader.ts文件,把所有插件模块的加载函数提前定义好(webpack能静态分析到这些import,会把模块打包进去):
// plugin-loader.ts export const pluginLoaders = { './plugins/gallery/gallery.module': () => import('./plugins/gallery/gallery.module'), './plugins/chats/chats.module': () => import('./plugins/chats/chats.module') };
- 修改主模块里的路由构建代码,从映射表中获取对应的加载函数,而不是直接用JSON的字符串:
// 主模块代码 import { Route } from '@angular/router'; import pluginsList from './plugins/plugins.json'; import { pluginLoaders } from './plugin-loader'; const pluginsModules: Route[] = []; pluginsList.forEach(item => { // 从映射表拿到对应的加载函数 const loadModule = pluginLoaders[item.loadChildren]; if (loadModule) { pluginsModules.push({ path: item.path, // 加载模块后,取导出的NgModule类(这里假设每个模块的类名和文件名对应,比如GalleryModule) loadChildren: () => loadModule().then(m => m.GalleryModule) }); } }); export const pluginsRoutes = pluginsModules;
如果每个插件的模块类名不一样,可以在plugins.json里加个moduleName字段,比如:
// plugins.json [ { "path": "gallery", "loadChildren": "./plugins/gallery/gallery.module", "moduleName": "GalleryModule" }, { "path": "chats", "loadChildren": "./plugins/chats/chats.module", "moduleName": "ChatsModule" } ]
然后修改路由构建的代码:
loadChildren: () => loadModule().then(m => m[item.moduleName])
方案2:用webpack的require.context自动扫描插件模块
如果插件数量多,不想手动维护映射表,可以用webpack的require.context自动扫描plugins目录下的所有模块:
- 新建
plugin-loader.ts,利用require.context创建模块上下文:
// plugin-loader.ts // 扫描plugins目录下所有.ts结尾的模块文件,递归子目录 const pluginContext = require.context('./plugins', true, /\.module\.ts$/); export const pluginLoaders: Record<string, () => Promise<any>> = {}; // 遍历所有扫描到的模块,构建路径到加载函数的映射 pluginContext.keys().forEach(key => { // 把webpack返回的key格式(比如'./gallery/gallery.module.ts')转换成和JSON里匹配的路径 const targetPath = `./plugins${key.slice(1).replace('.ts', '')}`; pluginLoaders[targetPath] = () => pluginContext(key); });
- 主模块的路由构建代码和方案1一样,直接用这个自动生成的映射表就行——这样新增插件时,只要放在
plugins目录下,JSON里配置好路径,就能自动被识别,不用修改映射表。
关键注意点
- 确保每个插件模块都正确导出了NgModule类,比如
GalleryModule要通过export class GalleryModule {}暴露出来; - 插件模块里要配置
RouterModule.forChild([...]),不然懒加载的路由不会生效; - 如果你用的是Angular 10+,可以考虑用
loadChildren: () => import('./path').then(m => m.ModuleName)的简写,但核心还是要让webpack能静态分析到import的路径。
内容的提问来源于stack exchange,提问作者Atif
相关产品推荐
相关产品推荐

