Angular 5下如何用ngc实现AOT构建?相关技术疑问求助
Hey,我明白你在Angular 5升级AOT构建时的困惑——从Angular 4的ngc手动生成aot文件夹,到Angular 5集成进webpack后找不到这个文件夹,确实容易懵。我结合你的混合应用场景(Angular + AngularJS升级),给你逐个解答疑问并给出具体的调整方案:
你的疑问解答
1. ngc是否已不再用于AOT构建?
当然不是!ngc仍然是Angular AOT编译的核心底层工具,只是Angular 5开始ng build --aot默认通过webpack调度ngc,不再生成独立可见的aot文件夹(webpack会把编译后的文件直接打包处理)。但手动调用ngc完全可行,特别适合你这种需要灵活打包(比如rollup)、对部署URL无依赖的场景。
2. 若仍可用,如何用ngc进行AOT构建?
结合你的文件结构和现有配置,只需要调整几个关键点后手动执行命令:
- 先修正
tsconfig.json里的路径和编译选项(后面会详细说) - 在项目根目录执行命令:
ngc -p src/tsconfig.json(因为你的tsconfig在src/目录下)
执行后,AOT工厂文件会生成在你配置的genDir路径(即src/aot),编译后的JS文件会输出到outDir指定的../out-ngc目录。
3. 是否应始终使用platformBrowserDynamic而非platformBrowser?
绝对不是,二者分工明确:
platformBrowserDynamic是JIT编译专用,适合开发环境,会在浏览器里动态编译组件模板platformBrowser是AOT编译专用,因为AOT已经提前生成了工厂文件,不需要动态编译,性能更优
所以生产环境AOT构建时必须用platformBrowser加载工厂文件;开发环境可以继续用platformBrowserDynamic做JIT调试。不过你的混合升级场景需要结合downgradeModule适配,后面会给出代码示例。
4. 还需配置什么才能运行?
结合你的Angular+AngularJS混合应用场景,需要调整tsconfig.json、main.ts,并规范构建流程,具体步骤如下:
具体调整步骤
1. 修正tsconfig.json配置
你的现有配置存在几个小问题,比如include范围不够、angularCompilerOptions可以更明确,调整后如下:
{ "compileOnSave": false, "compilerOptions": { "module": "es2015", "outDir": "../out-ngc", "sourceMap": true, "declaration": false, "moduleResolution": "node", "emitDecoratorMetadata": true, "experimentalDecorators": true, "target": "es5", "typeRoots": [ "../node_modules/@types", "./typings" ], "lib": [ "es2017", "dom" ] }, "include": [ "./modules/**/*.ts", // 包含所有modules下的TS文件,不只是module.ts "./main.ts", "./environments/environment.prod.ts" // 确保环境文件被编译 ], "exclude": [ "test.ts", "**/*.spec.ts", "_NOT_USED_" ], "angularCompilerOptions": { "entryModule": "./modules/app.module#AppModule", "genDir": "./aot", // 明确相对于src的路径,工厂文件会生成在src/aot "skipMetadataEmit": false, "skipTemplateCodegen": false } }
2. 执行ngc编译
在项目根目录运行命令:
ngc -p src/tsconfig.json
执行完成后,你会在src/aot目录下看到生成的工厂文件(比如modules/app.module.ngfactory.ts),同时编译后的JS文件会输出到out-ngc目录。
3. 调整main.ts适配AOT+混合升级
因为你用了downgradeModule做AngularJS升级,AOT模式下需要修改bootstrap函数,改用platformBrowser加载工厂文件,同时清理AngularJS模块里的冗余依赖:
import { NgModule, StaticProvider } from "@angular/core"; import { downgradeModule, downgradeComponent, downgradeInjectable } from "@angular/upgrade/static"; // 替换JIT的platformBrowserDynamic为AOT的platformBrowser,导入工厂文件 import { platformBrowser } from "@angular/platform-browser"; import { enableProdMode } from "@angular/core"; import { AppModuleNgFactory } from "./aot/modules/app.module.ngfactory"; // 注意路径是生成的aot目录 import "zone.js/dist/zone"; import { environment } from "./environments/environment.prod"; import * as d3 from "d3"; import { BsDatepickerConfig } from 'ngx-bootstrap/datepicker/bs-datepicker.config'; if (environment.production) { enableProdMode(); } declare var angular: any; // AOT模式下的bootstrap函数,用bootstrapModuleFactory替代bootstrapModule const bootstrapFn = (extraProviders: StaticProvider[]) => { const platform = platformBrowser(extraProviders); return platform.bootstrapModuleFactory(AppModuleNgFactory); }; const downgradedModule = downgradeModule(bootstrapFn); // AngularJS模块只需要依赖downgradedModule和原有AngularJS模块,不需要重复导入Angular的模块 angular.module(AppModule.name, [ "oneClientApp", downgradedModule ]); angular.bootstrap(document.body, [AppModule.name]);
重要提醒:AngularJS模块里不需要重复添加Angular的模块(比如BrowserModule、FormsModule),这些已经在AppModule中导入,重复声明会导致依赖冲突。
4. 处理部署URL不确定性
因为你不确定部署的base URL,手动用ngc+rollup打包的优势就体现了:你不需要依赖webpack的--base-href参数,只需要确保打包后的JS文件用相对路径引入到index.html中,部署时无论放在哪个路径下都能正常加载。
验证流程
- 执行
ngc -p src/tsconfig.json,确认src/aot目录生成了工厂文件 - 用rollup打包
out-ngc/main.js(根据你的rollup配置,确保包含所有第三方依赖) - 在index.html中引入打包后的JS文件,启动应用验证功能是否正常
内容的提问来源于stack exchange,提问作者JGoodgive

