web-dev-qa-db-fra.com

Angular2 trop de demandes de fichiers au chargement

Je crée un site web en utilisant Angular2 et j'ai ce que je suppose est un problème. Lors du premier chargement de ma angular page, SystemJS fait plus de 500 demandes de récupération pour chaque Angular2 fichier dans angular2/src répertoire. Au total, la première charge télécharge plus de 4 Mo et le démarrage prend plus de 14 secondes.

Ma index.html est-ce que les scripts suivants incluent:

<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>

Et mon code d’initialisation de systemJs ressemble à ceci:

    <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>

Mon dossier public a la structure suivante:

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

Quelques captures d'écran de certains des fichiers js demandés: enter image description here

enter image description here

Y a-t-il un moyen d'éviter toutes ces demandes?

57
Marcos Basualdo

J'ai eu exactement le même problème, je cherchais une réponse dans ce post. Voici ce que j'ai fait pour résoudre le problème.

  1. Modifiez votre projet pour utiliser webpack. Suivez ce court tutoriel: Angular2 QuickStart SystemJS To Webpack
  2. Cette méthode vous donnera un seul fichier javascript, mais il est assez volumineux (mon fichier de projet faisait plus de 5 Mo) et doit être réduit au minimum. Pour ce faire, j'ai installé webpack globaly: npm install webpack -g. Une fois installé, lancez webpack -p depuis le répertoire racine de vos applications. Cela a ramené la taille de mon fichier à environ 700 Ko.

De 20 secondes et 350 demandes à 3 secondes et 7 demandes.

47
David Herod

