В чем необходимость SystemJS в Angular2?

Я начинаю начинать до Angular и Angular2. Я смущен тем, как структурирован рабочий процесс. Я смотрел образец проекта, который присутствует на сайте Angular2.

Исправьте меня, если я ошибаюсь, но до сих пор я знаю, что все typescript передаются в javascript компилятором typescript. Тогда скомпилированный javascript на самом деле работает в браузере.

Теперь, если я импортирую файлы javascript в typescript, используя инструкции импорта ES6, такие как: -

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

Я имею в виду не то, что счетчик продуктивен? Взглянув на переписанный javascript файлов ts, он показывает, что все операторы импорта преобразуются в операторы require(). Прежде всего, как require() работает в файле ES5 js, а во-вторых, если это то, что делает SystemJS.

Это меня действительно сбивает с толку. Любая помощь будет принята с благодарностью.

Ответ 1

Когда tsc компилирует typescript в JavaScript, вы получаете кучу js файлов в вашей локальной системе. Их нужно как-то загружать в браузер. Поскольку браузеры еще не поддерживают загрузку модуля ES6, у вас есть два варианта: либо поместить их в свой файл index.html в правильном порядке зависимостей, либо вы можете использовать загрузчик, чтобы сделать все это для вас. Вы указываете корень для всех модулей, а затем все файлы загружаются и выполняются этим загрузчиком в правильном порядке зависимостей. Есть много загрузчиков: requirejs, webpack, systemjs и другие. В вашем конкретном случае это systemjs.

Глядя на переписанный javascript файлов ts, он показывает все Операторы импорта преобразуются в операторы require().

Да, это способ SystemJs загружать пакеты. Он использует синтаксис require() и exports, потому что синтаксис CommonJS для загрузки пакетов и вы указали этот тип в tsconfig.json:

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

Если вы должны положить module:'es6', вы увидите, что в ваших скомпилированных файлах javascript записи импорта и экспорта сохраняются. Однако, как упоминалось ранее, вы все еще не можете использовать этот синтаксис, поскольку браузеры не поддерживают его. Если вы хотите поставить module:'amd', вы увидите другой синтаксис, который использует define(). Я думаю, что загрузчик systemjs предпочтителен в учебнике стартера angular2, поскольку он действительно может загружать все типы модулей, поддерживаемые tsc. Однако, если вы хотите загрузить модули в качестве модулей es6, вы должны поместить module: 'system' в свой tsconfig.json. Это модульная система, предназначенная для соответствия стандарту es6 modules и используемая до полной поддержки es6 modules в браузерах.

Как работает настройка

В index.html вы добавите следующий script:

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

Теперь, почему существуют сопоставления. Предположим, что 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';

Однако это должно быть сделано во всех ссылках на @angular.core в файлах проекта и lib, включая @angular, что не является хорошим решением, как минимум.