我是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正在做的事情。
这让我很困惑。任何帮助将不胜感激。
答案 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';
现在,为什么映射存在。假设systemjs
将app/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
,这至少可以说是一个不错的解决方案。