Je vois que vous avez déjà une réponse, ce qui est bien sûr. MAIS pour ceux qui veulent utiliser systemjs (comme je le fais aussi), et ne pas aller à Webpack, vous pouvez toujours regrouper les fichiers. Cependant, cela implique également l'utilisation d'un autre outil (j'utilise gulp). Donc ... vous auriez la configuration suivante de systemjs (pas dans le code HTML, mais dans un fichier séparé - appelons-le "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);

Ensuite, dans votre fichier gulpfile.js, vous construirez un paquet comme celui-ci (en utilisant les fichiers info de system.config.js Et tsconfig.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']));

Ainsi, lors de l'exécution de "gulp build", vous obtiendrez le fichier "bundle.js" avec tout ce dont vous avez besoin. Bien sûr, vous avez également besoin de quelques paquets supplémentaires pour que cette tâche gulp bundle fonctionne:

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

Assurez-vous également que votre tsconfig.json contient "module":"commonjs". Voici mon tsconfig.json qui est utilisé dans ma tâche 'ts' Gulp:

{
    "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"
    ]
}

Ensuite, dans votre fichier HTML, vous devez seulement inclure ceci:

<!-- 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>

Et c'est tout ... J'ai reçu de 600 demandes, 4 Mo en environ 5 secondes ... à 20 demandes, 1,4 Mo en 1,6 secondes (machine de développement local). Mais ces 20 requêtes ~ 1,4 Mo en 1,6 secondes incluent également quelques autres js et css fournis par le thème administrateur, ainsi que quelques modèles HTML requis au premier chargement, je préfère utiliser des modèles externes - templateUrl: '', au lieu de ceux en ligne, écrits dans mon fichier Component.ts. Bien sûr, pour une application qui aurait des millions d'utilisateurs, cela ne suffirait toujours pas. De plus, le rendu côté serveur pour le chargement initial et le système de cache doit être implémenté. J'ai réussi à le faire avec angular universal, mais sous Angular2 beta (a pris environ 200-240 millisecondes pour charger le rendu initial de la même application d'administration que précédemment prend 1,6 seconde - je sais: WOW! ). Maintenant, c’est incompatible depuis la sortie d’Angular2 RC, mais je suis sûr que les spécialistes de l’universel l’initieront bientôt, notamment parce que ng-conf est à venir. De plus, ils envisagent également de créer Angular Universal pour PHP, ASP et quelques autres - pour le moment, ce n'est que pour Nodejs.

Edit: En fait, je viens de découvrir que sur NG-CONF, ils ont dit Angular Universal supporte déjà ASP (mais il ne supporte pas Angular2> beta.15 :)) ... mais donnons-leur un peu de temps, RC est sorti il ​​y a quelques jours

33
MrCroft

Je pense que votre question est liée à celle-ci:

Pour que quelque chose soit prêt pour la production (et l’accélérer), vous devez l’emballer.

Je veux dire transpiler tous les fichiers en JavaScript et les concaténer de la même façon que Angular2 par exemple. De cette façon, vous aurez plusieurs modules contenus dans un seul fichier JS. De cette façon, vous réduirez le nombre d'appels HTTP pour charger le code de votre application dans le navigateur.

3
Thierry Templier

J'ai trouvé une solution simple, en utilisant browserify & uglifyjs sur référentiel de mgechev's angular2-seed

Voici ma version:

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. Construisez votre projet.
  2. Exécuter: npm lance build_prod Il créera bundle.js & bundle.min.js sous le répertoire public\dist.
  3. Editez votre fichier index.html: Au lieu d’exécuter System.import('YourMainModule')... , add <script src="/dist/bundle.min.js"></script>
3
FreeBird72

Lors du premier chargement de ma angular page, systemjs effectue plus de 500 demandes de récupération de tous les fichiers angular2 dans le répertoire angular2/src. Au total, le premier chargement télécharge plus de 4 Mo. plus de 14 ans pour commencer.

Les flux de travail SystemJs sont relativement nouveaux et ne font pas l'objet de recherches suffisantes pour permettre un déploiement optimal.

Suggérez de revenir à commonjs + webpack. Plus: https://basarat.gitbooks.io/TypeScript/content/docs/quick/browser.html

Voici un exemple: https://github.com/AngularClass/angular2-webpack-starter

1
basarat

@ FreeBird72 Votre réponse est géniale.

Si vous souhaitez utiliser SystemJS pour le développement et accélérer le serveur de production comme je le fais. Regarde ça.

NOTE: Importez uniquement les composants que vous utilisez, NE PAS importer à partir du package complet.

Exemple: si vous souhaitez utiliser Modal à partir de ng2-bootstrap.

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

Au lieu de:

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

Ceci importera le composant modal à la place de la totalité de ng2-bootstrap

Suivez ensuite la réponse de @ FreeBird72

Ajouter ce 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",
    ...
  }
  ...
}

Ensuite vous pouvez npm run tsc sur le développement et npm run prod sur le serveur de production Supprimez également System.import(.... de votre index.html et remplacez-le par <script src="/dist/bundle.min.js"></script>

1
lthh89vt

Si vous souhaitez utiliser SystemJS, vous pouvez regrouper votre application avec [~ # ~] jspm [~ # ~] . J'ai eu beaucoup de succès avec cela jusqu'à présent, en utilisant bundle-sfx commande pour créer des fichiers JS uniques pour Angular 2 applications.

Il y a quelques informations utiles dans cet Gist , et il y a un projet pilote .

0
Harry

L’interface de ligne de commande Angular) prend désormais en charge le regroupement (avec arborescence pour supprimer le code inutilisé des importations), la minification et la compilation de modèles à l’avance, qui non seulement minimise énormément le demande, mais rend également le paquet très petit.Il utilise WebPack dessous.

Il est incroyablement facile de créer des versions de production avec:

ng build --prod --aot

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

0
Harry

J'utilise la version AG2 RC Lorsque j'utilisais la solution de MrCroft avec systemjs-builder, je rencontrais beaucoup de problèmes tels que: erreur TS2304: impossible de trouver le nom 'Map' erreur TS2304: impossible de trouver le nom 'Promise' ...

Après plusieurs essais, j'ai ajouté: ///<reference path="../../typings/index.d.ts" /> dans mon boot.ts et maintenant mon fichier bundle a été compilé.

0
Wong Kim Wah