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:
Y a-t-il un moyen d'éviter toutes ces demandes?
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.
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.
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
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.
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"
}
}
index.html
: Au lieu d’exécuter System.import('YourMainModule')... ,
add <script src="/dist/bundle.min.js"></script>
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
@ 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>
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 .
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
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é.