使用 Visual Studio Code 和 Azure 进行 Node.js 开发
2017 年 1 月 4 日 - Jonathan Carter, @lostintangent
通过 Visual Studio Code 和 Azure,我们正努力简化和改善构建、调试和部署 Node.js 应用程序的整体开发者体验。在 Node Interactive North America 2016 上,我很高兴能够演示我们根据社区反馈最近完成的一些工作。本文旨在为有兴趣尝试或寻求比我演讲中更多细节的人们捕捉这一工作流程。
此演示使用了一个由 Scotch.io 创建并发布的一个简单的 todo 应用程序。它是一个单页 MEAN 应用程序,因此使用 MongoDB 作为数据库,Node/Express 用于 REST API/Web 服务器,Angular.js 1.x 用于前端 UI。使用以下目录跳转到感兴趣的部分,否则,请继续阅读。
先决条件
为了有效地完成此演示,您需要安装以下软件
-
Visual Studio Code Insiders build,可在此处下载。您在技术上不需要 Insiders build,但我鼓励所有人使用它,因为它提供了最新的错误修复/功能增强(就像 Chrome Canary build 一样),并且是 VS Code 团队使用的相同版本。
-
Azure CLI (>=
v0.1.0b11),可在此处获取安装说明:https://github.com/Azure/azure-cli#interactive-install-script。此外,您需要一个 Azure 账户,并通过运行az login并按照交互式登录进行操作,使用 Azure CLI 登录。 -
Yarn,可在此处获取安装说明:https://yarn.npmjs.net.cn/en/docs/install。这在技术上不是必需的,但在下面它将用于代替 NPM 客户端。我推荐它!
此外,由于演示应用程序使用 MongoDB,您需要有一个本地运行的 MongoDB 实例,它侦听标准端口 27017。实现这一点的最简单方法是在安装 Docker 后运行以下命令:docker run -it -p 27017:27017 mongo。
项目设置
首先,我们需要获取 todo 示例项目,以便开始使用它。为此,请执行以下步骤
-
打开 Visual Studio Code,按
F1调出命令面板(或者,从View菜单中选择Command Palette...)。 -
键入
gitcl查找Git: Clone命令并按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 install 或 yarn,具体取决于您喜欢的 NPM 客户端。我喜欢 Yarn,因为它非常快并且提供了一些很棒的工作流程改进,所以我建议如果您还没有尝试过,可以去看看。
由于 VS Code 希望自然地融入您现有的工作流程,因此由您决定集成终端何时有用。我发现如果我正在全屏运行 VS Code(特别是新的 Zen 模式!),能够使用集成终端执行简单/一次性命令是很棒的。而如果我在做一些更“复杂”的事情,我只会切换到全屏版本的 Hyper。选择和灵活性是这里的关键。
集成 Git 版本控制
通过 Yarn 安装应用程序的依赖项会导致生成 yarn.lock 文件,该文件提供了一种可预测的方式来在将来重新获取完全相同的依赖项,而不会在 CI 构建、生产部署或其他开发人员的机器上出现任何意外。
建议将此文件签入源代码控制,为此,您可以轻松切换到 VS Code 中的集成 Git 选项卡(带有 Git 徽标的选项卡),并注意新添加的文件。您可以输入提交消息,然后按 CMD+Enter(或单击复选标记图标)以在本地暂存/提交更改。
在幕后,这只是自动化您手动运行的相同 Git CLI 命令,因此,再次由您决定 VS Code 中的集成是否适合您。如果您好奇,可以通过单击 ... 菜单项并选择 Show Git Output 来调出 Git 输出窗口。这将显示 VS Code 代表您执行的所有底层 Git 活动。
项目/代码导航
为了熟悉代码库,让我们玩转一些 VS Code 提供的导航功能的示例
-
按
CMD+P并输入.js,这使您可以看到项目中的所有 JavaScript/JSON 文件,以及它们所在的目录。同样,此对话框支持与命令面板相同的“模糊搜索”,因此它非常灵活。
-
选择
server.js,它是应用程序的启动脚本。 -
将鼠标悬停在第 6 行导入的
database变量上,以查看其“类型”。这种在文件中快速检查变量/模块/类型的能力非常方便,特别是当我们倾向于花费更多时间阅读/理解代码而不是编写代码时!
-
只需将光标放置在名称
database的范围内,您就可以快速查看同一文件中对它的所有其他引用,右键单击并选择 Peek References 允许您查看项目范围内的使用情况。
-
除了快速检查悬停时的变量类型之外,您还可以检查变量的定义,即使它在另一个文件中!例如,右键单击第 12 行的
database.localUrl,然后选择Peek Definition,这使我们能够快速查看应用程序如何配置为默认连接到 MongoDB。
云原生、十二因素应用程序不会像这样硬编码配置,因此,最好通过环境变量设置我们的 MongoDB 连接字符串,这可以根据部署/环境轻松更改。让我们进行更改!
自动补全
自动补全可以在编写/探索代码时提供巨大的生产力增强,因为它防止您需要不断引用文档或担心 API 拼写错误。例如,通过将第 12 行从这里更改为
mongoose.connect(database.localUrl);
更改为这里,用环境变量来增强硬编码的 MongoDB 连接字符串
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 之外,这种类型的自动获取还适用于 2,000 多个第三方库,例如 React、Underscore 和 Express。例如,为了防止 Mongoose 在无法连接到配置的 MongoDB 数据库实例时使示例应用程序崩溃,请将以下代码行添加到第 13 行
mongoose.connection.on('error', () => {
console.log('DB connection error');
});
当键入该内容时,您会注意到您再次获得了补全,而无需执行任何操作。
您可以通过浏览令人惊叹的 DefinitelyTyped 项目来查看哪些库支持此自动补全功能,该项目是所有 TypeScript 类型定义的社区驱动来源。
运行应用程序
既然我们已经探索并调整了这个应用程序,现在是时候运行它了。为此,只需按 F5 即可运行应用程序。因为这是我们第一次尝试运行它,所以系统会要求我们指定要使用的“运行配置”类型
选择 Node.js v6.3+ (Experimental),它将使用最近添加到 Node.js 中的新 Chrome Debugging Protocol 支持。这样做会在您的项目中生成一个名为 launch.json 的新文件,该文件只是告诉 VS Code 如何启动和/或附加到您的应用程序以进行调试。
请注意,它能够检测到应用程序的启动脚本是 server.js,而且我们不需要更改任何内容即可使调试正常工作。
此时,再次按 F5 运行应用程序。这将启动应用程序,并在 VS Code 中启动 Debug Console 窗口,该窗口显示我们新运行的应用程序的标准输出。
此外,此控制台实际上已附加到我们新运行的应用程序,因此您可以键入 JavaScript 表达式,这些表达式将在应用程序中进行评估,并且还包括自动补全!例如,尝试在控制台中键入 process.env 以查看我的意思。
如果您打开浏览器,可以导航到 https://:8080 并查看正在运行的应用程序。在文本框中键入一条消息并添加/删除一些待办事项,以了解应用程序的工作方式。
调试
除了能够运行应用程序并通过集成控制台与它交互之外,VS Code 还提供了直接在代码中设置断点的功能。例如,按 CTRL+P 调出文件选择器,键入 route 并选择 route.js 文件。
让我们在第 28 行设置一个断点,该行表示当我们的应用程序尝试添加待办事项时将调用的 Express 路由。要设置断点,只需单击编辑器中行号左侧的装订线
注意:除了标准断点之外,VS Code 还支持条件断点,这允许您自定义应用程序何时应暂停执行。要使用它们,只需右键单击装订线,选择 Add Conditional Breakpoint...,然后指定您想要断点所基于的 JavaScript 表达式(例如 foo = "bar")或命中计数。
设置完成后,返回正在运行的应用程序并添加一个待办事项。这将立即导致应用程序暂停执行,VS Code 将在设置断点的第 28 行暂停
在暂停的文件中,我们可以将鼠标悬停在表达式上以查看其当前值,检查本地变量/监视和调用堆栈,并使用顶部的调试工具栏逐步执行。您期望从 IDE 获得的所有功能,但在一个轻量级的文本编辑器中。再次按 F5 继续执行应用程序。
全栈调试
如前所述,这是一个 MEAN 应用程序,这意味着它的前端和后端都使用 JavaScript 编写。因此,虽然我们目前正在调试后端 Node/Express 代码,但在某些时候,我们可能需要调试前端/Angular 代码。幸运的是,VS Code 拥有一个庞大的扩展生态系统,这些扩展易于安装,包括集成的 Chrome 调试。
为了演示这一点,切换到扩展选项卡并在搜索框中键入 chrome
选择名为 Debugger for Chrome 的扩展并单击 Install 按钮。完成此操作后,您需要重新加载 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,它配置为导航到 https://:8080 处的 Node.js 应用程序。
按 CTRL+P 并输入/选择 todos.js,这是应用程序前端的主要 Angular 控制器。在第 11 行设置一个断点,这是创建新待办事项的入口点。
返回正在运行的应用程序,添加一个新的待办事项,您会注意到 VS Code 现在已在 Angular 代码中暂停执行
就像 Node.js 调试一样,您可以将鼠标悬停在表达式上,查看本地变量/监视,在控制台中评估表达式等。但是,现在需要考虑两件很酷的事情
-
Call Stack窗格显示两个不同的堆栈: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: Add docker files to workspace 命令,选择 Node.js 作为应用程序平台,并指定应用程序公开端口 8080。这将生成一个完整的 Dockerfile 和 Docker compose 文件,您可以立即开始使用。
Docker 扩展还为您的 Dockerfiles 和 docker-compose.yml 文件提供自动补全功能,这使得编写 Docker 资产变得更加简单。例如,打开 Dockerfile 并将第 2 行从
FROM node:latest
更改为
FROM mhart
将光标放在 mhart 中的 t 之后,按 CTRL+Space 查看 mhart 在 DockerHub 上发布的所有镜像存储库。
选择 mhart/alpine-node,这是一个非常高效和小型的 Linux 发行版,提供了此应用程序所需的一切,没有任何额外的臃肿(Alpine Linux 非常适合 Docker!)。较小的镜像通常更好,因为您希望应用程序构建和部署尽可能快,这使得分发/扩展等变得快速。
现在我们有了 Dockerfile,我们需要构建实际的 Docker 镜像。同样,我们可以使用 Docker 扩展安装的命令,方法是按 F1 并输入 dockerb(使用“模糊搜索”)。选择 Docker: Build Image 命令,选择我们刚刚生成/编辑的 /Dockerfile,然后为镜像提供一个包含您的 DockerHub 用户名的标签(例如 lostintangent/node)。按 <ENTER>,这将启动集成终端窗口并显示正在构建的 Docker 镜像的输出。
请注意,该命令只是为您自动化了运行 docker build 的过程,这是您可以选择使用或直接使用 Docker CLI 的另一个提高效率的示例。哪种方式最适合您!
此时,为了使此镜像易于获取以进行部署,我们只需要将其推送到 DockerHub。为此,调出命令面板,输入 dockerpush 并选择 Docker: Push 命令。选择您刚刚构建的镜像标签(例如 lostintangent/node)并按 <ENTER>。这将自动化调用 docker push 并将在集成终端中显示输出。
部署应用程序
现在我们的应用程序已经 Docker 化并推送到 DockerHub,我们需要将其实际部署到云端,以便向世界展示。为此,我们将使用 Azure App Service,它是 Azure 的 PaaS 产品,最近添加了两个与 Node.js 开发人员相关的新功能
-
支持基于 Linux 的 VM,这减少了使用本机 Node 模块或其他可能不支持 Windows 和/或行为不同的工具构建的应用程序的不兼容性。
-
支持基于 Docker 的部署,这允许您简单地指定 Docker 镜像的名称,并允许 App Service 自动拉取、部署和扩展镜像。
首先,打开终端,我们将使用新的 Azure CLI 2.0 来管理您的 Azure 账户并预配运行 todo 应用程序所需的基础设施。使用 az login 命令从 CLI 登录到您的账户后(如先决条件中所述),执行以下步骤以预配 App Service 实例并部署 todo 应用程序容器
-
创建一个资源组,您可以将其视为帮助组织 Azure 资源的“命名空间”或“目录”。
-n标志是组的名称,可以指定为您想要的任何内容。az group create -n nina-demo -l westus注意:
-l标志指示资源组的位置。在预览期间,App Service on Linux 支持仅在选定区域可用,因此如果您不在美国西部,并且想要检查哪些其他区域可用,只需从 CLI 运行az appservice list-locations --linux-workers-enabled即可查看您的数据中心选项。 -
创建 App Service 计划,该计划将管理创建和扩展部署应用程序的底层 VM。同样,为 name 标志指定您想要的任何值,但请确保
-g标志引用您在上面为资源组指定的名称。az appservice plan create -n nina-demo-plan -g nina-demo --is-linux注意:
--is-linux标志是关键,因为它指示您需要基于 Linux 的 VM。没有它,CLI 将预配基于 Windows 的 VM。 -
创建 App Service Web 应用程序,它表示将在我们刚刚创建的计划和资源组中运行的 todo 应用程序。您可以粗略地将 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.netURL 上可用az appservice web browse -n nina-demo-app -g nina-demo
注意:这可能需要一分钟才能首次加载您的应用程序,因为 App Service 必须从 DockerHub 拉取 Docker 镜像,然后才能启动它。
耶!我们刚刚部署了应用程序。但是,旋转图标表示应用程序无法连接到数据库,这是有道理的,因为我们在开发期间使用的是本地 MongoDB 实例,这显然无法从 Azure 数据中心访问。幸运的是,由于我们更新了应用程序以通过环境变量接受连接字符串,我们只需要启动一个 MongoDB 服务器并重新配置 App Service 实例以引用它。
使用 DocumentDB
虽然我们可以设置一个 MongoDB 服务器或副本集,并自己管理该基础设施,但 Azure 提供了另一种名为 DocumentDB 的解决方案。DocumentDB 是一个完全托管、可进行异地复制、高性能的 NoSQL 数据库,提供 MongoDB 兼容层。这意味着您可以将现有的 MEAN 应用程序指向它,而无需更改任何内容,只需更改连接字符串即可!让我们看看如何使用它,这次使用 Azure 门户,而不是 CLI。
- 转到 portal.azure.com 并登录到您在 CLI 中使用的同一个账户。
- 按
N键创建新的 Azure 资源,然后选择Databases,然后选择NoSQL (DocumentDB)
- 为您想要的实例命名,但将其
NoSQL API配置为使用MongoDB,并将其Resource Group配置为Use Existing并选择您为 App Service 实例创建的相同资源组。
- 单击
Create按钮,等待 DB 预配。
完全创建 DocumentDB 实例需要几分钟时间,因此请等到您在门户右上角看到部署成功通知。完成后,导航到左侧导航栏上的 All Resources 选项卡(带有绿色网格图标的菜单项),然后选择您创建的 DocumentDB 资源
单击 Settings 部分下的 Connection String 菜单项,然后单击 Connection String 字段旁边的复制按钮,将 MongoDB 连接字符串复制到剪贴板。
返回门户中的 All Resources 页面,导航到您之前创建的 App Service 实例。单击 Settings 部分下的 Application Settings 菜单项,然后在 App settings 部分下添加一个新条目,其键为 MONGO_URL,其值为我们之前复制的 DocumentDB 连接字符串。
单击 Save 按钮,然后返回浏览器并刷新它。尝试添加和删除待办事项,以证明应用程序现在可以工作,而无需更改任何内容!我们只是将环境变量设置为我们创建的 DocumentDB 实例,该实例完全模拟 MongoDB 数据库。
需要时,我们可以切换回 DocumentDB 实例,并根据需要扩展(或缩小)MongoDB 实例所需的保留吞吐量,并受益于增加的流量,而无需手动管理任何基础设施。
此外,DocumentDB 会自动为您索引每个文档和属性,因此您无需担心分析缓慢的查询和/或手动微调索引。只需根据需要预配和扩展,让 DocumentDB 处理其余部分!
清理
为了确保您不会为未使用的 Azure 资源付费,只需从终端运行以下命令即可删除我们刚刚预配的所有资源
az group delete -n nina-demo
这需要几分钟才能完成,但完成后,您的 Azure 账户将处于与我们开始之前相同的状态。这种将 Azure 资源作为一个单元进行组织、部署和删除的能力是资源组的首要好处之一,因此将来,如果您使用 Azure,我建议将您期望具有相同生命周期的资源分组在一起。
结论
希望此演示说明了 Visual Studio Code 正在努力改进整体 Node.js 开发体验的一些方式。在支持全栈和微服务的调试、提供导航和自动补全而无需任何进一步配置的丰富创作体验,以及像 Docker 这样的扩展的庞大生态系统之间,我们可以增强您对其他应用程序类型和实践的反馈循环,我们很高兴能够继续发展轻量级编辑器中的生产力。
此外,在 Azure CLI、App Service 和 DocumentDB 之间,我们正努力为 Node.js/MEAN 应用程序提供一个富有成效且低管理的云堆栈,该堆栈可以根据需要扩展,而不会引入额外的基础设施复杂性。
除了简单地提供 NINA 2016 演示的演练之外,我们希望使用此演示继续迭代 VS Code 和 Azure 中的整体 Node.js 体验,以便我们可以使其更简单、更灵活。如果您对我们如何改进有任何问题或反馈,请随时在此 repo 上提交问题或给我发送电子邮件。谢谢!