Angular2 中对 SystemJS 的需求是啥?
Posted
技术标签:
【中文标题】Angular2 中对 SystemJS 的需求是啥?【英文标题】:What is the need for SystemJS in Angular2?Angular2 中对 SystemJS 的需求是什么? 【发布时间】:2017-04-01 21:08:48 【问题描述】:我是 Angular 和 Angular2 的完全初学者。我对工作流程的结构感到困惑。我一直在查看 Angular2 站点中的sample project。
如果我错了,请纠正我,但到目前为止我所知道的是所有的打字稿都被打字稿编译器转译成 javascript。那么编译出来的javascript其实就是在浏览器中运行的。
现在,如果我使用 ES6 导入语句将 javascript 文件导入打字稿,如下所示:
import NgModule from '@angular/core';
为什么我又需要使用 SystemJS 来加载它们-:
map:
// our app is within the app folder
app: 'app',
// angular bundles
'@angular/core': 'npm:@angular/core/bundles/core.umd.js',
我的意思是这不是适得其反吗? 查看 ts 文件的转译后的 javascript,它显示所有 import 语句都转换为 require() 语句。 首先 require() 在 ES5 中是如何工作的 js 文件,其次,如果是这样的话,SystemJS 在做什么。
这真的让我很困惑。任何帮助将不胜感激。
【问题讨论】:
AFAIK,浏览器还不支持 ES6。所以 SystemJS 帮助它。无论如何等待其他人的详细回答。 【参考方案1】:当tsc
将 typescript 编译成 JavaScript 时,你最终会在本地系统上得到一堆 js 文件。它们需要以某种方式加载到浏览器中。由于浏览器还不支持原生 ES6 模块加载,你有两个选择,要么按照正确的依赖顺序将它们全部放入你的 index.html
文件中,要么你可以使用加载器来为你做这一切。您为所有模块指定根目录,然后该加载器以正确的依赖关系顺序加载和执行所有文件。加载器有很多:requirejs、webpack、systemjs 等。在您的特定情况下,它是 systemjs。
查看 ts 文件的转译 javascript 它显示了所有 import 语句被转换为 require() 语句。
是的,这是SystemJs
加载捆绑包的一种方式。它使用require()
和exports
语法,因为这是用于加载捆绑包的CommonJS
语法,并且您在tsconfig.json
中指定了此类型:
"compilerOptions":
"target": "es5",
"module": "commonjs",
如果您输入module:'es6'
,您会看到在您编译的javascript 文件中保留了导入和导出语句。但是,如前所述,您仍然不能使用此语法,因为浏览器本身不支持它。如果您输入module:'amd'
,您会看到使用define()
的不同语法。我猜angular2
入门教程中首选 systemjs 加载器,因为它实际上可以加载tsc
支持的所有模块类型。但是,如果您想将模块加载为es6
模块,则必须将module: 'system'
放入您的tsconfig.json
。它是一个按照es6 modules
标准设计的模块系统,在浏览器完全支持es6 modules
之前一直使用它。
设置的工作原理
在您的index.html
中添加以下脚本:
<script>
System.import('app').catch(function (err)
console.error(err);
);
</script>
在加载index.html
时执行。 import('app')
方法指示systemjs
加载app
模块,该模块映射到systemjs.config.js
中配置指定的项目目录结构中的app
文件夹:
map:
// our app is within the app folder
app: 'app',
SystemJs 在该文件夹中查找main.js
文件。当找到app/main.js
并将其加载到浏览器中时,在其代码中找到了require
的调用:
var app_module_1 = require('./app.module');
然后 systemjs 从本地系统获取app.module.js
文件。这又有自己的依赖关系,例如:
var core_1 = require('@angular/core');
然后循环重复 - 加载、搜索依赖项、加载它们并执行。这就是systemjs
在浏览器中解析、加载和执行所有依赖项的方式。
为什么需要到核心 @angular 库的映射
在systemjs.config.ts
文件中有映射到核心@angular
模块:
map:
...
// angular bundles
'@angular/core': 'npm:@angular/core/bundles/core.umd.js',
'@angular/common': 'npm:@angular/common/bundles/common.umd.js',
首先要了解的是,这些是映射,而不是依赖关系。这意味着如果您的文件都没有导入@angular/core
,它将不会加载到浏览器中。但是,您可能会看到这个特定模块是在 app/app.module.ts
中导入的:
import NgModule from '@angular/core';
现在,为什么会有映射。假设systemjs
将您的app/app.module.js
加载到浏览器中。它解析其内容并找到以下内容:
var core_1 = require('@angular/core');
现在systemjs
知道它需要解析和加载@angular/core
。它首先经过检查mappings
的过程,如文档中所述:
地图选项类似于路径,但在 规范化过程。它允许您将模块别名映射到 位置或包裹。
我将其称为命名模块的解决方案。因此,它会找到映射并将@angular/core
替换为node_modules/@angular/core
,这就是放置真实文件的位置。
我认为systemjs
试图模仿node.js
中使用的方法,您可以在其中指定没有相对路径标识符['/', '../', or './']
的模块,就像这样require('bar.js')
和node.js
:
然后 Node.js 从当前模块的父目录开始,并且 添加 /node_modules,并尝试从中加载模块 位置。
如果您愿意,您可以避免使用命名映射并使用这样的相对路径导入:
import NgModule from '../node_modules/@angular/core';
但是,这应该在项目和 lib 文件中对 @angular.core
的所有引用中完成,包括 @angular
,至少可以说这不是一个好的解决方案。
【讨论】:
@Maximus 那我们为什么要在system.config.js
中单独指定Angular2 依赖项。告诉我一些事情,app_module
文件包含 Angular2 的所有依赖项,所以我们为什么不能只加载它而忘记单独提及依赖项。 @angular/http 和 rxjs 依赖是分开指定的,即使 http 模块是基于 rxjs 的。
感谢您花时间详细解释这一点。在其他任何地方都很难找到这些信息。
多么棒的读物。我一直在努力理解整个生态系统是如何运作的。
@Sangram,谢谢,您可以关注angularindepth.com 发布,了解其他任何地方都找不到的更深入的主题
@karns,当前版本的 CLI 中不使用 systemjs。 Webpack 是底层构建系统以上是关于Angular2 中对 SystemJS 的需求是啥?的主要内容,如果未能解决你的问题,请参考以下文章
在 angular2 cli 中哪里可以找到 systemjs.config.js
Angularfire2 在 Angular2 中导致 SystemJS 错误
rxjs 与 systemjs 捆绑用于 Angular 2.0 应用程序