SystemJS 和 Webpack 之间有什么区别?

What are differences between SystemJS and Webpack?

我正在创建我的第一个 Angular 应用程序,我会弄清楚模块加载器的作用是什么。 为什么我们需要它们? 我尝试在 Google 上搜索和搜索,但我不明白为什么我们需要将其中之一安装到 运行 我们的应用程序中?

仅使用 import 从节点模块加载内容是否足够?

我已经关注 this tutorial(使用 SystemJS),它让我使用 systemjs.config.js 文件:

/**
 * System configuration for Angular samples
 * Adjust as necessary for your application needs.
 */
(function(global) {
  // map tells the System loader where to look for things
  var map = {
    'app':                        'transpiled', // 'dist',
    '@angular':                   'node_modules/@angular',
    'angular2-in-memory-web-api': 'node_modules/angular2-in-memory-web-api',
    'rxjs':                       'node_modules/rxjs'
  };
  // packages tells the System loader how to load when no filename and/or no extension
  var packages = {
    'app':                        { main: 'main.js',  defaultExtension: 'js' },
    'rxjs':                       { defaultExtension: 'js' },
    'angular2-in-memory-web-api': { main: 'index.js', defaultExtension: 'js' },
  };
  var ngPackageNames = [
    'common',
    'compiler',
    'core',
    'forms',
    'http',
    'platform-browser',
    'platform-browser-dynamic',
    'router',
    'router-deprecated',
    'upgrade',
  ];
  // Individual files (~300 requests):
  function packIndex(pkgName) {
    packages['@angular/'+pkgName] = { main: 'index.js', defaultExtension: 'js' };
  }
  // Bundled (~40 requests):
  function packUmd(pkgName) {
    packages['@angular/'+pkgName] = { main: '/bundles/' + pkgName + '.umd.js', defaultExtension: 'js' };
  }
  // Most environments should use UMD; some (Karma) need the individual index files
  var setPackageConfig = System.packageWithIndex ? packIndex : packUmd;
  // Add package entries for angular packages
  ngPackageNames.forEach(setPackageConfig);
  var config = {
    map: map,
    packages: packages
  };
  System.config(config);
})(this);

为什么我们需要这个配置文件?
为什么我们需要 SystemJS(或 WebPack 或其他)?
最后,你觉得哪个更好?

如果你去SystemJS Github页面,你会看到工具的描述:

Universal dynamic module loader - loads ES6 modules, AMD, CommonJS and global scripts in the browser and NodeJS.

因为你在 TypeScript 或 ES6 中使用模块,所以你需要一个模块加载器。对于 SystemJS,systemjs.config.js 允许我们配置模块名称与其对应文件匹配的方式。

如果您明确使用此配置文件(和 SystemJS)来导入应用程序的主模块,则此配置文件(和 SystemJS)是必需的:

<script>
  System.import('app').catch(function(err){ console.error(err); });
</script>

使用 TypeScript 并将编译器配置到 commonjs 模块时,编译器创建的代码不再基于 SystemJS。在此示例中,typescript 编译器配置文件将如下所示:

{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs", // <------
    "moduleResolution": "node",
    "sourceMap": true,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "removeComments": false,
    "noImplicitAny": false
  }
}

Webpack 是一个灵活的模块打包器。这意味着它走得更远,不仅处理模块,还提供了一种打包应用程序的方法(concat 文件、uglify 文件,...)。它还为开发提供了一个带有加载重载的开发服务器。

SystemJS 和 Webpack 不同,但使用 SystemJS,您仍然需要做一些工作(例如使用 Gulp or SystemJS builder)来打包 Angular2 应用程序以用于生产。

SystemJS 在客户端工作。它在需要时按需动态加载模块(文件)。您不必预先加载整个应用程序。例如,您可以在按钮单击处理程序中加载文件。

SystemJS 代码:

// example import at top of file
import myModule from 'my-module'
myModule.doSomething()

// example dynamic import (could be placed anywhere in your code)
// module not loaded until code is hit
System.import('my-module').then((myModule) {
  // myModule is available here
  myModule.doSomething()
});

除了配置它工作之外,这就是 SystemJS 的全部!你现在是 SystemJS 专家了!

Webpack 完全不同,需要永远掌握。它不做与 SystemJS 相同的事情,但是,当使用 Webpack 时,SystemJS 变得多余。

Webpack 准备了一个名为 bundle.js 的文件 - 这个文件包含所有 HTML、CSS、JS 等。因为所有文件都捆绑在一个文件中,所以现在不需要像 SystemJS 这样的延迟加载器(其中单个文件 根据需要加载)。

SystemJS 的优势在于延迟加载。该应用程序应该加载得更快,因为您不会一次性加载所有内容。

Webpack 的优势在于,虽然应用程序最初可能需要几秒钟才能加载,但一旦加载并缓存,它就会快如闪电。

我更喜欢 SystemJS,但 Webpack 似乎更流行。

Angular2 quickstart 使用 SystemJS。

Angular CLI 使用 Webpack。

Webpack 2(将提供 tree shaking)处于测试阶段,所以现在可能不是迁移到 Webpack 的好时机。

注意 SystemJS 正在实现 ES6 module loading standard。 Webpack 只是另一个 npm 模块。

Task runners(对于那些想了解 SystemJS 可能存在的生态系统的人的可选阅读)

对于 SystemJS,它的唯一职责是延迟加载文件,因此仍然需要一些东西来缩小这些文件、转换这些文件(例如从 SASS 到 CSS)等。这些工作必须完成的任务称为 任务

Webpack 在配置后会正确地为您执行此操作(并将输出捆绑在一起)。如果你想用 SystemJS 做一些类似的事情,你通常会使用 JavaScript 任务运行器。最受欢迎的任务运行器是另一个名为 gulp 的 npm 模块。

因此,例如,SystemJS 可能会延迟加载已被 gulp 缩小的缩小 JavaScript 文件。 Gulp,如果设置正确,可以即时缩小文件并实时重新加载。实时重新加载是代码更改的自动检测和自动浏览器刷新以更新。在开发过程中很棒。使用 CSS,可以进行实时流式传输(即您看到页面更新了新样式,甚至无需重新加载页面)。

Webpack 和 gulp 还可以执行许多其他任务,这里无法一一列举。我提供了一个例子:)

到目前为止,我一直在使用 systemjs。它正在一个接一个地加载文件,第一次加载需要 3-4 秒,而没有缩小文件。切换到 webpack 后,我得到了很大的性能提升。现在只需要加载一个包文件(还有 polyfills 和供应商库,它们几乎从未改变并且几乎总是被缓存),仅此而已。现在只需一秒钟即可加载客户端应用程序。没有额外的客户端逻辑。加载的单个文件的数量越少,性能就越高。使用 systemjs 时,您应该考虑动态导入模块以节省性能。使用 webpack 你主要关注你的逻辑,因为一旦包被缩小并缓存在你的浏览器中,性能仍然会很好。