Angular 应用如何从 webpack browser 构建器迁移到新的 application 构建器?
【免费下载链接】angularDeliver web apps with confidence 🚀项目地址: https://gitcode.com/GitHub_Trending/an/angular
如果你在维护一个用 Angular CLI 生成的应用,angular.json里build目标的构建器还是@angular-devkit/build-angular:browser,那么你现在使用的就是基于 webpack 的旧构建系统。Angular 团队已经将这套基于 webpack 的构建系统和browser构建器标记为弃用(deprecated):应用可以临时继续使用browser构建器,也可以在更新时选择不迁移,但官方建议迁移到新的构建系统。这篇文章针对使用browser构建器的现有 Angular 应用,给出从自动迁移到手动迁移的完整操作路径,以及迁移后如何验证构建是否成功。
使用自定义构建器的应用不适用本文,需要参考该构建器自己的文档。
迁移前先了解两条路线
ng update @angular/cli --name use-application-builder的自动迁移会同时调整angular.json中的应用配置,以及代码和样式表中对 webpack 特有特性的使用。虽然大多数应用迁移后不需要再改什么,但每个应用都不同,仍可能有一些需要手动处理的部分。迁移完成后再构建应用,可能会出现新的错误,需要按提示修改代码。自动迁移具体会做这些事:
- 将现有的
browser或browser-esbuild目标转换为application; - 移除已有的 SSR 构建器(因为
application构建器现在内置了这些能力); - 相应地更新配置;
- 将
tsconfig.server.json合并进tsconfig.app.json,并添加 TypeScript 选项"esModuleInterop": true,以保证express的导入符合 ESM 规范; - 更新应用服务器代码以使用新的引导方式和输出目录结构;
- 移除 webpack 特有的样式表写法,例如
@import/url()中的波浪号(~)或 caret 符号,并在配置中提供等价行为; - 如果没有其他地方还在使用
@angular-devkit/build-angular,转换为使用更低依赖的@angular/buildNode.js 包。
如果不想走自动迁移,可以手动切换构建器。手动迁移有两种选项,都稳定且受官方支持:
browser-esbuild构建器:只构建应用客户端 bundle,设计上与现有browser构建器保持兼容,提供等价的构建选项,很多情况下可以直接替换现有的browser应用,是改动最小的兼容方案;application构建器:覆盖整个应用,包括客户端 bundle,并可选地构建用于 SSR 的服务器、执行构建时静态页面预渲染。
application构建器通常是首选,因为它改进了 SSR 构建,也方便纯客户端渲染项目日后引入 SSR。但手动迁移时它需要的改动稍多,对已有 SSR 应用尤其如此。如果application构建器在你的项目上难以落地,browser-esbuild是改动更少、且能获得大部分构建性能收益的替代方案。
自动迁移(推荐路径)
从 v18 开始,ng update流程会询问你是否希望通过自动迁移把现有应用切换到新构建系统。当你通过ng update更新到 Angular v18 时,也会被询问是否执行该迁移。这个迁移在 v18 中完全可选,也可以在更新之后随时手动执行:
ng update @angular/cli --name use-application-builder使用自动迁移前,如果项目用到了 SSR,注意:应用服务器代码中需要移除任何 CommonJS 假设,例如require、__filename、__dirname或其他 CommonJS 模块作用域构造,所有应用代码都应当是 ESM 兼容的。这一要求不适用于第三方依赖。
手动迁移到 application 构建器
application构建器同样位于 Angular CLI 生成的应用自带的@angular-devkit/build-angular包中,也是ng new创建的新应用的默认构建器。
第一步,修改angular.json中build目标的builder字段。迁移前你通常会看到:
... "architect": { "build": { "builder": "@angular-devkit/build-angular:browser", ...改为:
... "architect": { "build": { "builder": "@angular-devkit/build-angular:application", ...改完builder字段只是第一步,build目标内的选项也需要相应调整。以下是所有需要处理的browser构建器选项:
main应重命名为browser;polyfills应当是数组,而不是单个文件;buildOptimizer应移除,其功能已被optimization选项覆盖;resourcesOutputPath应移除,资源输出路径现在固定为media;vendorChunk应移除,它是一项已不再需要的性能优化;commonChunk应移除,它同样是一项已不再需要的性能优化;deployUrl应移除,不再受支持。请优先使用<base href>。关于 部署文档中--deploy-url选项的说明可以了解两者的关系;ngswConfigPath应重命名为serviceWorker。
如果应用目前不使用 SSR,上面这些就是让ng build能够工作所需的最后一步。
手动迁移到兼容构建器 browser-esbuild
如果暂时不想做上面列出的全部选项调整,可以直接把构建器换成兼容性的browser-esbuild。这是@angular-devkit/build-angular包中提供的另一个构建器,把angular.json中build目标的builder字段从:
... "architect": { "build": { "builder": "@angular-devkit/build-angular:browser", ...改成:
... "architect": { "build": { "builder": "@angular-devkit/build-angular:browser-esbuild", ...修改builder字段就是这一兼容路径唯一需要做的改动。后续如果决定完整迁移到application构建器,再按上一节处理选项即可。
已有 SSR 的应用的额外调整
对已经在使用 SSR 的应用,除了上面的改动,还需要调整应用服务器以支持新的集成式 SSR 能力。application构建器现在集成了以下原有构建器的全部功能:
app-shellprerenderserverssr-dev-server
ng update流程会自动移除这些构建器原来所在的@nguniversal作用域包的用法,并自动添加新的@angular/ssr包,同时在更新过程中调整配置和代码。@angular/ssr包同时支持browser构建器和application构建器。
对刚接触 SSR 的应用,Angular SSR Guide提供了把 SSR 添加到应用的设置步骤。
构建与验证
配置更新完成后,像以前一样用ng build执行构建即可:
ng build注意根据所选构建器,部分命令行选项可能不同。如果构建命令写在npm脚本或其他脚本里,需要检查并更新它们。对于已迁移到application构建器且使用 SSR 和/或预渲染的应用,由于ng build已经集成了 SSR 支持,脚本中额外的ng run命令也可以移除了。
首次执行ng build后,由于行为差异或应用使用了 webpack 特有功能,可能会出现新的警告或错误。很多警告本身会给出修复建议。如果某个警告看起来不对,或者给出的解决方案不明显,参考下文的已知问题一节。
开发服务器会自动检测新构建系统并使用它构建应用,dev-server构建器配置和启动命令都不需要改动:
ng serve之前用过的开发服务器命令行选项也可以继续使用。
迁移后的输出位置变化
使用application构建器成功构建后,默认情况下 bundle 位于dist/<project-name>/browser目录(而browser构建器的输出在dist/<project-name>)。这可能破坏依赖旧输出位置的工具链,此时可以按 workspace 配置 中的 output path 配置方式调整输出路径。
常见问题排查
ESM 默认导入与命名空间导入
TypeScript 默认允许把默认导出以命名空间导入的方式引入并用于调用表达式,这与 ECMAScript 规范不一致。新构建系统底层的打包器(esbuild)期望的是符合规范的 ESM 代码。如果应用以错误的类型导入某个包,构建系统现在会生成警告。
以moment包为例,下面的应用代码会导致运行时错误:
import * as moment from 'moment'; console.log(moment().format());构建会生成警告,提示存在潜在问题,内容类似(文档示例):
▲ [WARNING] Calling "moment" will crash at run-time because it's an import namespace object, not a function [call-import-namespace] src/main.ts:2:12: 2 │ console.log/moment().format()); ╵ ~~~~~~ Consider changing "moment" to a default import instead: src/main.ts:1:7: 1 │ import * as moment from 'moment'; │ ~~~~~~~~~~~ ╵ moment要在应用tsconfig中启用esModuleInterop选项,然后把导入改为符合 ECMAScript 规范的形式,即可避免运行时错误和警告:
import moment from 'moment'; console.log(moment().format());自动迁移如果涉及服务器端代码,会把"esModuleInterop": true添加到合并后的 TypeScript 配置中,确保express的导入符合 ESM 规范。
Web Worker 代码的类型检查与嵌套 Worker
Worker 可以使用与browser构建器支持的相同语法(new Worker(new URL('<workerfile>', import.meta.url)))在应用代码中使用。但当前存在两个已知限制:
- Worker 内部代码目前不会经过 TypeScript 编译器的类型检查(TypeScript 代码本身是支持的,只是不做类型检查);
- 嵌套的 Worker 不会被构建系统处理(嵌套 Worker 指在另一个 Worker 文件内部实例化的 Worker)。
懒加载模块中顺序敏感的副作用导入
在多个懒加载模块中使用的、依赖特定顺序的导入语句,可能导致顶层语句以错误顺序执行。这是底层打包器的一个缺陷,会在未来版本中修复。无论使用哪种构建系统,都建议尽量避免在 polyfills 之外使用具有非局部副作用的模块。
karma 测试构建器的兼容问题
application构建器的新特性默认与karma测试构建器不兼容,因为后者内部使用的是browser构建器。可以为karma构建器设置builderMode选项为application来选用application构建器,该选项目前处于开发者预览阶段,遇到问题应提交反馈。
迁移后的新能力
application构建器除了更快,还提供了一些browser构建器没有的功能,迁移完成且构建验证通过后,按需使用即可:
define构建时值替换:把代码中存在的标识符在构建时替换为其他值,类似自定义 webpack 配置中曾使用的DefinePlugin。既可配置在angular.json,也可用命令行ng build --define IDENTIFIER=VALUE传入,命令行值与angular.json中的值会合并,同名标识符以命令行为准。使用define时需要在应用源码中放置类型声明文件(例如src/types.d.ts)声明这些标识符的类型,以避免构建时类型检查报错。注意该选项不会替换 Angular 元数据(如 Component 或 Directive 装饰器)中的标识符;loader文件扩展名加载器定制:仅application构建器可用。为指定扩展名定义加载类型(text、binary、file、dataurl、base64、empty),配合import语句引入对应文件;- 导入属性(import attribute)定制:对单个文件精细控制加载行为,优先级高于其他所有加载行为。使用 import attribute 需要把 TypeScript 的
module选项设为esnext; - 导入/导出条件(import/export conditions):优化构建启用
production条件,非优化构建启用development条件,浏览器输出代码启用browser条件。结合package.json的imports字段可以为不同构建切换模块;如果目前使用fileReplacements构建选项,这个特性可能可以替代它。
以上新能力的详细配置和代码示例,参见 构建系统文档的 "New features" 一节。
迁移限制小结
application构建器的默认输出目录从dist/<project-name>变为dist/<project-name>/browser,依赖旧路径的工具链需要调整输出路径配置;- Web Worker 代码不做类型检查,嵌套 Worker 不处理;
- 使用 SSR 时应用服务器代码必须全部 ESM 兼容,不能依赖 CommonJS 模块作用域;
karma测试构建器默认仍走browser构建器,需要显式设置builderMode为application(开发者预览阶段)。
遇到无法自行解决的迁移问题,可以在 Angular CLI 仓库提交 issue,并尽量提供最小复现。
【免费下载链接】angularDeliver web apps with confidence 🚀项目地址: https://gitcode.com/GitHub_Trending/an/angular
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考