Angular2 demasiadas solicitudes de archivo al cargar


Estoy haciendo un sitio web usando Angular2 y estoy teniendo lo que supongo que es un problema. En la primera carga de mi página angular, SystemJS está haciendo más de 500 cientos de solicitudes para recuperar cada archivo Angular2 en el directorio angular2/src. En total, la primera carga descarga más de 4MB y tarda más de 14 segundos en comenzar.

Mi index.html hace los siguientes scripts incluye:

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

Y mi código de inicialización SystemJS se ve así:

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

Mi carpeta pública tiene lo siguiente estructura:

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

Un par de capturas de pantalla de algunos de los archivos js que se están solicitando: introduzca la descripción de la imagen aquí

introduzca la descripción de la imagen aquí

¿Hay alguna manera de evitar todas esas peticiones?

Author: Michael, 2016-02-09

9 answers

Tuve exactamente el mismo problema, en realidad estaba buscando en este post una respuesta. Esto es lo que hice para resolver el problema.

  1. Modifica tu proyecto para usar webpack. Sigue este breve tutorial: Angular2 QuickStart SystemJS A Webpack
  2. Este método le dará un solo archivo javascript, sin embargo, es bastante grande (mi archivo de proyecto tenía más de 5 MB) y necesita ser minificado. Para ello he instalado webpack globaly: npm install webpack -g. Una vez instalado, ejecute webpack -p desde la raíz de sus aplicaciones directorio. Esto redujo el tamaño de mi archivo a unos 700KB

Desde 20 segundos y 350 peticiones hasta 3 segundos y 7 peticiones.

 47
Author: David Herod,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-02-12 00:45:26

Veo que ya tienes una respuesta, que es buena, por supuesto. PERO para aquellos que quieran usar systemjs (como yo también lo hago), y no ir a webpack, todavía puede agrupar los archivos. Sin embargo, implica el uso de otra herramienta también (yo uso gulp). Tan... tendrías la siguiente configuración de systemjs (no en el html, sino en un archivo separado-llamémoslo " 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);

Entonces, en tu gulpfile.js construiría un paquete como este (usando la información de system.config.js y tsconfig.json archivos):

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']));

Por lo tanto, al ejecutar "gulp build", obtendrá el "bundle.js " archivo con todo lo que necesita. Claro, también necesita algunos paquetes más para que esta tarea de paquete de gulp funcione:

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

También, asegúrese de que en su tsconfig.json que tienes "module":"commonjs". Aquí está mi tsconfig.json que se usa en mi tarea '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"
    ]
}

Entonces, en tu archivo html solo necesitas incluir esto:

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

Y eso es todo... Recibí 600 peticiones, 4mb en unos 5 segundos... a 20 solicitudes, 1.4 mb en 1.6 segundos (máquina de desarrollo local). Pero estas 20 solicitudes ~1.4 mb en 1.6 segundos también incluyen algunos otros js y css que el tema de administración vino con más algunas plantillas html que se requieren en la primera carga, prefiero usar plantillas externas - templateUrl: ", en lugar de las en línea, escritas en mi componente.archivo ts. Claro, para una aplicación que tendría millones de usuarios, esto todavía no sería suficiente. También la representación del lado del servidor para la carga inicial y el sistema de caché debe ser implementado, en realidad me las arreglé para hacer eso con angular universal, pero en Angular2 beta (tomó alrededor de 200-240 milisegundos para cargar el renderizado inicial de la misma aplicación de administración que anteriormente toma 1.6 segundos-Lo sé: WOW!). Ahora es incompatible desde que Angular2 RC salió, pero estoy seguro de que los chicos que hacen universal lo pondrán al día pronto, especialmente desde que ng-conf se acerca. Además, también están planificando para hacer Angular Universal para PHP, ASP y algunos otros , ahora mismo es sólo para Nodejs.

