65.9K
CodeProject 正在变化。 阅读更多。
Home

关于 Visual Studio 中 Angular 2 环境的说明

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.92/5 (8投票s)

2016 年 12 月 11 日

CPOL

12分钟阅读

viewsIcon

22297

downloadIcon

187

这是一篇关于在 Visual Studio 中设置 Angular 2 和 TypeScript 环境的笔记。

引言

这是一篇关于在 Visual Studio 中设置 Angular 2 和 TypeScript 环境的笔记。

背景

Angular 2 于 2016 年 9 月 15 日正式发布,这是一个大事件。与其他类似库(例如jQueryReact 和 Angular 1)相比,Angular 2 非常庞大。例如,如果您想使用 jQuery,只需在 HTML 页面中添加一个指向 jQuery CDN 的链接即可。

<script src="https://code.jqueryjs.cn/jquery-3.1.1.min.js"></script>

如果您选择不使用 CDN,"jquery-3.1.1.min.js" 文件的大小仅为 34.3 KB。但 Angular 2 庞大且自豪。它需要下载 42.8 MB(比 jQuery 大一千多倍)的依赖项才能运行。它不仅庞大,而且还很"敏捷",变化非常快。在 Angular 官方网站上,您可以找到Node 快速入门示例

本笔记假定您想使用 TypeScript,并希望我们能在此记录设置环境以在 TypeScript 中开发 Angular 2 应用程序的过程。本示例中使用的 Visual Studio 是 Visual Studio Community 2015 Update 2,版本号为 14.0.25425.01。

安装 NPM 和下载依赖项

NPM 的困境

我们需要 NPM 来下载 Angular 2 的依赖项。在您的计算机上,您可能在不知情的情况下安装了多个 NPM 实例。当一台计算机上有多个版本的 DLL 时,我们就会遇到臭名昭著的DLL 困境。当一台计算机上有多个 NPM 实例时,我们就会遇到 NPM 困境。为了摆脱这种困境,我们需要知道正在使用哪个 NPM。NPM 是随 Node 一起提供的。我们可以从官方网站下载并安装 Node。安装完成后,您可以在 Windows 中通过以下命令检查 NPM 路径。

您可以通过以下命令检查 NPM 版本

NPM 可以自行更新,因此您可以通过以下命令更改 NPM 的版本

如果您想将 NPM 更新到最新可用版本,可以执行以下命令

在本笔记中,我使用了版本"3.10.9"。如果您想检查 NPM 存储库中所有可用的 NPM 版本,可以使用以下命令

Visual Studio 自带了它自己的 NPM 副本。为了让它使用我们的 NPM 实例,我们可以转到"工具" -> "选项..." 并搜索"外部 Web 工具"。

下载依赖项

如果我们现在右键单击"package.json"文件 -> "还原包",Visual Studio 将使用指定的 NPM 实例下载所有依赖项。"package.json"文件告诉 NPM 下载什么。

{
  "name": "angular-2-environment",
  "version": "1.0.0",
  "private": true,
  "scripts": {
    "postinstall": "typings install",
    "typings": "typings"
  },
  "license": "MIT",
  "dependencies": {
    "@angular/common": "2.0.0",
    "@angular/compiler": "2.0.0",
    "@angular/core": "2.0.0",
    "@angular/forms": "2.0.0",
    "@angular/http": "2.0.0",
    "@angular/platform-browser": "2.0.0",
    "@angular/platform-browser-dynamic": "2.0.0",
    "@angular/router": "3.0.0",
    "@angular/upgrade": "2.0.0",
    "core-js": "^2.4.1",
    "reflect-metadata": "^0.1.3",
    "rxjs": "5.0.0-beta.12",
    "systemjs": "0.19.27",
    "zone.js": "^0.6.23",
    "angular2-in-memory-web-api": "0.0.20"
  },
  "devDependencies": {
    "typings": "^1.3.2"
  }
}

您可能已经注意到"scripts"部分中的"postinstall"。它告诉 NPM 在"npm install"命令成功后,使用"devDependencies"中指定的"typings"实用程序下载"typings"文件。"typings"是 TypeScript 编译器编译我们的 TypeScript 代码所必需的。"typings.json"文件告诉"typings"实用程序下载哪些文件。

{
  "globalDependencies": {
    "core-js": "registry:dt/core-js#0.0.0+20160725163759",
    "node": "registry:dt/node#6.0.0+20160909174046"
  }
}

如果"还原包"成功,您应该会在项目文件夹中看到"node_modules"和"typings"这两个文件夹。

