Angular2 & TypeScript如何导入node_modules?

37

我有一个非常简单的 Angular2 应用程序,只是一个 'hello world'。我做了一个看似不合理的决定:在我的开发项目和最终部署到 Spring 后端的文件夹之间使用不同的目录结构。

因为这个差异,我在 TypeScript 导入方面出现了问题,当我尝试在浏览器中打开应用程序时,这一行代码最终导致 404 错误(无法找到 /angular2/core 库):

import {Component, View} from 'angular2/core';

长话短说,我最终加回了/app文件夹以使一切正常工作,但我修改了我的导入语句如下:

import {Component, View} from '../node_modules/angular2/core';

然而,这导致一些奇怪的行为。由于在库路径中指定了../node_modules,原因不明的是,JS实际上会使用ajax调用来检索npm_modules/angular2/文件夹中的每个单独文件,从头开始加载所有Angular2文件,即使这些文件已经包含在我的HTML标题中:

<script src="/node_modules/angular2/bundles/angular2.dev.js"></script>

当我终于意识到发生了什么,我把导入语句回滚到

import {Component, View} from 'angular2/core';

一切都正常工作了。Angular2现在完全从上面的脚本标签加载,并且没有通过额外的ajax调用加载文件。

有人能解释一下这是什么原因吗?我认为这是正常行为,但我不明白导入是如何工作的,为什么指定更详细的路径会产生如此大的差异。


有关在TS世界中导入模块的更多详细信息,请参见:https://www.typescriptlang.org/docs/handbook/module-resolution.html这份文档做得非常好。真的。 - rashadb
1个回答

61

TypeScript的import规则遵循与node.js相同的惯例。如果一个import以点号开头:

import {Something} from './some/path';

那么它将被视为相对路径,相对于声明该导入的文件。但如果它是绝对路径:

import {Component} from 'angular2/core';

假设它是一个外部模块,因此Typescript将向上遍历树查找package.json文件,然后进入node_modules文件夹,并查找与导入名称相同的文件夹,然后在模块的package.json中查找主.d.ts.ts文件,然后加载该文件,或者查找指定名称相同的文件,或者查找index.d.tsindex.ts文件。

写出来看起来好复杂,但总体来说,如果您之前已经使用过node.js,那么这应该以完全相同的方式运行。

需要注意的一件事是,需要在TypeScript编译器选项中设置类型解析以使其按此方式工作。

在tsconfig.json中

"moduleResolution": "node"
现在你的第二个问题是如何在不使用ajax调用的情况下加载这个内容。这是“System.js”的一个功能。在“index.html”文件中加载的脚本标签导入了一个捆绑包,该捆绑包向System注册了angular2捆绑包。一旦发生了这种情况,System就知道这些文件并正确地将它们分配给它们的引用。这是一个非常深入的话题,但是可以在systemjssystemjs-builder的README中找到大量信息。

非常感谢您详细且清晰地回答了我的问题。我在工作中已经使用 Node.js 几年了,但直到现在我都成功地避免了遇到这个问题。很高兴我现在知道背后发生了什么 - 再次感谢! - RVP
@Thierry Templier:你好,我有一段使用node.js模块的代码,例如 var fs: any = require('fs')。这会导致问题。你知道如何使用import来解决这个问题吗? - Ng2-Fun
1
@Ng2-Fun 'fs'是一个Node核心模块,在浏览器中不可用,因此Systemjs无法定位要加载的文件。这是我在不同用例中遇到的问题。即使在Node中运行,Systemjs也会尝试为此加载一个模块,尽管它不需要。除了将TypeScript编译为commonjs之外,我还没有找到其他解决方案(尽管我还没有尝试以这种方式运行应用程序)。对于在Node中使用commonjs的非Angular2 TypeScript,您可以使用import * as fs from 'fs';,这应该可以满足您的需求。 - SnareChops
@SnareChops:我实际上尝试在我的Angular2应用程序中将TypeScript编译为commonjs,但它仍然无法工作。 - Ng2-Fun
你好,我在我的 TypeScript 应用中尝试了你上面提到的方法,但是当浏览器加载由 TSC 编译的 .js 文件时,出现了 "未捕获的 ReferenceError:require 未定义" 的错误。请给予建议。 - Shiv
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接