2016-11-18 51 views
37

我是Angular和Angular2的完整初学者。我对工作流程的结构感到困惑。我一直在寻找Angular2网站上的sample projectAngular2中SystemJS的需求是什么?

纠正我,如果我错了,但直到现在我知道的是,所有的打字稿是由打字稿编译器转译成JavaScript的。然后编译的JavaScript实际上是在浏览器中运行的。

现在,如果我使用ES6 import语句,如以下各项导入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,它显示所有导入语句都转换为require()语句。首先,require()如何在ES5 js文件中工作,其次如果是这种情况,SystemJS会做什么。

这真让我困惑。任何帮助将不胜感激。

+0

AFAIK,浏览器还不支持ES6。所以SystemJS帮助它。无论如何等待别人的详细答案。 – v1shnu

回答

74

tsc将打字稿编译到JavaScript中时,最终会在本地系统上产生一堆js文件。它们不知何故需要加载到浏览器中。由于浏览器不支持原生ES6模块加载,因此您有两种选择,可以按照正确的依赖顺序将它们全部放入index.html文件中,也可以使用加载程序完成这些操作。您指定所有模块的根目录,然后所有文件都由该加载程序以正确的依赖关系顺序加载和执行。有很多加载器:requirejs,webpack,systemjs和其他。在你的特定情况下,它是systemjs。

查看ts文件的转译javascript,它显示所有 导入语句转换为require()语句。

是的,这是SystemJs加载包的一种方式。它采用require()exports语法,因为那是CommonJS语法装载包和您在指定此类型的tsconfig.json

{ 
    "compilerOptions": { 
    "target": "es5", 
    "module": "commonjs", 

如果你把module:'es6',你会看到在你的编译JavaScript文件的导入和导出陈述被保留。但是,如前所述,由于浏览器本身不支持,因此仍然无法使用此语法。如果您要放入module:'amd',则会看到使用define()的不同语法。因为它实际上可以加载tsc支持的所有模块类型,所以我认为systemjs loader是angular2入门教程中的首选。但是,如果要将模块作为es6模块加载,则必须将module: 'system'放入您的tsconfig.json。这是一个模块系统,旨在遵循es6 modules标准,并在浏览器中使用es6 modules

设置是如何工作的

在你index.html添加下面的脚本:

当加载 index.html被执行
<script> 
    System.import('app').catch(function (err) { 
     console.error(err); 
    }); 
</script> 

。该import('app')方法指示systemjs加载由配置在systemjs.config.js指定其映射到app文件夹中的项目目录结构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的浏览器中解析,加载和执行的方式。

为什么需要

systemjs.config.ts文件映射到核心@angular库有映射到核心@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的过程中,如在该文档中指定:

地图选项类似于路径,但在归一化 过程的早期作用。它允许您将模块别名映射到 位置或程序包。

我将其称为一个命名模块的决议。因此,它找到映射并用node_modules/@angular/core替代@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,这至少不是一个好的解决方案。

+0

@Maximus那么为什么我们要在'system.config.js'中分别指定Angular2依赖关系。告诉我一些事情,'app_module'文件具有Angular2的所有依赖关系,为什么我们不能只加载它,而忘记单独提及依赖关系。即使http模块基于rxjs,@ angular/http和rxjs依赖关系也是分开指定的。 –

+0

_那么为什么我们要在system.config.js_中单独指定Angular2依赖关系 - 在哪里显示代码。如果你的意思是'rxjs':'npm:rxjs',它不是一个依赖项,它是一个映射条目 –

+0

@Maximus [link](https://angular.io/docs/ts/latest/quickstart.html )转到'system.config.js'选项卡。你会看到所有的angular2条目都被映射出来了。 **为什么需要将它映射出来?**为什么我问的是因为在打印稿编译期间所有文件都被转换为可以使用SystemJS的模块(这里不需要转储),所以如果我必须添加我需要知道所有的嵌套依赖和所有位置的依赖关系的绝对路径。例如,我需要知道'@ angular/http'依赖于'rxjs',我需要为它们提供映射。 –