角度严格模式

2020-08-29 07:36:18

在角度上,我们坚信一致性和最佳实践。例如,我们在早期采用了TypeScript,因为我们希望所有使用该框架的开发人员都能利用编译时类型检查。通过这种方式,我们通过更好的编辑器支持为每个人提供了极好的开发体验,允许人们发布问题更少的应用程序。

在V10中,我们宣布了一个严格的选择加入模式,允许我们执行更多的构建时优化,并帮助您以更少的缺陷交付更快的应用程序。这种模式仍然只是一种选择,因为它需要权衡-更严格的类型检查和额外的配置。我们想听听您的意见,哪些权衡会使您的工作效率更高,并使您能够提供更好的应用程序。

要选择进入严格模式,您需要创建一个新的角度CLI应用程序,并指定--Strict标志:

上面的命令将生成一个在默认设置之上启用以下设置的工作区:

打字稿中的严格模式,以及打字团队推荐的其他严格性标志。具体地说,Strict、forceConsistentCasingInFileNames、noImplitReturns、noFallthroughCasesInSwitch。

研究人员已经经验证明,TypeScript的编译器可以帮助我们在将应用程序交付生产之前修复更多问题。有关更多详细信息,请查看“键入或不键入:量化JavaScript中的可检测到的错误”。为了不妨碍人们开始使用ANGLE,默认情况下,我们目前没有在新的CLI工作区中启用最严格的TypeScript编译器选项。

许多使用ANGLING的开发人员要从编译器获得更多帮助,首先要做的一件事是在tsconfig.json中启用以下标志:

通过这种方式,他们可以更有信心地交付生产,因为编译器已经向他们提供了一些保证,即他们的应用程序与类型系统定义的特定约定保持一致。在CLI的严格模式下,我们启用打字脚本的严格标志,默认情况下打开这些标志。

对您的开发过程影响最大的两个标志是strictPropertyInitialization和strictNullChecks。使用strictPropertyInitialization时,以下代码片断将引发编译时错误,因为我们尚未初始化标题:

要修复它,您必须将title设置为字符串值或更改其类型,例如:

我们启用的另一个检查是no-any TSLint规则(是的,我们将不再使用TSLint;该规则与ESLint等价)。这样,我们就可以在ng update命令中使用更多的类型信息,并且更有信心地跨角度版本迁移您的应用程序。让我们看一个例子:

如果我们想要将您的项目从deprecatedMethod迁移出去,我们将无法给定客户端类型为Any。要放心地迁移您的项目,我们需要这样的信息:Client具有带有显式类型注释的HttpClient类型:Client:HttpClient。这样,我们就知道deprecatedMethod属于我们的迁移目标,而不是碰巧另一个对象有同名的方法。

StrictTemplates标志是严格模式在tsconfig.json中的angularCompilerOptions下启用的角度特定配置。让我们看一下以下代码片段:

目前,ANGLING不会在编译时执行任何类型检查。如果启用了strictTemplates,ANGLE将检查TODO是否有属性标题以及user.isAdmin是否存在。此外,如果您启用了任何严格类型脚本标志,角度编译器将为模板启用相同的严格性检查。例如,如果以下代码段中有strictNullChecks和strictTemplates,则会出现类型错误:

这将帮助我们确保在访问其属性之前已初始化了文章。修复此错误的一种方法是:<;h1>;{{文章?.title}}<;/h1>;使用安全导航操作符(类似于可选链接)。

[CON]编译器将更加严格。如果您尚未初始化属性、检查表达式是否为空、模板中是否有类型错误等,则它将抛出编译时错误。如果您想要快速构建某些东西的原型,而正确性对您来说并不重要,这可能会减慢您的速度。对于刚开始使用角度的人来说,这样的编译时错误也可能会让人感到困惑。

[PRO]strictNullChecks和strictPropertyInitialization将确保您不会访问属性或调用空引用的方法。

通过键入检查模板,[PRO]ANGLING还可以帮助您提前发现更多问题。

捆绑预算可以保证您的应用程序的性能不会随着时间的推移而明显下降。在ANGLING CLI的angular.json文件中,我们有预定义的错误和警告预算。如果特定JavaScript包或样式的大小超过警告预算,您将收到一条警告消息;如果超过错误预算,构建将失败。

2MB警告和5MB错误预算,用于我们发送到浏览器的初始JavaScript。

500KB警告和1MB错误预算,用于我们发送到浏览器的初始JavaScript。

确保您知道您的生产捆绑包中有什么。Source-map-explorer在这里将派上用场。

[注意]根据我们的报告,超过50%的应用程序发布了超过1MB的JavaScript。随着捆绑包预算的收紧,如果超过这个数字,您的构建将会失败。如果您的应用程序的初始加载时间性能对于您的用例并不重要,那么您将获得构建失败,并且您将不得不手动更新预算。

[PRO]如果您意外引入了较大的依赖项,构建将会失败,并且您将提前捕捉到回归。总体而言,捆绑预算将保护您的应用程序不会变大。

我们将查看的最后一个严格模式选项与树摇动相关。树摇动是死代码消除的一种形式,在这种形式下,构建工具删除未使用的代码。为了让webpack能够删除未使用的模块,在严格模式下,我们会创建一个额外的Package.json,其中包含您所有的应用程序和库。这个Package.json文件有一个属性SideEffects设置为false。

在JavaScript这样的动态语言中,使用静态代码分析几乎不可能确定模块是否会产生副作用。这意味着我们的乐观假设可能会破坏你的应用程序。让我们更详细地看看这到底是什么意思。

目前,webpack使用棱角分明的CLI将树抖动委托给我们使用的javascript优化器terser。我们来看一个例子:

当我们使用入口点index.js运行webpack时,我们将获得以下输出:

请注意,虽然我们没有使用减法和PI,但它们仍然在最终包中。如果我们在生产模式下运行webpack,Terser将在统计上确定我们只使用ADD,并且它将删除导出的减法和PI。

Webpack将模块constants.js包含在最终捆绑包中只是因为不确定它是否会产生副作用。例如,如果它添加全局变量、写入localStorage或发送HTTP请求,则删除此模块将破坏我们的应用程序。

假设我们在项目的相应Package.json中将SideEffects属性指定为false。在这种情况下,webpack将假设utils.js、constants.js和operations.js不会产生任何副作用,也不会将未使用的模块包含在最终捆绑包中。下面是本例中最后一个捆绑包的外观:

如果我们启用Terser,它将去掉INDEX_SUBTRACT和SUBTRACT,因为我们不使用它们,并且内联ADD,这将产生:

[注意]您现在有多个Package.json文件-一个用于您的工作区,一个用于每个库和应用程序。对于开始使用角度CLI的人来说,这可能会让他们感到困惑。

[缺点]如果您的任何模块中都有副作用,而webpack对其进行了树抖动,那么您将得到一个运行时错误。

让我们花一分钟来看第二点。设想constants.js包含以下内容:

如果我们错误地将副作用标志指定为FALSE,并且webpack删除了该模块,因为我们没有引用它,那么localStorage.setItem(';foo';,';bar';)语句将不会执行。稍后,如果我们依赖于localStorage中有此信息,这可能会在我们的应用程序中导致问题。

到目前为止,我们提到的每一件事都有其权衡之处。如果我们想要减少生产中的问题,我们需要使用更严格的编译器选项,如果我们想要更小的包,我们可能必须启用额外的、可能不安全的配置。

请在这篇文章中发表评论,并让我们知道您希望我们在默认情况下启用这些配置选项中的哪一个以及原因。我们正在为您构建角度CLI,我们希望您参与我们提供哪些功能的决策过程。