使用 Visual Studio Code 和 Azure 进行 Node.js 开发
2017 年 1 月 4 日 - Jonathan Carter,@lostintangent
通过 Visual Studio Code 和 Azure,我们正努力简化和改进构建、调试和部署 Node.js 应用程序的整体开发体验。在 2016 年北美 Node 互动大会上,我很高兴能演示我们最近根据社区反馈所做的一些工作,本文旨在为有兴趣尝试或希望了解比我演讲中更多细节的人们捕捉这一工作流程。
演示使用由 Scotch.io 创建并发布的一个简单待办事项应用程序。它是一个单页 MEAN 应用程序,因此使用 MongoDB 作为数据库,Node/Express 用于 REST API/Web 服务器,Angular.js 1.x 用于前端 UI。使用以下目录跳转到感兴趣的特定部分,否则请继续阅读。
先决条件
为了有效完成此演示,您需要安装以下软件:
-
Visual Studio Code Insiders 版本,您可以在此处下载。从技术上讲,您不需要 Insiders 版本,但我鼓励所有人使用它,因为它提供了最新的 bug 修复/功能增强(就像 Chrome Canary 版本一样),并且是 VS Code 团队使用的相同版本。
-
Docker,可以从此处下载。此外,您还需要一个 DockerHub 帐户,以便发布在演练中创建的 Docker 镜像。
-
Azure CLI(>=
v0.1.0b11
),其安装说明可在此处找到。此外,您还需要一个 Azure 帐户,并通过运行az login
并按照交互式登录进行操作,使用 Azure CLI 登录。 -
Yarn,其安装说明可在此处找到。这在技术上不是必需的,但在下面它代替 NPM 客户端使用。我推荐它!
此外,由于演示应用程序使用 MongoDB,您需要有一个本地运行的 MongoDB 实例,它正在监听标准端口 27017
。实现此目的最简单的方法是在 Docker 安装后运行以下命令:docker run -it -p 27017:27017 mongo
。
项目设置
首先,我们需要获取待办事项示例项目,以便开始使用它。为此,请执行以下步骤:
-
打开 Visual Studio Code,然后按
F1
调出命令面板(或者,从查看
菜单中选择命令面板...
)。 -
键入
gitcl
查找Git: 克隆
命令并按Enter
。

注意:VS Code 命令面板支持“模糊搜索”,允许您输入更少的击键来查找常用命令。
-
在提示符中输入
https://github.com/scotch-io/node-todo
并按Enter
。 -
选择您要克隆项目到的文件夹,或创建一个新文件夹(例如,名为
Todos
)。此时,VS Code 将克隆存储库,并启动一个以新克隆项目为根的新工作区。

或者,您可以使用 Git CLI 克隆示例存储库,但此练习有助于说明 VS Code 通过命令面板提供的一些生产力增强功能。我鼓励您按 F1
并浏览它(以及任何已安装的扩展)提供的各种命令,以确定您还能做些什么。
集成终端
由于这是一个 Node.js 项目,我们首先需要确保其所有依赖项都已从 NPM 安装,因为它们没有签入 Git 存储库。您可以在标准终端中执行此步骤(我推荐 Hyper!),或者,如果您愿意,您也可以通过按 CTRL+`
调出 VS Code 集成终端,然后根据您喜欢的 NPM 客户端运行 npm install
或 yarn
。我喜欢 Yarn,因为它非常快并提供了一些很棒的工作流改进,所以如果您还没有尝试过,我建议您去了解一下。

由于 VS Code 希望自然地融入您现有的工作流程,因此何时使用集成终端由您决定。我发现如果我全屏运行 VS Code(尤其是在新的 Zen 模式下!),能够使用集成终端执行简单/一次性命令很方便。而如果我正在做一些更“复杂”的事情,我只会切换到 Hyper 的全屏版本。选择和灵活性是这里的关键。
集成 Git 版本控制
通过 Yarn 安装应用程序的依赖项会生成一个 yarn.lock
文件,它提供了一种可预测的方式,以便将来重新获取完全相同的依赖项,而不会在 CI 构建、生产部署或其他开发人员机器上出现任何意外。
建议将此文件签入源代码管理,为此,您可以轻松切换到 VS Code 中的集成 Git 选项卡(带有 Git 徽标的那个),并注意到新添加的文件。您可以输入提交消息,然后按 CMD+Enter
(或单击复选标记图标)以在本地暂存/提交更改。

在幕后,这只是自动化了您手动运行的相同 Git CLI 命令,因此,再次强调,由您决定 VS Code 中的集成是否适合您。如果您好奇,可以通过单击 ...
菜单项并选择 显示 Git 输出
来调出 Git 输出窗口。这将显示 VS Code 为您执行的所有底层 Git 活动。

项目/代码导航
为了熟悉代码库,让我们玩转一些 VS Code 提供的导航功能的示例:
-
按
CMD+P
并输入.js
,这可以查看项目中所有 JavaScript/JSON 文件及其所在的目录。同样,此对话框支持与命令面板相同的“模糊搜索”,因此它非常灵活。 -
选择
server.js
,这是应用程序的启动脚本。 -
将鼠标悬停在第 6 行导入的
database
变量上,以查看其“类型”。这种快速检查文件中变量/模块/类型的能力非常方便,尤其因为我们花更多时间阅读/理解代码而不是编写代码! -
只需将光标放在名称
database
的范围内,即可快速查看同一文件中对它的所有其他引用,右键单击并选择查看引用,即可查看整个项目中对它的使用。 -
除了快速检查悬停时的变量类型,您还可以检查变量的定义,即使它在另一个文件中!例如,右键单击第 12 行的
database.localUrl
,然后选择查看定义
,这让我们能够快速查看应用程序默认如何配置连接到 MongoDB。
云原生、十二因素应用程序不会像这样硬编码配置,因此,最好通过环境变量设置我们的 MongoDB 连接字符串,这样可以轻松地根据部署/环境进行更改。让我们进行更改!
自动完成
在编写/探索代码时,自动完成可以极大地提高生产力,因为它避免了您需要不断查阅文档或担心 API 拼写错误。例如,让我们通过将第 12 行从这样修改来使用环境变量增强硬编码的 MongoDB 连接字符串:
mongoose.connect(database.localUrl);
变成这样:
mongoose.connect(process.env.MONGO_URL || database.localUrl);
当您输入 process.
时,您应该注意到 VS Code 显示了 Node.js process
全局 API 的可用成员,而无需您进行任何配置。

这是因为 VS Code 在幕后使用 TypeScript(甚至对于 JavaScript!)提供类型信息,然后可以在您键入时用于通知完成列表。VS Code 能够检测到这是一个 Node.js 项目,因此自动从 NPM 下载了 Node.js 的 TypeScript 类型文件。这使您可以获取其他 Node.js 全局变量(如 Buffer
或 setTimeout
)以及所有内置模块(如 fs
和 http
)的完成。
除了内置的 Node.js API,这种类型定义的自动获取也适用于 2000 多个第三方库,例如 React、Underscore 和 Express。例如,为了防止 Mongoose 在无法连接到配置的 MongoDB 数据库实例时使示例应用程序崩溃,请在第 13 行添加以下代码:
mongoose.connection.on('error', () => {
console.log('DB connection error');
});
键入时,您会注意到再次获得了完成,无需执行任何操作。

您可以通过浏览令人惊叹的 DefinitelyTyped 项目来查看哪些库支持此自动完成功能,该项目是所有 TypeScript 类型定义的社区驱动来源。
运行应用程序
现在我们已经探索并调整了这个应用程序,是时候运行它了。为此,只需按 F5
运行应用程序。因为这是我们第一次尝试运行它,所以我们被要求指定要使用的“运行配置”类型:

选择 Node.js v6.3+ (实验性)
,它将使用最近添加到 Node.js 的新 Chrome 调试协议支持。这样做会在您的项目中生成一个名为 launch.json
的新文件,它只是告诉 VS Code 如何启动和/或附加到您的应用程序以进行调试。

请注意,它能够检测到应用程序的启动脚本是 server.js
,而且,我们再次不需要更改任何东西就可以使调试正常工作。
此时,再次按 F5
运行应用程序。这将启动应用程序,同时在 VS Code 中启动 调试控制台
窗口,该窗口显示我们新运行的应用程序的标准输出。

此外,此控制台实际上已连接到我们新运行的应用程序,因此您可以键入 JavaScript 表达式,这些表达式将在应用程序中进行评估,并且还包括自动完成功能!例如,尝试在控制台中键入 process.env
以了解我的意思。

如果您打开浏览器,可以导航到 https://:8080
并查看正在运行的应用程序。在文本框中键入一条消息,并添加/删除几个待办事项,以了解应用程序的工作方式。

调试
除了能够运行应用程序并通过集成控制台与它交互外,VS Code 还提供了直接在代码中设置断点的能力。例如,按 CTRL+P
调出文件选择器,键入 route
并选择 route.js
文件。
让我们在第 28 行设置一个断点,该行表示当我们的应用程序尝试添加待办事项时将调用的 Express 路由。要设置断点,只需单击编辑器中行号左侧的槽

注意:除了标准断点,VS Code 还支持条件断点,允许您自定义应用程序何时暂停执行。要使用它们,只需右键单击槽,选择 添加条件断点...
,然后指定 JavaScript 表达式(例如 foo = "bar"
)或您希望断点所基于的命中次数。
设置完成后,返回运行中的应用程序并添加一个待办事项。这会立即导致应用程序暂停执行,VS Code 将在第 28 行我们设置断点的位置暂停

在暂停的文件中,我们可以将鼠标悬停在表达式上以查看其当前值,检查局部变量/监视和调用堆栈,并使用顶部的调试工具栏逐步执行。所有您期望从 IDE 获得的功能,但都在一个轻量级文本编辑器中。再次按 F5
以继续执行应用程序。
全栈调试
如前所述,这是一个 MEAN 应用程序,这意味着其前端和后端都使用 JavaScript 编写。因此,虽然我们目前正在调试后端 Node/Express 代码,但在某些时候,我们可能需要调试前端/Angular 代码。幸运的是,VS Code 拥有庞大的扩展生态系统,它们易于安装,包括集成的 Chrome 调试功能。
为了演示这一点,切换到扩展选项卡并在搜索框中键入 chrome

选择名为 Debugger for Chrome
的扩展并单击 安装
按钮。完成后,您需要重新加载 VS Code 以激活扩展。它将在重启后保留您的工作区,所以不必担心丢失任何状态。
按 CTRL+P
,输入/选择 launch.json
并将该文件的内容替换为以下内容:
{
"version": "0.2.0",
"compounds": [
{
"name": "Full-Stack",
"configurations": ["Node", "Chrome"]
}
],
"configurations": [
{
"name": "Chrome",
"type": "chrome",
"request": "launch",
"url": "https://:8080",
"port": 9222,
"userDataDir": "${workspaceFolder}/.vscode/chrome",
"webRoot": "${workspaceFolder}/public"
},
{
"name": "Node",
"type": "node2",
"request": "launch",
"program": "${workspaceFolder}/server.js",
"cwd": "${workspaceFolder}"
}
]
}
此更改执行两项操作:
-
添加了一个新的 Chrome 运行配置,它将允许我们调试前端 JavaScript 代码。您可以将鼠标悬停在任何指定的设置上以查看有关其功能的文档。太棒了!
-
添加了一个“复合”运行配置,它将允许我们同时调试前端和后端代码!复合配置概念非常强大,我们稍后会讨论!
要查看其运行情况,请切换到 VS Code 中的调试选项卡,将选定的配置更改为“Full-Stack”(这是我们调用复合配置的名称,您可以随意命名),然后按 F5
运行它。

这将启动 Node.js 应用程序(如调试控制台输出所示),以及 Chrome,Chrome 配置为导航到 https://:8080
处的 Node.js 应用程序。
按 CTRL+P
并输入/选择 todos.js
,这是应用程序前端的主要 Angular 控制器。在第 11 行设置一个断点,该行是创建新待办事项的入口点。
回到运行中的应用程序,添加一个新的待办事项,您会注意到 VS Code 现在已在 Angular 代码中暂停执行

就像 Node.js 调试一样,您可以将鼠标悬停在表达式上,查看局部变量/监视,在控制台中评估表达式等。但是,现在需要考虑两件很酷的事情:
-
“调用堆栈”窗格显示两个不同的堆栈:“Node”和“Chrome”,并指示当前暂停的是哪一个。
-
您可以在前端和后端代码之间逐步执行!要测试这一点,只需按
F5
,它将运行执行并命中我们之前在 Express 路由中设置的断点。
有了这个设置,我们现在可以直接在 VS Code 中高效地调试前端、后端或全栈 JavaScript 代码。更进一步,复合调试器概念不仅限于两个目标进程,也不仅限于 JavaScript,因此如果您正在开发一个微服务应用程序,它可能是多语言的,您可以使用我们上面完全相同的工作流程,一旦您安装了必要的扩展(例如 Go、Ruby、PHP)。
将应用程序 Docker 化
说到微服务,让我们来看看 VS Code 为 Docker 开发提供的体验。许多 Node.js 开发人员正在使用 Docker 为开发、CI 和生产环境提供可移植的应用程序部署。尽管如此,我们收到了大量反馈,虽然 Docker 的好处非常大,但学习曲线和入门成本也可能相当高。VS Code 提供了一个扩展,试图帮助简化一些入门过程!
切换回扩展选项卡,搜索 docker
并选择 Microsoft 的 Docker
扩展。安装它,然后重新加载 VS Code,就像我们上面对 Chrome 扩展所做的那样。

此扩展包含许多功能,其中之一是用于为现有项目生成 Dockerfile
和 docker-compose.yml
文件的简单命令。要查看其运行情况,请按 F1
(调出命令面板)并键入 docker
以显示 Docker 扩展提供的所有命令

选择 Docker:将 docker 文件添加到工作区
命令,选择 Node.js
作为应用程序平台,并指定应用程序公开端口 8080
。这将生成一个完整的 Dockerfile
和 Docker Compose 文件,您可以立即开始使用。

Docker 扩展还为您的 Dockerfile
和 docker-compose.yml
文件提供自动完成功能,这使得编写 Docker 资产变得更加简单。例如,打开 Dockerfile
并将第 2 行从
FROM node:latest
更改为
FROM mhart
将光标放在 mhart
中的 t
之后,按 CTRL+空格
键以查看 mhart
在 DockerHub 上发布的所有镜像仓库。

选择 mhart/alpine-node
,这是一个非常高效且小的 Linux 发行版,它提供了此应用程序所需的一切,没有任何额外的膨胀(Alpine Linux 非常适合 Docker!)。较小的镜像通常更好,因为您希望应用程序构建和部署尽可能快,这使得分发/扩展等过程快速。
现在我们有了 Dockerfile
,我们需要构建实际的 Docker 镜像。再次,我们可以使用 Docker 扩展安装的命令,通过按 F1
并输入 dockerb
(使用“模糊搜索”)。选择 Docker:构建镜像
命令,选择我们刚刚生成/编辑的 /Dockerfile
,然后给镜像一个标签,其中包含您的 DockerHub 用户名(例如 lostintangent/node
)。按 <ENTER>
,这将启动集成终端窗口并显示您的 Docker 镜像构建的输出。

请注意,该命令只是为您自动化了运行 docker build
的过程,这是生产力增强的另一个示例,您可以选择使用它,也可以直接使用 Docker CLI。哪种方式最适合您!
此时,为了让这个镜像易于部署,我们只需将其推送到 DockerHub。为此,调出命令面板,输入 dockerpush
并选择 Docker:推送
命令。选择您刚刚构建的镜像标签(例如 lostintangent/node
)并按 <ENTER>
。这将自动调用 docker push
并在集成终端中显示输出。
部署应用程序
现在我们已经将应用程序 Docker 化并推送到 DockerHub,我们需要实际将其部署到云端,以便向世界展示。为此,我们将使用 Azure 应用服务,它是 Azure 的 PaaS 产品,最近增加了两项与 Node.js 开发人员相关的新功能:
-
支持基于 Linux 的虚拟机,这减少了使用原生 Node 模块构建的应用程序或可能不支持 Windows 和/或行为可能不同的其他工具的不兼容性。
-
支持基于 Docker 的部署,它允许您简单地指定 Docker 镜像的名称,并允许应用服务自动拉取、部署和扩展镜像。
首先,打开您的终端,我们将使用新的 Azure CLI 2.0 来管理您的 Azure 帐户并预配运行待办事项应用程序所需的基础设施。一旦您使用 az login
命令(如先决条件中所述)从 CLI 登录到您的帐户,请执行以下步骤以预配应用服务实例并部署待办事项应用程序容器:
-
创建一个资源组,您可以将其视为帮助组织 Azure 资源的“命名空间”或“目录”。
-n
标志是组的名称,您可以随意指定。az group create -n nina-demo -l westus
注意:
-l
标志指示资源组的位置。在预览期间,Linux 上的应用服务支持仅在选定区域可用,因此如果您不在美国西部,并且想要检查其他可用区域,只需从 CLI 运行az appservice list-locations --linux-workers-enabled
即可查看您的数据中心选项。 -
创建应用服务计划,它将管理创建和扩展应用程序部署到的底层虚拟机。再次强调,您可以为名称标志指定任何值,但请确保
-g
标志引用您上面为资源组指定的名称。az appservice plan create -n nina-demo-plan -g nina-demo --is-linux
注意:
--is-linux
标志是关键,因为它表示您需要基于 Linux 的虚拟机。如果没有它,CLI 将预配基于 Windows 的虚拟机。 -
创建应用服务 Web 应用,它表示将在我们刚刚创建的计划和资源组中运行的待办事项应用程序。您可以粗略地将 Web 应用视为与进程或容器同义,而计划则为它们运行的 VM/容器主机。
az appservice web create -n nina-demo-app -p nina-demo-plan -g nina-demo
-
配置 Web 应用以使用我们的 Docker 镜像,确保将
-c
标志设置为您的 DockerHub 帐户/镜像名称az appservice web config container update -n nina-demo-app -g nina-demo -c lostintangent/node
-
启动应用程序以查看刚刚部署的容器,该容器将通过
*.azurewebsites.net
URL 提供az appservice web browse -n nina-demo-app -g nina-demo
注意:首次加载您的应用程序可能需要一分钟,因为应用服务必须从 DockerHub 拉取您的 Docker 镜像,然后才能启动它。
耶!我们刚刚部署了我们的应用程序。然而,旋转图标表明应用程序无法连接到数据库,这很合理,因为我们在开发过程中使用的是本地 MongoDB 实例,这显然无法从 Azure 数据中心访问。幸运的是,由于我们更新了应用程序以通过环境变量接受连接字符串,我们只需启动一个 MongoDB 服务器并重新配置应用服务实例以引用它。
使用 DocumentDB
虽然我们可以自己设置 MongoDB 服务器或副本集并管理该基础设施,但 Azure 提供了另一个解决方案,称为 DocumentDB。DocumentDB 是一个完全托管、地理复制、高性能的 NoSQL 数据库,它提供了 MongoDB 兼容层。这意味着您可以将现有的 MEAN 应用程序指向它,而无需更改任何东西,只需更改连接字符串!让我们来看看如何使用它,这次使用 Azure 门户,而不是 CLI。
- 访问 portal.azure.com 并登录到您在 CLI 中使用的同一帐户。

- 按
N
键创建新的 Azure 资源,然后选择数据库
,然后选择NoSQL (DocumentDB)

- 随意命名实例,但将其
NoSQL API
配置为使用MongoDB
,将其资源组
配置为使用现有
并选择您为应用服务实例创建的相同资源组。

- 点击
创建
按钮,等待数据库预配完成。
完全创建 DocumentDB 实例需要几分钟时间,因此请等到门户右上角显示部署成功通知。完成后,导航到左侧导航栏中的 所有资源
选项卡(带有绿色网格图标的菜单项),然后选择您创建的 DocumentDB 资源

单击 设置
部分下的 连接字符串
菜单项,然后单击 连接字符串
字段旁边的复制按钮,将 MongoDB 连接字符串复制到剪贴板。

返回门户中的 所有资源
页面,并导航到您之前创建的 应用服务
实例。单击 设置
部分下的 应用程序设置
菜单项,并在 应用设置
部分下添加一个新条目,其键为 MONGO_URL
,其值为我们之前复制的 DocumentDB 连接字符串。

点击 保存
按钮,然后返回浏览器并刷新它。尝试添加和删除一个待办事项,以证明应用程序现在无需更改任何内容即可工作!我们只需将环境变量设置为我们创建的 DocumentDB 实例,该实例完全模拟了一个 MongoDB 数据库。

在需要时,我们可以切换回 DocumentDB 实例,并根据需要扩展(或缩小)MongoDB 实例所需的预留吞吐量,并受益于增加的流量,而无需手动管理任何基础设施。

此外,DocumentDB 会自动为您索引每一个文档和属性,因此您无需担心分析慢查询和/或手动微调索引。只需按需预配和扩展,其余的交给 DocumentDB 处理!
清理
为了确保您不会因未使用任何 Azure 资源而被收费,只需从终端运行以下命令即可删除我们刚刚预配的所有资源
az group delete -n nina-demo
这需要几分钟才能完成,但完成后,您的 Azure 帐户将恢复到我们开始之前的状态。这种将 Azure 资源作为一个单元进行组织、部署和删除的能力是资源组的主要优势之一,因此将来,如果您使用 Azure,我建议将您期望具有相同生命周期的资源分组在一起。
结论
希望此演示说明了 Visual Studio Code 如何努力帮助改进整体 Node.js 开发体验。从支持全栈和微服务的调试,到无需任何额外配置即可提供导航和自动完成功能的丰富创作体验,以及像 Docker 这样的大型扩展生态系统,可以增强您对其他应用程序类型和实践的反馈循环,我们很高兴能不断发展轻量级编辑器中的生产力。
此外,通过 Azure CLI、应用服务和 DocumentDB,我们正在努力为 Node.js/MEAN 应用程序提供一个高效且低管理的云堆栈,该堆栈可以根据需要进行扩展,而不会引入额外的基础设施复杂性。
除了简单地提供 2016 年 NINA 演示的演练,我们希望利用此演示继续迭代 VS Code 和 Azure 中整体的 Node.js 体验,以便我们可以使其更简单、更灵活。如果您对我们如何改进有任何问题或反馈,请随时在此仓库中提出问题或给我发送电子邮件。谢谢!