简体   繁体   English

Angular2加载的文件请求过多

[英]Angular2 too many file requests on load

I'm making a website using Angular2 and I'm having what i suppose is an issue. 我正在使用Angular2创建一个网站,但我有一个问题。 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. 在我的angular页面的第一次加载中, SystemJS发出了500多个请求来检索angular2/src目录中的每个Angular2文件。 In total, the first load downloads more than 4MB and it takes more than 14 seconds to start. 总共,首次加载下载超过4MB,并且开始花费的时间超过14秒。

My index.html does 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: 一些被请求的js文件的屏幕截图: 在此处输入图片说明

在此处输入图片说明

Is there a way to avoid all of those requests? 有办法避免所有这些请求吗?

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. 修改您的项目以使用webpack。 Follow this short tutorial: Angular2 QuickStart SystemJS To Webpack 请遵循以下简短教程: Angular2 QuickStart SystemJS到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. 此方法将为您提供单个javascript文件,但是它很大(我的项目文件超过5MB),并且需要缩小。 To do this I installed webpack globaly: npm install webpack -g . 为此,我全局安装了webpack: npm install webpack -g Once installed, run webpack -p from your apps root directory. 安装后,从您的应用程序根目录运行webpack -p This brought my file size down to about 700KB 这使我的文件大小减小到约700KB

From 20 seconds and 350 requests down to 3 seconds and 7 requests. 从20秒和350个请求降低到3秒和7个请求。

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. 但是对于那些想要使用systemjs (就像我也一样),而不是去使用webpack的人,您仍然可以捆绑文件。 However, it does involve using another tool also (I use gulp). 但是,它确实也涉及使用其他工具(我使用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配置(不在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.js and tsconfig.json files): 然后,在您的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. 因此,当运行“ gulp build”时,将获得包含所有所需内容的“ bundle.js”文件。 Sure, you also need a few more packages for this gulp bundle task to work: 当然,您还需要更多软件包才能使该gulp捆绑包任务正常工作:

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" . 另外,请确保在tsconfig.json中具有"module":"commonjs" Here is my tsconfig.json which is used in my 'ts' gulp task: 这是我的'ts' gulp任务中使用的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). 就是这样...我从600个请求(大约5秒内的4mb)到20个请求(1.6秒内的1.4mb)(本地开发机器)。 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. 但是这20个请求在1.6秒内达到约1.4mb,其中还包括管理主题附带的其他js和CSS,以及一些首次加载时需要的html模板,我更喜欢使用外部模板-templateUrl:”,而不是内联代码,写在我的component.ts文件中。 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 milliseconds to load the initial render of the same admin app that above takes 1.6 seconds - I know: WOW! ). 同样应该为初始加载和缓存系统实现服务器端渲染,我实际上设法使用angular Universal做到了这一点,但是在Angular2 beta(花了大约200-240毫秒来加载同一个管理应用程序的初始渲染,而上述花费1.6秒-我知道: 哇! )。 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. 自从Angular2 RC发布以来,它就已经不兼容了,但是我敢肯定,进行通用开发的人很快就会加快速度,特别是因为ng-conf即将推出。 Plus, they're also planing to make Angular Universal for PHP, ASP and a few other - right now it's only for Nodejs. 此外,他们还计划将Angular Universal用于PHP,ASP和其他一些工具-现在仅适用于Node.js。

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刚刚问世。几天前

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. 我的意思是将所有文件都转换为JavaScript文件,然后像Angular2一样将它们合并。 This way you will have several modules contained into a single JS file. 这样,您将在单个JS文件中包含多个模块。 This way you will reduce the number of HTTP calls to load your application code into the browser. 这样,您将减少将应用程序代码加载到浏览器中的HTTP调用次数。

I found a simple solution, using browserify & uglifyjs on mgechev's angular2-seed repository 我找到了一个简单的解决方案,在mgechev的angular2种子存储库上使用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_prod It'll create bundle.js & bundle.min.js under public\\dist directory. 运行: npm run build_prod它将在public \\ dist目录下创建bundle.js和bundle.min.js。
  3. Edit your index.html file: Instead of running System.import('YourMainModule')... , add <script src="/dist/bundle.min.js"></script> 编辑index.html文件:代替运行System.import('YourMainModule')... ,添加<script src="/dist/bundle.min.js"></script>

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. 在我的angular页面的第一次加载中,systemjs发出了500多个请求来检索angular2 / src目录中的每个angular2文件。 In total, the first load downloads more than 4mb and it takes more than 14s to start. 总共,首次加载下载的大小超过4mb,并且开始耗时超过14s。

The SystemJs workflows are fairly new and don't have enough research in them for best deployment. SystemJs工作流是相当新的,并且没有足够的研究来最好地进行部署。

Suggest going back to commonjs + webpack . 建议回到commonjs + webpack More : https://basarat.gitbooks.io/typescript/content/docs/quick/browser.html 更多: 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

@FreeBird72 Your answer is awesome. @ FreeBird72您的答案很棒。

If you want to use SystemJS for development and speed up the production server like I do. 如果您想像我一样使用SystemJS进行开发并加快生产服务器的速度。 Check this out. 看一下这个。

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 tsc on development and npm run prod on 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 。还从index.html中删除System.import(....并将其更改为<script src="/dist/bundle.min.js"></script>

If you want to stick with SystemJS, you can bundle your app with JSPM . 如果您想坚持使用SystemJS,可以将您的应用程序与JSPM捆绑在一起。 I've had good success with this so far, using JSPM's bundle-sfx command to make single JS files for Angular 2 apps. 到目前为止,我已经取得了很好的成功,使用JSPM的bundle-sfx命令为Angular 2应用制作了单个JS文件。

There's some useful information in this Gist , and there's a seed project. Gist中有一些有用的信息,并且有一个种子项目。

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" />添加了///<reference path="../../typings/index.d.ts" /> ,现在我的捆绑文件已编译好。

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. Angular命令行界面现在支持捆绑(通过摇晃来从导入中删除未使用的代码),最小化和提前模板编译,这不仅极大地减少了发出的请求数量,而且使捆绑非常小。 It uses WebPack underneath. 它在下面使用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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM