Javascript Angular2 加载时文件请求过多

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/35280582/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 17:31:20  来源:igfitidea点击:

Angular2 too many file requests on load

javascripttypescriptangularsystemjs

提问by Marcos Basualdo

I'm making a website using Angular2and I'm having what i suppose is an issue. On the first load of my angular page, SystemJSis making more than 500 hundred requests to retrieve every Angular2file in angular2/srcdirectory. In total, the first load downloads more than 4MB and it takes more than 14 seconds to start.

我正在使用一个网站Angular2,但我遇到了我认为的问题。在我的 angular 页面的第一次加载时,SystemJS发出超过 50000 个请求来检索目录中的每个Angular2文件angular2/src。总的来说,第一次加载下载超过 4MB,启动时间超过 14 秒。

My index.htmldoes the following scripts includes:

index.html的以下脚本包括:

<script src="libs/angular2/bundles/angular2-polyfills.js"></script>
<script src="libs/systemjs/dist/system.src.js"></script>
<script src="libs/rxjs/bundles/Rx.js"></script>
<script src="libs/angular2/bundles/angular2.min.js"></script>
<script src="libs/angular2/bundles/http.dev.js"></script>
<script src="libs/jquery/jquery.js"></script>
<script src="libs/lodash/lodash.js"></script>
<script src="libs/bootstrap/js/bootstrap.js"></script>

And my systemJs initialization code looks like this:

我的 systemJs 初始化代码如下所示:

    <script>
      System.config({
        defaultJSExtensions: true,
        paths: {
          '*': 'libs/*',
          'app/*': 'app/*'
        },
        packageConfigPaths: ['libs/*/package.json'],
        packages: {
          app: {
            format: 'register',
            defaultExtension: 'js'
          }
        }
      });
      System.import('app/main')
            .then(null, console.error.bind(console));

    </script>

My public folder has the following structure:

我的公用文件夹具有以下结构:

.
├── img
├── styles
├── app
├── libs
|   └── angular2
|   └── systemjs
|   └── rxjs
|   └── jquery
|   └── lodash
|   └── bootstrap
└── index.html

A couple of screenshots of some of the js files that are being requested: enter image description here

一些正在请求的 js 文件的屏幕截图: 在此处输入图片说明

enter image description here

在此处输入图片说明

Is there a way to avoid all of those requests?

有没有办法避免所有这些请求?

采纳答案by David Herod

I had the exact same problem, was actually looking at this post for an answer. Here is what I did to solve the problem.

我遇到了完全相同的问题,实际上是在看这篇文章以寻求答案。这是我为解决问题所做的工作。

  1. Modify your project to use webpack. Follow this short tutorial: Angular2 QuickStart SystemJS To Webpack
  2. This method will give you a single javascript file however it is quite large (my project file was over 5MB) and needs to be minified. To do this I installed webpack globaly:npm install webpack -g. Once installed, run webpack -pfrom your apps root directory. This brought my file size down to about 700KB
  1. 修改您的项目以使用 webpack。按照这个简短的教程: Angular2 QuickStart SystemJS 到 Webpack
  2. 此方法将为您提供一个 javascript 文件,但它非常大(我的项目文件超过 5MB)并且需要缩小。为此,我全局安装了 webpack:npm install webpack -g. 安装后,webpack -p从您的应用程序根目录运行。这使我的文件大小减少到大约 700KB

From 20 seconds and 350 requests down to 3 seconds and 7 requests.

从 20 秒和 350 个请求减少到 3 秒和 7 个请求。

回答by MrCroft

I see you already have a response, which is good of course. BUT for those who want to use systemjs(like I also do), and not go to webpack, you can still bundle the files. However, it does involve using another tool also (I use gulp). So... you would have the folowing systemjs config (not in the html, but in a separate file - let's call it "system.config.js"):

我看到你已经有了回应,这当然很好。但是对于那些想要使用systemjs(就像我也这样做)而不是去 webpack 的人,你仍然可以捆绑这些文件。但是,它也涉及使用另一个工具(我使用 gulp)。所以......你会有以下 systemjs 配置(不是在 html 中,而是在一个单独的文件中 - 我们称之为“system.config.js”):

(function(global) {

    // map tells the System loader where to look for things
    var map = {
        'app':                        'dist/app', // this is where your transpiled files live
        'rxjs':                       'node_modules/rxjs',
        'angular2-in-memory-web-api': 'node_modules/angular2-in-memory-web-api', // this is something new since angular2 rc.0, don't know what it does
        '@angular':                   'node_modules/@angular'
    };

    // packages tells the System loader how to load when no filename and/or no extension
    var packages = {
        'app':                        { main: 'boot.js',  defaultExtension: 'js' },
        'rxjs':                       { defaultExtension: 'js' },
        'angular2-in-memory-web-api': { defaultExtension: 'js' }
    };

    var packageNames = [
        '@angular/common',
        '@angular/compiler',
        '@angular/core',
        '@angular/http',
        '@angular/platform-browser',
        '@angular/platform-browser-dynamic',
        //'@angular/router', // I still use "router-deprecated", haven't yet modified my code to use the new router that came with rc.0
        '@angular/router-deprecated',
        '@angular/http',
        '@angular/testing',
        '@angular/upgrade'
    ];

    // add package entries for angular packages in the form '@angular/common': { main: 'index.js', defaultExtension: 'js' }
    packageNames.forEach(function(pkgName) {
        packages[pkgName] = { main: 'index.js', defaultExtension: 'js' };
    });

    var config = {
        map: map,
        packages: packages
    };

    // filterSystemConfig - index.html's chance to modify config before we register it.
    if (global.filterSystemConfig) { global.filterSystemConfig(config); }

    System.config(config);
})(this);

Then, in your gulpfile.js you would build a bundle like this (using the info from system.config.jsand tsconfig.jsonfiles):

然后,在您的 gulpfile.js 中,您将构建一个这样的包(使用来自system.config.jstsconfig.json文件的信息):

var gulp = require('gulp'),
    path = require('path'),
    Builder = require('systemjs-builder'),
    ts = require('gulp-typescript'),
    sourcemaps  = require('gulp-sourcemaps');

var tsProject = ts.createProject('tsconfig.json');

var appDev = 'dev/app'; // where your ts files are, whatever the folder structure in this folder, it will be recreated in the below 'dist/app' folder
var appProd = 'dist/app';

/** first transpile your ts files */
gulp.task('ts', () => {
    return gulp.src(appDev + '/**/*.ts')
        .pipe(sourcemaps.init({
            loadMaps: true
        }))
        .pipe(ts(tsProject))
        .pipe(sourcemaps.write('.'))
        .pipe(gulp.dest(appProd));
});

/** then bundle */
gulp.task('bundle', function() {
    // optional constructor options
    // sets the baseURL and loads the configuration file
    var builder = new Builder('', 'dist/system.config.js');

    /*
       the parameters of the below buildStatic() method are:
           - your transcompiled application boot file (the one wich would contain the bootstrap(MyApp, [PROVIDERS]) function - in my case 'dist/app/boot.js'
           - the output (file into which it would output the bundled code)
           - options {}
    */
    return builder
        .buildStatic(appProd + '/boot.js', appProd + '/bundle.js', { minify: true, sourceMaps: true})
        .then(function() {
            console.log('Build complete');
        })
        .catch(function(err) {
            console.log('Build error');
            console.log(err);
        });
});

/** this runs the above in order. uses gulp4 */
gulp.task('build', gulp.series(['ts', 'bundle']));

So, when running "gulp build", you will get the "bundle.js" file with everything you need. Sure, you also need a few more packages for this gulp bundle task to work:

因此,当运行“gulp build”时,您将获得包含您需要的所有内容的“bundle.js”文件。当然,你还需要一些更多的包来让这个 gulp bundle 任务工作:

npm install --save-dev github:gulpjs/gulp#4.0 gulp-typescript gulp-sourcemaps path systemjs-builder

Also, make sure that in your tsconfig.json you have "module":"commonjs". Here is my tsconfig.json which is used in my 'ts'gulp task:

另外,请确保在您的 tsconfig.json 中有"module":"commonjs". 这是我在 gulp'ts'任务中使用的 tsconfig.json :

{
    "compilerOptions": {
        "target": "es5",
        "module": "commonjs",
        "moduleResolution": "node",
        "sourceMap": true,
        "emitDecoratorMetadata": true,
        "experimentalDecorators": true,
        "removeComments": false,
        "noImplicitAny": false
    },
    "exclude": [
        "node_modules",
        "typings/main",
        "typings/main.d.ts"
    ]
}

Then, in your html file you only need to include this:

然后,在您的 html 文件中,您只需要包含以下内容:

<!-- Polyfill(s) for older browsers -->
<script src="node_modules/es6-shim/es6-shim.min.js"></script>

<script src="node_modules/zone.js/dist/zone.js"></script>
<script src="node_modules/reflect-metadata/Reflect.js"></script>
<script src="dist/app/bundle.js"></script>

And that's it... I got from 600 requests, 4mb in about 5 seconds... to 20 requests, 1.4mb in 1.6 seconds (local development machine). But these 20 requests ~1.4mb in 1.6 seconds also include some other js and css that the admin theme came with plus a few html templates that get required on the first load, I prefer to use external templates - templateUrl: '', instead of inline ones, written in my component.ts file. Sure, for an app that would have millions of users, this still wouldn't be enough. Also server-side rendering for initial load and cache system should be implemented, I actually managed to do that with angular universal, but on Angular2 beta (took about 200-240 millisecondsto load the initial render of the same admin app that above takes 1.6 seconds - I know: WOW!). Now it's incompatible since Angular2 RC came out, but I'm sure the guys doing universal will get it up to speed soon, specially since ng-conf is coming up. Plus, they're also planing to make Angular Universal for PHP, ASP and a few other - right now it's only for Nodejs.

就是这样......我从 600 个请求,大约 5 秒内获得 4mb......到 20 个请求,1.6 秒内获得 1.4mb(本地开发机器)。但是这 20 个请求在 1.6 秒内约 1.4mb 还包括管理主题附带的一些其他 js 和 css 以及一些在第一次加载时需要的 html 模板,我更喜欢使用外部模板 - templateUrl: '',而不是内联的,写在我的 component.ts 文件中。当然,对于拥有数百万用户的应用程序来说,这仍然不够。还应该实现初始加载和缓存系统的服务器端渲染,我实际上设法用 angular 通用来做到这一点,但是在 Angular2 beta 上(大约需要200-240 毫秒来加载上面需要 1.6 的相同管理应用程序的初始渲染秒 - 我知道:哇!)。现在它不兼容,因为 Angular2 RC 出来了,但我相信做通​​用的人很快就会加快速度,特别是因为 ng-conf 即将推出。另外,他们还计划为 PHP、ASP 和其他一些工具制作 Angular Universal——现在它只适用于 Nodejs。

Edit:Actually, I've just found out that on NG-CONF they said Angular Universal already supports ASP (but it doesn't support Angular2 > beta.15 :)) ... but let's give them some time, RC just came out a few days ago

编辑:实际上,我刚刚发现在 NG-CONF 上,他们说 Angular Universal 已经支持 ASP(但它不支持 Angular2 > beta.15 :))...但是让我们给他们一些时间,RC 刚刚来几天前出来

回答by FreeBird72

I found a simple solution, using browserify & uglifyjs on mgechev's angular2-seed repository

我找到了一个简单的解决方案,在mgechev 的 angular2-seed 存储库上使用browserify和 uglifyjs

Here's my version:

这是我的版本:

pacakge.json:

pacakge.json:

{
...
  "scripts": {
      "build_prod": "npm run clean && npm run browserify",
      "clean": "del /S/Q public\dist",
      "browserify": "browserify -s main  public/YourMainModule.js > public/dist/bundle.js && npm run minify",
      "minify": "uglifyjs public/dist/bundle.js --screw-ie8 --compress --mangle --output public/dist/bundle.min.js"
    },
...
  "devDependencies": {
      "browserify": "^13.0.1",    
      "typescript": "^1.9.0-dev.20160625-1.0",
      "typings": "1.0.4",
      "uglifyjs": "^2.4.10"
    }
}
  1. Build your project.
  2. Run: npm run build_prodIt'll create bundle.js & bundle.min.js under public\dist directory.
  3. Edit your index.htmlfile: Instead of running System.import('YourMainModule')... ,add <script src="/dist/bundle.min.js"></script>
  1. 构建您的项目。
  2. 运行:npm run build_prod会在public\dist目录下创建bundle.js & bundle.min.js。
  3. 编辑您的index.html文件:而不是运行System.import('YourMainModule')... ,添加<script src="/dist/bundle.min.js"></script>

回答by Thierry Templier

I think that your question is related to this one:

我认为你的问题与这个有关:

To have something ready for production (and speed it up), you need to package it.

要为生产做好准备(并加快生产速度),您需要对其进行打包。

I mean transpiling all files into JavaScript ones and concat them the same way Angular2 does for example. This way you will have several modules contained into a single JS file. This way you will reduce the number of HTTP calls to load your application code into the browser.

我的意思是将所有文件转换为 JavaScript 文件并以与 Angular2 相同的方式连接它们,例如。这样,您将在一个 JS 文件中包含多个模块。这样,您将减少将应用程序代码加载到浏览器的 HTTP 调用次数。

回答by lthh89vt

@FreeBird72 Your answer is awesome.

@FreeBird72 你的回答很棒。

If you want to use SystemJS for development and speed up the production server like I do. Check this out.

如果你想像我一样使用 SystemJS 进行开发并加速生产服务器。看一下这个。

NOTE:Only import the components that you use, DO NOT import from the whole package.

注意:仅导入您使用的组件,不要从整个包中导入。

Eg: If you want to use Modal from ng2-bootstrap.

例如:如果你想使用 ng2-bootstrap 中的 Modal。

import {MODAL_DIRECTIVES} from "ng2-bootstrap/components/modal";

Instead of:

代替:

import {MODAL_DIRECTIVES} from "ng2-bootstrap/ng2-bootstrap";

This will import the modal component instead of the whole ng2-bootstrap

这将导入模态组件而不是整个 ng2-bootstrap

Then follow the answer from @FreeBird72

然后按照@FreeBird72的答案进行操作

Add this package.json

添加这个 package.json

{
  ...
  "scripts": {
    ...
    "prod": "npm run tsc && npm run browserify",
    "browserify": "browserify -s main  dist/main.js > dist/bundle.js && npm run minify",
    "minify": "uglifyjs dist/bundle.js --screw-ie8 --compress --mangle --output dist/bundle.min.js",
    ...
  },
  "devDependencies": {
    ...
    "browserify": "^13.0.1",    
    "uglifyjs": "^2.4.10",
    ...
  }
  ...
}

Then you can npm run tscon development and npm run prodon production server Also remove System.import(....from your index.html and change it to <script src="/dist/bundle.min.js"></script>

然后你可以npm run tsc在开发和npm run prod生产服务器上也System.import(....从你的 index.html 中删除并将其更改为<script src="/dist/bundle.min.js"></script>

回答by basarat

On the first load of my angular page, systemjs is making more than 500 hundred requests to retrieve every angular2 file in angular2/src directory. In total, the first load downloads more than 4mb and it takes more than 14s to start.

在我的 angular 页面的第一次加载时,systemjs 发出超过 50000 个请求来检索 angular2/src 目录中的每个 angular2 文件。总的来说,第一次加载下载超过 4mb,启动时间超过 14 秒。

The SystemJs workflows are fairly new and don't have enough research in them for best deployment.

SystemJs 工作流是相当新的,没有足够的研究来实现最佳部署。

Suggest going back to commonjs+ webpack. More : https://basarat.gitbooks.io/typescript/content/docs/quick/browser.html

建议回到commonjs+ webpack。更多:https: //basarat.gitbooks.io/typescript/content/docs/quick/browser.html

Here is an example : https://github.com/AngularClass/angular2-webpack-starter

这是一个例子:https: //github.com/AngularClass/angular2-webpack-starter

回答by Harry

The Angular command line interface now supports bundling (with tree-shaking to strip out unused code from imports), minification, and ahead-of-time template compilation, which not only hugely minimises the number of requests made, but also makes the bundle very small. It uses WebPack underneath.

Angular 命令行界面现在支持捆绑(通过摇树从导入中去除未使用的代码)、缩小和提前模板编译,这不仅极大地减少了发出的请求数量,而且使捆绑非常小的。它在下面使用 WebPack。

It's incredibly easy to make production builds with it:

使用它进行生产构建非常容易:

ng build --prod --aot

https://github.com/angular/angular-cli

https://github.com/angular/angular-cli

回答by Harry

If you want to stick with SystemJS, you can bundle your app with JSPM. I've had good success with this so far, using JSPM's bundle-sfxcommand to make single JS files for Angular 2 apps.

如果您想坚持使用 SystemJS,您可以将您的应用程序与JSPM捆绑在一起。到目前为止,我在这方面取得了很好的成功,使用 JSPM 的bundle-sfx命令为 Angular 2 应用程序制作单个 JS 文件。

There's some useful information in this Gist, and there's a seed project.

这个 Gist 中有一些有用的信息,还有一个种子项目。

回答by Wong Kim Wah

I am using AG2 RC version While using MrCroft's solution with systemjs-builder, i was hitting a lot of issues like: error TS2304: Cannot find name 'Map' error TS2304: Cannot find name 'Promise'...

我正在使用 AG2 RC 版本在将 MrCroft 的解决方案与 systemjs-builder 一起使用时,我遇到了很多问题,例如:错误 TS2304:找不到名称“地图”错误 TS2304:找不到名称“承诺”...

After many tries, i added: ///<reference path="../../typings/index.d.ts" />into my boot.ts and now I got my bundle file compiled.

经过多次尝试,我添加: ///<reference path="../../typings/index.d.ts" />到我的 boot.ts 中,现在我编译了我的包文件。