Ответ 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
, что не является хорошим решением, как минимум.