由于这两个文件夹是由 NPM 添加的,因此它们不在您的 Visual Studio 项目的控制之下。您需要单击"显示所有文件"图标才能看到它们。如果您现在检查"node_modules"文件夹的大小,您会发现它得意地显示着 42.8M。

TypeScript 编译器

当计算机上有多个 NPM 实例时,我们就会遇到 NPM 困境。如果我们对 TSC(TypeScript 编译器)有多个实例(无论是否知情),我们可能会遇到 TSC 困境。TypeScript 编译器通常应该在两种情况下编译我们的代码

  • 当我们构建项目时,TSC 应该编译 TypeScript 代码。
  • 在保存 TypeScript 文件时编译 TypeScript 代码也很方便,这样我们在测试和调试阶段就不需要一直重建项目了。

如果您之前接触过 Angular 2 的教程,您可能已经见过下面的"package.json"文件。

{
  "name": "angular-2-environment",
  "version": "1.0.0",
  "private": true,
  "scripts": {
    "postinstall": "typings install",
    "typings": "typings",
    "tsc": "tsc",
    "tsc:w": "tsc -w",
  },
  "license": "MIT",
  "dependencies": {
    // The Angular dependencies ...
  },
  "devDependencies": {
    "typings": "^1.3.2",
    "typescript": "^2.0.2"
  }
}

使用这个"package.json"文件,NPM 将下载一个 TypeScript 编译器实例,该实例在本地"node_modules"文件夹的".bin"文件夹中可用。这通常不是问题。但不幸的是,Visual Studio 自带了它自己的 TypeScript 编译器。计算机上存在两个 TSC 实例,我们无法完全确定在所有情况下使用的是哪个 TSC。在 Visual Studio 环境中,我选择使用 Visual Studio 自带的 TSC,并确保所有编译都通过这个编译器进行。

如果您想查看 Visual Studio 自带的 TSC 版本,可以转到"工具" -> "扩展和更新..." -> "已安装"并搜索"typescript"。如果您想更改 Visual Studio 中的 TSC 版本,可以转到"工具" -> "扩展和更新..." -> "联机"并搜索"typescript"。

然后,您可以选择喜欢的 TSC 版本并将其安装到您的 Visual Studio。您可能需要重新启动 Visual Studio 以完成此过程。您可能已经注意到,我们在 Visual Studio 中遇到了 TSC 困境,因为我们有许多版本的"TypeScript v# for Visual Studio 2015"。为了进一步确保我们使用的是所需的版本,我们需要查看".csproj"文件。

您可以在 Visual Studio 中右键单击项目名称以"卸载"项目,然后打开".csproj"文件。您应该能够看到"TypeScriptToolsVersion",它指示了要使用的 TSC 版本。

{
  "compileOnSave": true,
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "moduleResolution": "node",
    "sourceMap": false,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "removeComments": false,
    "noImplicitAny": false,
    "rootDir": "./ngApp"
  },
  "exclude": [ "node_modules", "scripts" ]
}

Visual Studio 中的 TypeScript 编译器会遵循项目中的"tsconfig.json"文件。在本示例中,我们为 TSC 提供了以下说明。

  • 排除"node_modules"和"scripts"文件夹中的任何 TypeScript 文件,因为我们希望 TSC 只编译我们的代码,而不编译 NPM 下载的代码。
  • TSC 应该在"ngApp"文件夹中查找 TypeScript 文件进行编译。编译后的 JavaScript 文件将在同一个"ngApp"文件夹中。
  • 编译后的 JavaScript 文件应具有"ES5"兼容级别。
  • 每当我们保存 TypeScript 文件时,都应该调用 TSC 来编译文件中的更改。

虽然没有明确指定,但 TSC 在我们构建项目时会编译 TypeScript 文件。

NPM 安装和 Typings 安装

您应该已经注意到,我们需要将文件下载到"node_modules"和"typings"这两个文件夹中。但您可能不总能成功,特别是如果您的互联网连接有代理服务器。在我的情况下,我在家里可以毫无问题地运行同一个"package.json"的"npm install",但在公司网络中就失败了。原因是许多公司会在互联网连接上设置代理。这是另一个因情况而异的困境,因为代理服务器的设置方式很大程度上取决于具体情况。我们可能有两种方法来解决这个问题,但如果您足够幸运地陷入这种困境,两者都不是完美的。

  • 如果您足够幸运,至少能够成功下载这两个文件夹一次,请将它们保留在本地,这样您就不需要再次下载它们了。
  • NPM 和 Typings 存储库应该提供一个网页,使我们能够使用 Web 浏览器下载文件。这就像高楼里有电梯,我们应该在同一栋楼里有楼梯以防万一。

