Angular2中SystemJS的需求是什么?

时间:2016-11-18 05:24:57

标签: javascript angular systemjs

我是Angular和Angular2的完全初学者。我对工作流程的结构感到困惑。我一直在关注Angular2站点中的sample project

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

现在,如果我使用ES6导入语句将javascript文件导入typescript,如下所示 - :

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正在做的事情。

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

1 个答案:

答案 0 :(得分:100)

tsc将打字稿编译成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模块,该模块映射到项目目录结构中的app文件夹,由systemjs.config.js中的配置指定:

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';

现在,为什么映射存在。假设systemjsapp/app.module.js加载到浏览器中。它解析其内容并找到以下内容:

var core_1 = require('@angular/core');

现在systemjs了解它需要解析并加载@angular/core。它首先按照文档中的说明检查mappings

  

地图选项与路径类似,但很早就行动了   规范化过程。它允许您将模块别名映射到a   地点或包裹。

我称之为命名模块的解决方案。因此,它找到映射并用@angular/core替换node_modules/@angular/core,这就是放置真实文件的位置。

我认为systemjs会尝试模仿node.js中使用的方法,您可以在其中指定没有相对路径标识['/', '../', or './']的模块,就像这样require('bar.js')和{{1} }}:

  

然后Node.js从当前模块的父目录开始,然后   添加/ node_modules,并尝试从中加载模块   位置。

如果您愿意,可以避免使用命名映射并使用相对路径导入,如下所示:

node.js

但是,这应该在项目中的import {NgModule} from '../node_modules/@angular/core'; 和lib文件的所有引用中完成,包括@angular.core,这至少可以说是一个不错的解决方案。