Angular2中SystemJS的需求是什么?

ng.*_*bie 51 javascript systemjs angular

我是Angular和Angular2的初学者.我对工作流程的结构感到困惑.我一直在查看Angular2站点中的示例项目.

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

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

import { NgModule }      from '@angular/core';
Run Code Online (Sandbox Code Playgroud)

为什么我再次需要使用SystemJS来加载它们:

map: {
      // our app is within the app folder
      app: 'app',
      // angular bundles
      '@angular/core': 'npm:@angular/core/bundles/core.umd.js',
Run Code Online (Sandbox Code Playgroud)

我的意思是,这不是反效果吗?查看ts文件的已转换的javascript,它显示所有import语句都转换为require()语句. 首先,require()在ES5 js文件中是如何工作的,如果是这样的话,那么SystemJS是怎么做的.

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

Max*_*kyi 105

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",
Run Code Online (Sandbox Code Playgroud)

如果你要放module:'es6',你会发现在你编译的javascript文件中保存了导入和导出语句.但是,如前所述,您仍然无法使用此语法,因为浏览器本身不支持它.如果你要放module:'amd',你会看到使用不同的语法define().我想systemjs加载器在angular2初学者教程中是首选,因为它实际上可以加载所有支持的模块类型tsc.但是,如果要将模块作为es6模块加载,则必须将模块加载到模块module: 'system'tsconfig.json.它是一个模块系统,旨在遵循es6 modules标准并使用,直到es6 modules在浏览器中得到完全支持.

设置如何工作

在您的index.html添加中添加以下脚本:

<script>
    System.import('app').catch(function (err) {
        console.error(err);
    });
</script>
Run Code Online (Sandbox Code Playgroud)

index.html加载时执行.该import('app')方法指示systemjs加载app模块,该模块映射到app项目目录结构中的文件夹,如下所示systemjs.config.js:

map: {
    // our app is within the app folder
    app: 'app',
Run Code Online (Sandbox Code Playgroud)

SystemJs main.js在该文件夹中查找文件.当app/main.js找到并加载到浏览器中时,在其代码require中找到调用:

var app_module_1 = require('./app.module');
Run Code Online (Sandbox Code Playgroud)

然后systemjs app.module.js从本地系统获取文件.这又有其自身的依赖性,如:

var core_1 = require('@angular/core');
Run Code Online (Sandbox Code Playgroud)

循环重复 - 加载,搜索依赖关系,加载它们并执行.这是所有dependecies在浏览器中解析,加载和执行的方式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',
Run Code Online (Sandbox Code Playgroud)

这里要理解的第一件事是这些是映射,而不是依赖.这意味着如果您的文件@angular/core都没有导入,则不会将其加载到浏览器.但是,您可能会看到此特定模块是在app/app.module.ts以下位置导入的:

import { NgModule }      from '@angular/core';
Run Code Online (Sandbox Code Playgroud)

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

var core_1 = require('@angular/core');
Run Code Online (Sandbox Code Playgroud)

现在systemjs明白它需要解决和加载@angular/core.它首先mappings按照文档中的规定进行检查:

map选项与path类似,但在规范化过程中很早就起作用了.它允许您将模块别名映射到位置或包.

我称之为命名模块的解决方案.因此,它找到了映射和替换@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';
Run Code Online (Sandbox Code Playgroud)

但是,这应该@angular.core在项目和lib文件的所有引用中完成,包括@angular,至少可以说这不是一个好的解决方案.

  • 感谢您花时间详细解释这一点.在其他任何地方都很难找到这些信息. (4认同)
  • 真是太棒了.我正在努力了解整个生态系统如何运作在幕后发生的事情. (2认同)
  • @Sangram,谢谢,您可以关注 [angularindepth.com](https://blog.angularindepth.com/) 出版物,了解您在其他任何地方都找不到的更深入的主题 (2认同)
  • @karns,当前版本的CLI内未使用systemjs。Webpack是基础构建系统 (2认同)