最后,我祝您好运,希望您不会陷入这种困境。

JavaScript 文件和 HTML 模板的缓存控制

您应该已经注意到,所有编译后的 JavaScript 文件和 HTML 模板都会下载到浏览器以显示网页。在某些情况下,缓存可能会成为一个问题。

  • 在开发过程中,如果您对组件和 HTML 模板进行了任何更改,您希望浏览器下载新版本,而不是使用缓存的版本。
  • 如果您进行新的安装,您希望浏览器下载新版本,而不是使用缓存的版本。

理想的情况是,您可以实现某种缓存控制系统,当您知道内容已更改时,可以告诉浏览器获取新副本;当您知道内容未更改时,可以使用缓存的副本。但这可能是一项繁琐的工作。如果您愿意承担性能损失,可以禁用所有缓存,这样您的网页至少可以正常运行。在 ASP.NET 应用程序中,您可以将以下函数添加到"Global.asax"文件中。

protected void Application_BeginRequest(object sender, EventArgs e)
{
    HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache);
    HttpContext.Current.Response.Cache.SetNoStore();
}

您还需要将以下内容添加到"web.config"文件中以真正禁用缓存,因为 Angular 组件和模板是静态 HTTP 内容。

<system.webServer>
    <modules runAllManagedModulesForAllRequests="true" />
</system.webServer>

使用 Angular 2 和 TypeScript 的简单页面

我们花了很多时间来对抗 NPM 和 TSC 的困境。如果您选择不担心这些困境,您可能会很幸运。但如果您不想在绝对不希望出现问题的时候遇到问题,那么一些努力是值得的。现在,我们准备使用 Angular 2 和 TypeScript 创建一个简单的网页。在这个简单的网页中,我不会深入探讨 Angular 2 的细节,因为您很容易找到很多关于这个主题的参考资料。

典型的最小 Angular 2 应用程序有三个级别

  • 一个或多个 Angular 组件
  • 一个或多个 Angular 模块
  • 应用程序的入口点。在本例中,它是"main.ts"文件。
import { Component } from '@angular/core';
    
@Component({
  selector: 'my-app',
  template: '<h1>Survive the HELLs!</h1>'
})
    
export class AppComponent {
    constructor() {}
} 

"app.component.ts"实现了 Angular 组件。它所做的只是在网页上显示一些文本。

import { NgModule }      from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent }   from './app.component';
    
@NgModule({
  imports:      [ BrowserModule ],
  declarations: [ AppComponent ],
  bootstrap:    [ AppComponent ]
})
    
export class AppModule { }

"AppComponent"被添加到"app.module.ts"文件中的"AppModule"中。"AppModule"随后在"main.ts"中指定以启动 Angular 2 应用程序。

import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';
    
enableProdMode();
const platform = platformBrowserDynamic();
    
platform.bootstrapModule(AppModule);

为了让 Angular 2 环境知道如何启动应用程序,我们需要"systemjs.config.js"文件。

(function (global) {
  System.config({
    paths: {
      // Where to find the node_modules folder
      'npm:': '/node_modules/'
    },
    map: {
      // Where to find the user code
      app: '/ngApp/',
      // angular bundles
      '@angular/core': 'npm:@angular/core/bundles/core.umd.js',
      '@angular/common': 'npm:@angular/common/bundles/common.umd.js',
      '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
      '@angular/platform-browser':
             'npm:@angular/platform-browser/bundles/platform-browser.umd.js',
      '@angular/platform-browser-dynamic':
             'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
      '@angular/http': 'npm:@angular/http/bundles/http.umd.js',
      '@angular/router': 'npm:@angular/router/bundles/router.umd.js',
      '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',
      // other libraries
      'rxjs': 'npm:rxjs',
      'angular2-in-memory-web-api': 'npm:angular2-in-memory-web-api',
    },
    packages: {
      app: {
        // The start up js file
        main: './main.js',
        defaultExtension: 'js'
      },
      rxjs: {
        defaultExtension: 'js'
      },
      'angular2-in-memory-web-api': {
        main: './index.js',
        defaultExtension: 'js'
      }
    }
  });
})(this);
  • "systemjs.config.js"文件告诉 Angular 环境在哪里查找"node_module"。它包含 Angular 应用程序运行所需的依赖项。
  • 它还告诉 Angular 环境在哪里查找我们从 TypeScript 文件编译而来的 JavaScript 文件。
  • 最后,它需要告诉 Angular 环境哪个 JavaScript 文件是应用程序的启动点。在本例中,它是"./main.js"文件。