Editar: En realidad, acabo de descubrir que en NG-CONF dijeron que Angular Universal ya soporta ASP (pero no soporta Angular2 > beta.15 :)) ... pero vamos a darles un poco de tiempo, RC acaba de salir hace unos días

 33
Author: MrCroft,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-20 22:06:21

Creo que tu pregunta está relacionada con esta:

Para tener algo listo para la producción (y acelerarlo), debe empaquetarlo.

Me refiero a transpilar todos los archivos en JavaScript y concatarlos de la misma manera que Angular2 lo hace, por ejemplo. De esta manera tendrá varios módulos contenidos en un solo archivo JS. De esta manera se reducirá la número de llamadas HTTP para cargar el código de la aplicación en el navegador.

 3
Author: Thierry Templier,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:54:46

Encontré una solución simple, usando browserify & uglifyjs en el repositorio angular2-seed de mgechev

Aquí está mi versión:

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. Construye tu proyecto.
  2. Ejecutar: npm ejecutar build_prod Creará un paquete.js & bundle.min.js bajo el directorio public\dist.
  3. Edita tu archivo index.html : En lugar de ejecutar System.import('YourMainModule')... , añadir <script src="/dist/bundle.min.js"></script>
 3
Author: FreeBird72,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-03 08:14:42

En la primera carga de mi página angular, systemjs está haciendo más de 500 cientos de solicitudes para recuperar cada archivo angular2 en el directorio angular2/src. En total, la primera carga descarga más de 4mb y tarda más de 14 segundos en comenzar.

Los flujos de trabajo de SystemJS son bastante nuevos y no tienen suficiente investigación para una mejor implementación.

Sugieren volver a commonjs + webpack. Mas : https://basarat.gitbooks.io/typescript/content/docs/quick/browser.html

Aquí hay un ejemplo: https://github.com/AngularClass/angular2-webpack-starter

 1
Author: basarat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-02-08 22:34:50

@FreeBird72 Tu respuesta es impresionante.

Si desea utilizar SystemJS para el desarrollo y acelerar el servidor de producción como lo hago yo. Mira esto.

NOTA: Solo importe los componentes que utilice, NO importe desde todo el paquete.

Eg: Si desea utilizar Modal de ng2-bootstrap.

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

En lugar de:

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

Esto importará el componente modal en lugar de todo ng2-bootstrap

Luego sigue la respuesta de @FreeBird72

Agregue este paquete.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",
    ...
  }
  ...
}

Entonces puede npm run tsc en el desarrollo y npm run prod en el servidor de producción También elimine System.import(.... de su índice.html y cambiarlo a <script src="/dist/bundle.min.js"></script>

 1
Author: lthh89vt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-27 23:04:11

Si desea seguir con SystemJS, puede agrupar su aplicación con JSPM. He tenido un buen éxito con esto hasta ahora, utilizando el comando bundle-sfx de JSPM para hacer archivos JS individuales para aplicaciones Angular 2.

Hay cierta información útil en este Gist, y hay un proyecto semilla .

 0
Author: Harry,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-30 16:27:53

Estoy usando la versión AG2 RC Mientras usaba la solución de MrCroft con systemjs-builder, estaba golpeando muchos problemas como: error TS2304: No se puede encontrar el nombre 'Map' error TS2304: No se puede encontrar el nombre 'Promise'...

Después de muchos intentos, agregué: ///<reference path="../../typings/index.d.ts" /> en mi bota.ts y ahora tengo mi archivo bundle compilado.

 0
Author: Wong Kim Wah,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-31 06:25:54

La interfaz de línea de comandos Angular ahora admite la agrupación (con agitación de árbol para eliminar el código no utilizado de las importaciones), la minificación y la compilación de plantillas por adelantado, lo que no solo minimiza enormemente el número de solicitudes realizadas, sino que también hace que el paquete sea muy pequeño. Utiliza WebPack debajo.

Es increíblemente fácil hacer compilaciones de producción con él:

ng build --prod --aot

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

 0
Author: Harry,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-23 02:37:06