SystemJS和Webpack有什么区别?

235

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

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

我已经按照这个教程(使用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或其他)?
最后,你认为哪个更好?


4
在这里,您可以阅读一篇非常好的文章,比较SystemJs(Jspm)和Webpack:http://ilikekillnerds.com/2015/07/jspm-vs-webpack。 - Sweta
请查看此答案 https://dev59.com/2FkR5IYBdhLWcg3w6RED#40670147 以获取有关SystemJS的信息。 - Max Koretskyi
3个回答

214

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 模块加载标准。而 Webpack 只是另一个 npm 模块。

任务运行器(可选阅读,适用于想要了解 SystemJS 可能存在的生态系统的人)

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

Webpack 在正确配置时会为您完成这些工作(并将输出捆绑在一起)。如果您想在 SystemJS 中执行类似的操作,则通常会使用 JavaScript 任务运行器。最流行的任务运行器是另一个 npm 模块,称为 gulp

因此,例如,SystemJS 可以懒加载由 gulp 进行缩小处理的 JavaScript 文件。设置正确后,gulp 可以在运行时缩小文件并进行实时重载。实时重载是自动检测代码更改和自动浏览器刷新以更新的功能,在开发过程中非常好用。对于 CSS,可以进行实时流式传输(即看到页面更新新样式,而不必刷新页面)。

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


7
我也觉得SystemJS和JSPM比webpack更容易使用。而且我发现生成的生产包要小一些(与另一个webpack示例项目相比)。以下是我关于此主题的帖子:https://dev59.com/ilkS5IYBdhLWcg3wMTys - Peter Salomonsen
7
你可以使用angular2-router-loader与Webpack和懒加载。了解更多信息请参见https://medium.com/@daviddentoom/angular-2-lazy-loading-with-webpack-d25fe71c29c1。 - Alex Klaus
37
关于Webpack,你的看法是错误的!它允许你将捆绑和惰性加载相结合。此外,它会自动将延迟加载的模块打包成块。 - dizel3d
3
@AlexKlaus,谢谢你提供的例子!我一直在寻找类似的东西 :) - tftd
4
Webpack和SystemJS是完全不同的工具,需要花费很长时间来掌握。它们的功能也不相同,但是当使用Webpack时,SystemJS变得多余了。然而,我不同意这种看法。SystemJS仍然可以让开发者在不必为每次更改都进行构建的情况下进行开发。我可以对一个TypeScript文件进行修改,保存(这将自动调用tsc.exe进行构建),然后重新加载页面而不会有任何问题。而使用Webpack时,我必须重新构建项目,这可能需要更长的时间,因为它会重新编译和构建所有内容。我还没有找到任何使用Webpack避免这种情况的方法。 - Polantaris
显示剩余2条评论

144
如果您前往SystemJS的GitHub页面,您将看到该工具的描述:
通用动态模块加载器 - 在浏览器和NodeJS中加载ES6模块、AMD、CommonJS和全局脚本。
因为您在TypeScript或ES6中使用模块,所以需要一个模块加载器。在SystemJS的情况下,systemjs.config.js允许我们配置模块名称与相应文件匹配的方式。
如果您明确使用它来导入应用程序的主模块,则需要此配置文件(和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是一个灵活的模块打包工具。这意味着它不仅处理模块,还提供了一种打包应用程序的方式(合并文件、压缩文件等)。它还提供了一个带有热重载功能的开发服务器。
SystemJS和Webpack是不同的,但使用SystemJS时,你仍然需要进行一些工作(例如使用GulpSystemJS builder)来为生产环境打包Angular2应用程序。

2
当你说“使用SystemJS时,你仍然需要做一些工作(例如使用Gulp或SystemJS构建器)来为生产环境打包你的Angular2应用程序”时,这是否意味着我当前使用npm start命令? - smartmouse
5
实际上,对于生产环境来说,为模块加载大量文件(单个文件(300个请求)或打包的文件(40个请求))是不高效的。你需要将所有内容收集到一个或两个文件中(你的代码和第三方库代码),离线编译你的模板(使用ngc),并利用树摇动(tree shaking)来最小化捆绑包的大小。这篇文章可能会对你有帮助:http://blog.mgechev.com/2016/06/26/tree-shaking-angular2-production-build-rollup-javascript/。同时,你还需要混淆CSS文件。 - Thierry Templier
1
使用npm start,你可以“简单地”启动一个服务器,该服务器将根据你的SystemJS模块配置为应用程序提供服务... - Thierry Templier
11
谷歌已正式转向使用webpack。因此,我认为最好坚持使用大多数社区正在使用的工具。我很快就会将我的systemJS项目迁移到webpack上,但并不确定应该如何操作。 - user2180794
1
@JonasKello 这是 Angular CLI 的情况。请查看此链接:https://github.com/angular/angular-cli,在“Webpack update”一节中。 - Thierry Templier
显示剩余5条评论

1

到目前为止,我一直在使用systemjs。它逐个加载文件,第一次加载没有缩小的文件需要3-4秒钟。切换到webpack之后,我获得了很大的性能提升。现在只需要加载一个捆绑文件(还有几乎从不更改且几乎总是缓存的polyfills和vendor libs),就完成了。现在加载客户端应用程序只需要一秒钟,没有额外的客户端逻辑。加载的单个文件数量越少,性能越高。当使用systemjs时,应考虑动态导入模块以节省性能。使用webpack时,主要关注逻辑,因为一旦捆绑文件被缩小并在浏览器中缓存,性能仍将良好。


3
您只回答了 OP 的一个问题,留下一条评论可能更好。 - Ben

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接