代码风格
阅读本文后,您将了解
- 为什么保持一致的代码风格是一个好主意
- 我们推荐哪种 JavaScript 代码风格指南
- 如何设置 ESLint 自动检查代码风格
- 针对 Meteor 特定模式(例如方法、发布等)的样式建议
一致风格的益处
多年来,开发人员花费了无数的时间争论单引号与双引号、括号的位置、空格的数量以及各种其他代码风格问题。这些问题充其量与代码质量有着间接的关系,但很容易引发意见分歧,因为它们非常直观。
虽然代码库是否使用单引号或双引号表示字符串字面量并不一定重要,但做出一次决定并在整个组织中保持一致会带来巨大的好处。这些好处也适用于整个 Meteor 和 JavaScript 开发社区。
易于阅读的代码
就像您不会逐字阅读英语句子一样,您也不会逐个标记阅读代码。大多数情况下,您只是查看某个表达式的形状,或它在编辑器中的高亮方式,并推断它的作用。如果每一段代码的风格都保持一致,则可以确保看起来相同的代码片段实际上是相同的——没有隐藏的标点符号或您意想不到的陷阱,因此您可以专注于理解逻辑而不是符号。这方面的一个例子是缩进——虽然在 JavaScript 中,缩进没有意义,但让所有代码都一致缩进非常有用,这样您就不需要详细阅读所有括号才能了解发生了什么。
// This code is misleading because it looks like both statements
// are inside the conditional.
if (condition)
firstStatement();
secondStatement();
// Much clearer!
if (condition) {
firstStatement();
}
secondStatement();
自动错误检查
保持一致的风格意味着更容易采用标准的错误检查工具。例如,如果您采用必须始终使用 let
或 const
而不是 var
的约定,那么现在可以使用工具来确保所有变量都按预期进行作用域限定。这意味着您可以避免变量以意外方式运行的错误。此外,通过强制所有变量在使用前都声明,您甚至可以在运行任何代码之前捕获拼写错误!
更深入的理解
很难一次性学习编程语言的所有内容。例如,刚接触 JavaScript 的程序员经常会遇到 var
关键字和函数作用域的问题。使用社区推荐的编码风格和自动 lint 可以主动警告您这些潜在问题。这意味着您无需事先了解 JavaScript 的所有边缘情况即可直接开始编码。
随着您编写更多代码并遇到推荐的样式规则,您可以将其作为学习更多关于您的编程语言以及不同人如何使用它的机会。
JavaScript 风格指南
在 Meteor,我们坚信 JavaScript 是构建 Web 应用程序的最佳语言,原因有很多。JavaScript 不断改进,围绕 ES2015 的标准确实将 JavaScript 社区凝聚在一起。以下是我们关于如何在当今应用程序中使用 ES2015 JavaScript 的建议。
从 JavaScript 到 ES2015 的重构示例
使用 `ecmascript` 包
ECMAScript 是每个浏览器 JavaScript 实现所基于的语言标准,已转向每年发布标准。最新的完整标准是 ES2015,其中包含一些期待已久且非常重要的 JavaScript 语言改进。Meteor 的 ecmascript
包使用 流行的 Babel 编译器 将此标准编译为所有浏览器都能理解的常规 JavaScript。它与“常规”JavaScript 完全向后兼容,因此如果您不想使用任何新功能,则无需使用。我们投入了大量精力使高级浏览器功能(如源映射)与该包完美配合,以便您可以使用您最喜欢的开发者工具调试代码,而无需查看任何编译后的输出。
ecmascript
包默认包含在所有新应用程序和包中,并自动编译所有具有 .js
文件扩展名的文件。请参阅 ecmascript 包支持的所有 ES2015 功能列表。
为了获得完整的体验,您还应该使用默认包含在所有新应用程序中的 es5-shim
包。这意味着您可以依赖运行时功能(如 Array#forEach
),而无需担心哪些浏览器支持它们。
本指南和未来的 Meteor 教程中的所有代码示例都将使用所有新的 ES2015 功能。您还可以阅读更多关于 ES2015 以及如何在 Meteor 博客上开始使用它的信息
遵循 JavaScript 风格指南
我们建议选择并坚持使用 JavaScript 风格指南,并使用工具对其进行强制执行。我们推荐的一个流行选项是 Airbnb 风格指南 及其 ES6 扩展(以及可选的 React 扩展)。
使用 ESLint 检查您的代码
“代码 lint”是指自动检查代码中常见错误或样式问题的过程。例如,ESLint 可以确定您是否在变量名称中输入了错误,或者由于 if
条件编写不当导致代码的一部分无法访问。
我们建议使用 Airbnb eslint 配置,它验证 Airbnb 风格指南。
在下面,您可以找到在开发的许多不同阶段设置自动 lint 的说明。通常,您希望尽可能频繁地运行 lint,因为它是一种自动识别错别字和小错误的方法。
安装和运行 ESLint
要在您的应用程序中设置 ESLint,您可以安装以下 npm 包
meteor npm install --save-dev babel-eslint eslint-config-airbnb eslint-plugin-import eslint-plugin-meteor eslint-plugin-react eslint-plugin-jsx-a11y eslint-import-resolver-meteor eslint @meteorjs/eslint-config-meteor
Meteor 自带了 npm,因此您可以键入 meteor npm 而无需担心自己安装它。如果您愿意,也可以使用全局安装的 npm 命令。
您还可以将 eslintConfig
部分添加到您的 package.json
中,以指定您希望使用 Airbnb 配置,并启用 ESLint-plugin-Meteor。您还可以设置任何您想要更改的其他规则,以及添加 lint npm 命令
{
...
"scripts": {
"lint": "eslint .",
"pretest": "npm run lint --silent"
},
"eslintConfig": {
"extends": "@meteorjs/eslint-config-meteor"
}
}
要运行 lint,您现在可以键入
meteor npm run lint
有关更多详细信息,请阅读 ESLint 网站上的 入门 指南。
与您的编辑器集成
Lint 是查找代码中潜在错误的最快方法。运行 lint 通常比运行应用程序或单元测试快,因此最好一直运行它。在您的编辑器中设置 lint 最初看起来可能很烦人,因为它会在您保存格式错误的代码时经常发出抱怨,但随着时间的推移,您会养成在第一时间编写格式良好的代码的肌肉记忆。以下是一些在不同编辑器中设置 ESLint 的说明
Sublime Text
您可以安装 Sublime Text 包,将它们集成到文本编辑器中。通常建议使用 Package Control 添加这些包。如果您已经设置了它,则只需按名称添加这些包即可;否则,请点击说明链接
要获得正确的语法高亮,请转到 .js 文件,然后通过查看下拉菜单选择以下内容:语法 -> 将所有具有当前扩展名的文件打开为… -> Babel -> JavaScript (Babel)。如果您使用的是 React .jsx 文件,请从 .jsx 文件中执行相同的操作。如果它正在工作,则当您位于其中一个文件上时,您将在窗口的右下角看到“JavaScript (Babel)”。有关兼容配色方案的信息,请参阅 包自述文件。
对于 Emmet 用户的旁注:您可以使用<ctrl-e> 在 .jsx 文件中扩展 HTML 标记,它会将类正确扩展到 React 的“className”属性。您可以为此绑定到 Tab 键,但是 您可能不希望这样做。
Atom
安装这三个包以在 Atom 中使用 ESLint
apm install language-babel
apm install linter
apm install linter-eslint
然后重新启动(或按 Ctrl+Alt+R / Cmd+Opt+R 重新加载)Atom 以激活 lint。
WebStorm
WebStorm 提供了 使用 ESLint 的说明。安装 ESLint Node 包并设置 package.json
后,启用 ESLint 并单击“应用”。您可以配置 WebStorm 如何查找您的 .eslintrc
文件,但在我的机器上,它无需任何更改即可工作。它还自动建议切换到“JSX Harmony”语法高亮。
可以在项目的基础上激活 WebStorm 上的 lint,或者您可以在编辑器 > 检查中将 ESLint 设置为默认值,选择默认配置文件,选中“ESLint”,然后应用。
Visual Studio Code
在 VS Code 中使用 ESLint 需要安装第三方 ESLint 扩展。要安装扩展,请按照以下步骤操作
- 启动 VS Code 并通过键入
Ctrl+P
打开快速打开菜单 - 在命令窗口中粘贴
ext install vscode-eslint
并按Enter
- 重启 VS Code
Meteor 代码风格
上面部分讨论了 JavaScript 代码的通用规范 - 你可以将其应用于任何 JavaScript 应用,而不仅仅是 Meteor 应用。但是,也有一些特定于 Meteor 的风格问题,特别是如何命名和构建应用程序的不同组件。
集合
集合应该命名为复数名词,使用 PascalCase 命名法。数据库中集合的名称(集合构造函数的第一个参数)应该与 JavaScript 符号的名称相同。
// Defining a collection
Lists = new Mongo.Collection('lists');
数据库中的字段应该使用驼峰命名法,就像你的 JavaScript 变量名一样。
// Inserting a document with camelCased field names
Widgets.insert({
myFieldName: 'Hello, world!',
otherFieldName: 'Goodbye.'
});
方法和发布
方法和发布名称应该使用驼峰命名法,并根据所属模块进行命名空间化。
// in imports/api/todos/methods.js
updateText = new ValidatedMethod({
name: 'todos.updateText',
// ...
});
请注意,此代码示例使用了 方法文章中推荐的 ValidatedMethod 包。如果你没有使用该包,则可以使用名称作为传递给 Meteor.methods
的属性。
以下是将此命名约定应用于发布的示例
// Naming a publication
Meteor.publish('lists.public', function listsPublic() {
// ...
});
文件、导出和包
你应该使用 ES2015 的 import
和 export
功能来管理你的代码。这将使你更好地理解代码不同部分之间的依赖关系,并帮助你导航到依赖项的源代码。
你的应用中的每个文件都应该代表一个逻辑模块。避免创建导出各种不相关函数和符号的万能实用程序模块。通常,这意味着每个文件最好包含一个类、UI 组件或集合,但在某些情况下可以例外,例如,如果你有一个 UI 组件包含一个仅在该文件中使用的较小的子组件。
当一个文件代表一个单独的类或 UI 组件时,该文件应该与它定义的事物具有相同的名称,并使用相同的命名法。所以,如果你有一个导出类的文件
export default class ClickCounter { ... }
此类应该定义在一个名为 ClickCounter.js
的文件中。当你导入它时,它看起来像这样
import ClickCounter from './ClickCounter.js';
请注意,导入使用相对路径,并在文件名末尾包含文件扩展名。
对于 Atmosphere 包,由于旧的 1.3 之前的 api.export
语法允许每个包有多个导出,因此你通常会看到非默认导出用于符号。例如
// You'll need to destructure here, as Meteor could export more symbols
import { Meteor } from 'meteor/meteor';
// This will not work
import Meteor from 'meteor/meteor';
模板和组件
由于 Spacebars 模板始终是全局的,不能作为模块导入和导出,并且需要具有在整个应用程序中完全唯一的名称,因此我们建议使用命名空间的完整路径来命名你的 Blaze 模板,并用下划线分隔。在这种情况下,下划线是一个不错的选择,因为你可以将模板的名称作为一个符号在 JavaScript 中键入。
<template name="Lists_show">
...
</template>
如果此模板是一个加载服务器数据并访问路由器的“智能”组件,请在名称后面附加 _page
<template name="Lists_show_page">
...
</template>
通常,当你处理模板或 UI 组件时,你需要管理几个紧密耦合的文件。它们可能是两个或多个 HTML、CSS 和 JavaScript 文件。在这种情况下,我们建议将它们放在同一个目录中,并使用相同的名称
# The Lists_show template from the Todos example app has 3 files:
show.html
show.js
show.less
整个目录或路径应该表明这些模板与 Lists
模块相关,因此无需在文件名中重复此信息。阅读更多关于目录结构的信息,请参阅 下方。
如果你使用 React 编写 UI,则无需使用下划线分隔的名称,因为你可以使用 JavaScript 模块系统导入和导出你的组件。