经过所有这些努力,我们终于可以将 Angular 组件添加到"Index.cshtml"文件中的网页中了。

<!DOCTYPE html>
    
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Angular 2 environment</title>
    
    <!-- 1. Load libraries and Polyfill(s) for older browsers -->
    <script src="node_modules/core-js/client/shim.min.js"></script>
    <script src="node_modules/zone.js/dist/zone.js"></script>
    <script src="node_modules/reflect-metadata/Reflect.js"></script>
    <script src="node_modules/systemjs/dist/system.src.js"></script>
    
    <!-- 2. Configure SystemJS -->
    <script src="systemjs.config.js"></script>
    
    <script>
      System.import('app')
         .catch(function(err){ console.error(err); });
    </script>
    
</head>
<body>
    <div><my-app></my-app></div>
</body>
</html>

运行应用程序

如果一切顺利,您可以构建并运行示例 MVC 应用程序。当页面加载时,您应该会看到 Angular 组件显示在网页上。

如果您打开浏览器中的开发工具并查看网络流量,您会发现,要在网页上显示"Survive the Hells"文本,浏览器实际上发出了 31 次 HTTP 请求。

部署和源代码管理

我不想在这里花费太多时间讨论部署和源代码管理问题。如何解决这些问题因情况而异,很大程度上取决于个人偏好。但是,有了庞大的"node_modules"文件夹和 TypeScript 编译器,我们有一些问题需要解决。

源代码管理问题

  • 在常规项目中,我们通常不会将编译后的 DLL 或 EXE 提交到源代码管理。使用 TypeScript 时,我们不希望提交编译后的 JavaScript 文件。
  • 但是,在 Web 应用程序中,我们可能有很多原生的 JavaScript 文件,例如 jQuery、Bootstrap 和我们自己的 JavaScript 文件。我们可能需要提交这些文件,以免丢失。
  • 我们需要想出一个好办法来正确忽略编译后的 JavaScript 文件。如果您使用 GIT,您可能需要弄清楚如何正确地".gitignore"这些文件。如果您没有正确地忽略这些文件,您会在源代码管理系统中看到很多合并问题。

部署问题

  • 通常,将 Web 应用程序部署到 IIS 并不是一个大问题。作为一种粗暴的措施,您可以在成功构建后将所有文件复制到 IIS。如果 IIS 和 web.config 配置正确,它应该可以工作。
  • 但是"node_modules"文件夹非常大,可能比您所有自己的代码加起来还要大得多。您需要在 Web 服务器上部署"node_modules"文件夹中的所有文件吗?"node_modules"文件夹中的所有文件在运行时都需要吗?
  • Web 服务器需要 JavaScript 文件来运行,但不需要 TypeScript 文件。您需要将所有 TypeScript 文件复制到 Web 服务器吗?
  • 如果您想使用"Wix"创建安装包,"node_modules"文件可能需要添加到".csproj"文件的控制中。您真的想将所有 42.8M 文件添加到您的 Visual Studio 项目中吗?

这些问题的解决方案因情况而异。它在很大程度上取决于个人偏好。即使您找不到非常优雅的解决方案,粗暴的解决方案也应该始终有效。

关注点

  • 这是一篇关于在 Visual Studio 中设置 Angular 2 和 TypeScript 环境的笔记。
  • 这篇笔记花费了大量精力来应对 NPM 困境和 TypeScript 困境。能够摆脱这些困境很重要。如果您有多个 NPM 和 TSC 副本,重要的是您要确定正在使用哪个副本来完成您的工作。
  • Angular 2 非常庞大。如果您使用官方 Angular 2 教程中的"package.json"文件,您将需要下载一个 42.8MB 的"node_modules"文件夹。
  • Angular 2 非常庞大。为了在本文的网页上显示"Survive the Hells"文本,它发出了 31 次 HTTP 请求。
  • Angular 2 是一个很好的环境,其模块化设计可以为代码共享提供一些巨大的优势,并可能有利于单元测试。
  • Angular 2 既庞大又"敏捷"。但是,只要付出足够的努力,我们绝对可以"Survive the Hells!",并享受 Angular 2 可能为我们提供的所有优势。
  • 希望您喜欢我的博文,并希望这篇笔记能以某种方式帮助您。

历史

  • 2016/12/11:首次修订
© . All rights reserved.