Comment diminuer la taille du bundle prod?

135

J'ai une application simple, initialisée par angular-cli.

Il affiche quelques pages relatives à 3 itinéraires. J'ai 3 composants. Sur l'une de cette page, j'utilise lodashet des modules HTTP Angular 2 pour obtenir des données (en utilisant RxJS Observable, mapet subscribe). J'affiche ces éléments en utilisant un simple *ngFor.

Mais, malgré le fait que mon application soit vraiment simple, j'obtiens un énorme package (à mon avis) et des cartes. Je ne parle pas des versions gzip mais de la taille avant gzipping. Cette question n'est qu'une enquête de recommandations générales.

Quelques résultats de tests:

ng build

Hash: 8efac7d6208adb8641c1 Durée: bloc de 10129 ms {0} main.bundle.js, main.bundle.map (main) 18,7 Ko {3} [initial] [rendu]

bloc {1} styles.bundle.css, styles.bundle.map, styles.bundle.map (styles) 155 Ko {4} [initial] [rendu]

chunk {2} scripts.bundle.js, scripts.bundle.map (scripts) 128 Ko {4} [initial] [rendu]

bloc {3} vendor.bundle.js, vendor.bundle.map (fournisseur) 3,96 Mo [initial] [rendu]

bloc {4} inline.bundle.js, inline.bundle.map (inline) 0 octets [entrée] [rendu]

Attendez: un package de 10 Mo pour une application aussi simple?

ng build --prod

Hash: 09a5f095e33b2980e7cc Durée: 23455 ms bloc {0} main.6273b0f04a07a1c2ad6c.bundle.js, main.6273b0f04a07a1c2ad6c.bundle.map (main) 18,3 ko {3} [initial] [rendu]

bloc {1} styles.bfdaa4d8a4eb2d0cb019.bundle.css, styles.bfdaa4d8a4eb2d0cb019.bundle.map, styles.bfdaa4d8a4eb2d0cb019.bundle.map (styles) 154 Ko {4} [initial] [rendu]

bloc {2} scripts.c5b720a078e5464ec211.bundle.js, scripts.c5b720a078e5464ec211.bundle.map (scripts) 128 Ko {4} [initial] [rendu]

bloc {3} vendor.07af2467307e17d85438.bundle.js, vendor.07af2467307e17d85438.bundle.map (fournisseur) 3,96 Mo [initial] [rendu]

bloc {4} inline.a345391d459797f81820.bundle.js, inline.a345391d459797f81820.bundle.map (inline) 0 octets [entrée] [rendu]

Attendez à nouveau: une telle taille de bundle de fournisseur similaire pour prod?

ng build --prod --aot

Hash: 517e4425ff872bbe3e5b Durée: bloc de 22856 ms {0} main.95eadabace554e3c2b43.bundle.js, main.95eadabace554e3c2b43.bundle.map (main) 130 ko {3} [initial] [rendu]

bloc {1} styles.e53a388ae1dd2b7f5434.bundle.css, styles.e53a388ae1dd2b7f5434.bundle.map, styles.e53a388ae1dd2b7f5434.bundle.map (styles) 154 Ko {4} [initial] [rendu]

bloc {2} scripts.e5c2c90547f3168a7564.bundle.js, scripts.e5c2c90547f3168a7564.bundle.map (scripts) 128 Ko {4} [initial] [rendu]

bloc {3} vendor.41a6c1f57136df286f14.bundle.js, vendor.41a6c1f57136df286f14.bundle.map (fournisseur) 2,75 Mo [initial] [rendu]

bloc {4} inline.97c0403c57a46c6a7920.bundle.js, inline.97c0403c57a46c6a7920.bundle.map (inline) 0 octets [entrée] [rendu]

ng build --aot

Hash: 040cc91df4df5ffc3c3f Durée: bloc de 11011 ms {0} main.bundle.js, main.bundle.map (main) 130 Ko {3} [initial] [rendu]

bloc {1} styles.bundle.css, styles.bundle.map, styles.bundle.map (styles) 155 Ko {4} [initial] [rendu]

chunk {2} scripts.bundle.js, scripts.bundle.map (scripts) 128 Ko {4} [initial] [rendu]

bloc {3} vendor.bundle.js, vendor.bundle.map (fournisseur) 2,75 Mo [initial] [rendu]

bloc {4} inline.bundle.js, inline.bundle.map (inline) 0 octets [entrée] [rendu]

Donc quelques questions pour déployer mon application sur prod:

  • Pourquoi les offres groupées des fournisseurs sont-elles si importantes?
  • L'arbre secoue-t-il correctement angular-cli?
  • Comment améliorer cette taille de bundle?
  • Les fichiers .map sont-ils requis?
  • Les fonctionnalités de test sont-elles incluses dans les bundles? Je n'en ai pas besoin en prod.
  • Question générique: quels sont les outils recommandés à emballer pour produire? Peut-être que angular-cli(utiliser Webpack en arrière-plan) n'est pas la meilleure option? Pouvons-nous faire mieux?

J'ai recherché de nombreuses discussions sur Stack Overflow, mais je n'ai trouvé aucune question générique.

BlackTrouGalaxie
la source
Pour en savoir plus sur l'optimisation de l'application angular 2, consultez ceci: github.com/mgechev/angular-performance-checklist#introduction
Timathon
1
Mais je ne pense pas que nous devrions nous soucier autant, angular-cli évoluera et les choses seront faites de mieux en mieux. Si vous avez besoin d'une fonctionnalité que angular-cli n'a pas, soumettez simplement un problème dans leur dépôt
Timathon
Bien que je pense que @Timathon a raison à certains égards, si quelqu'un essaie de déployer Angular2 en production, il devrait se soucier de la taille des bundles, car cela affecte directement les performances de l'application. La liste de contrôle des performances angulaires est une excellente ressource pour voir ce qui peut être amélioré. l'équipe angulaire travaille à réduire la taille des lots. Excité de voir où ça va!
Jack Clancy

Réponses:

73

Mise à jour février 2020

Étant donné que cette réponse a eu beaucoup de succès, j'ai pensé qu'il serait préférable de la mettre à jour avec de nouvelles optimisations angulaires:

  1. Comme l'a dit un autre répondant, ng build --prod --build-optimizerc'est une bonne option pour les personnes utilisant moins d'Angular v5. Pour les versions plus récentes, cela se fait par défaut avecng build --prod
  2. Une autre option consiste à utiliser la segmentation du module / le chargement paresseux pour mieux diviser votre application en petits morceaux
  3. Le moteur de rendu Ivy est livré par défaut dans Angular 9, il offre de meilleures tailles de bundle
  4. Assurez-vous que vos départements tiers peuvent être secoués. Si vous n'utilisez pas encore Rxjs v6, vous devriez l'être.
  5. Si tout le reste échoue, utilisez un outil comme webpack-bundle-analyzer pour voir ce qui cause le gonflement de vos modules
  6. Vérifiez si vos fichiers sont gzippés

Certains prétendent que l'utilisation de la compilation AOT peut réduire la taille du bundle du fournisseur à 250 Ko. Cependant, dans l'exemple de BlackHoleGalaxy, il utilise la compilation AOT et se retrouve toujours avec une taille de bundle fournisseur de 2,75 Mo avec ng build --prod --aot, 10 fois plus grande que les 250 Ko supposés. Ce n'est pas hors de la norme pour les applications angular2, même si vous utilisez la v4.0. 2,75 Mo est encore trop volumineux pour quiconque se soucie vraiment des performances, en particulier sur un appareil mobile.

Vous pouvez faire plusieurs choses pour améliorer les performances de votre application:

1) AOT & Tree Shaking (angular-cli le fait hors de la boîte). Avec Angular 9, AOT est par défaut sur l'environnement prod et dev.

2) Utilisation du rendu côté serveur Angular Universal AKA (pas dans cli)

3) Web Workers (encore une fois, pas dans cli, mais une fonctionnalité très demandée)
voir: https://github.com/angular/angular-cli/issues/2305

4) Service Workers
voir: https://github.com/angular/angular-cli/issues/4006

Vous n'avez peut-être pas besoin de tous ces éléments dans une seule application, mais voici quelques-unes des options actuellement présentes pour optimiser les performances angulaires. Je crois / j'espère que Google est conscient des lacunes hors de la boîte en termes de performances et prévoit de les améliorer à l'avenir.

Voici une référence qui parle plus en détail de certains des concepts que j'ai mentionnés ci-dessus:

https://medium.com/@areai51/the-4-stages-of-perf-tuning-for-your-angular2-app-922ce5c1b294

Jack Clancy
la source
Mon projet minimal est de 384 Ko, voir github.com/JCornat/min-angular Je suis sûr qu'il existe un moyen facile de l'optimiser, mais il est proche de 250 Ko!
Jacques Cornat
2
@JacquesCornat a l'air bien! Mais votre application n'a qu'un seul composant. La question est de savoir comment gérer les tailles de bundle ou les applications plus volumineuses. Souvent, AOT ne réduit pas suffisamment la taille des lots et les utilisateurs sont obligés de chercher une autre façon d'optimiser. Je recommande vivement à tout le monde de consulter webpack-bundle-analyzer. Un moyen très utile / facile de voir ce qui cause le ballonnement
Jack Clancy
Malheureusement, des utilitaires tels que sw-precacherefusent de traiter les offres groupées des fournisseurs de plus de 2 Mo.
1
@JackClancy "La question est de savoir comment gérer les tailles de bundle ou les applications plus importantes". Non, sa question est "comment améliorer cette taille de bundle?" et il parle de son application minimale avec 3 composants. Quoi qu'il en soit, en parlant de gros bundles, en utilisant la configuration AngularClass / angular-starter, la même que dans mon repo, ma taille de bundle pour les grandes applications est passée de 8 Mo (4 Mo sans fichiers de carte) à 580 Ko.
Jacques Cornat
1
Merci, tu m'as sauvé. --prod a réduit la taille de l'application de 6 Mo à 1,2 Mo. Toujours pas parfait, mais acceptant car il est destiné à un usage de bureau uniquement.
Vyacheslav Tsivina
21

Utilisez dernière version cli angulaire et commande use build de --prod --build-optimiseur Il va certainement réduire la taille de construction pour env prod.

Voici ce que fait l'optimiseur de build sous le capot:

L'optimiseur de build a deux tâches principales. Tout d'abord, nous sommes en mesure de marquer des parties de votre application comme pures, ce qui améliore le tremblement de l'arbre fourni par les outils existants, en supprimant les parties supplémentaires de votre application qui ne sont pas nécessaires.

La deuxième chose que fait l'optimiseur de build est de supprimer les décorateurs angulaires du code d'exécution de votre application. Les décorateurs sont utilisés par le compilateur et ne sont pas nécessaires au moment de l'exécution et peuvent être supprimés. Chacun de ces travaux réduit la taille de vos bundles JavaScript et augmente la vitesse de démarrage de votre application pour vos utilisateurs.

Remarque : une mise à jour pour Angular 5 et plus, le ng build --prodprocessus prend automatiquement en charge le processus ci-dessus :)

Shubhendu Vaid
la source
1
En ce qui concerne angular 6 pour le moment, le fournisseur est toujours de 4 Mo pour installer uniquement angular / material et firebase
FindOutIslamNow
C'est un problème angulaire / matériel, même si j'ai fait face à cette erreur. Le tremblement d'arbre mal effectué est probablement la cause première. Avec le nouveau moteur de rendu IVY, cela serait probablement résolu.
Shubhendu Vaid
13

Lodash peut contribuer un morceau de code de bogue à votre bundle en fonction de la façon dont vous importez à partir de celui-ci. Par exemple:

// includes the entire package (very large)
import * as _ from 'lodash';

// depending on your buildchain, may still include the entire package
import { flatten } from 'lodash';

// imports only the code needed for `flatten`
import flatten from 'lodash-es/flatten'

Personnellement, je voulais toujours des empreintes plus petites de mes fonctions utilitaires. Par exemple, vous flattenpouvez contribuer jusqu'à 1.2Kvotre forfait, après minimisation. J'ai donc créé une collection de fonctions de lodash simplifiées. Ma mise en œuvre de flattencontribue autour 50 bytes. Vous pouvez le vérifier ici pour voir s'il fonctionne pour vous: https://github.com/simontonsoftware/micro-dash

Eric Simonton
la source
1
2 / J'ai essayé les astuces "loadash-es" du commentaire ci-dessus. Cela réduit la taille de mon bundle de 0,08 Mo.
Stefdelec
Ce n'est pas beaucoup! Avez-vous encore quelque chose d'important du lodash à l'ancienne? Vous n'obtiendrez aucune aide à moins que tout soit importé de la nouvelle manière.
Eric Simonton
Je pense que j'ai tout remplacé. La taille n'aurait pas changé autrement. J'ai donné un autre conseil ci-dessous (chose gzip) qui nous a vraiment aidés.
Stefdelec
Intéressant. À quelle part de votre forfait est / a contribué lodash? (Par exemple en utilisant source-map-explorer.)
Eric Simonton
11

Premièrement, les offres groupées des fournisseurs sont énormes simplement parce qu'Angular 2 repose sur de nombreuses bibliothèques. La taille minimale de l' application Angular 2 est d'environ 500 Ko (250 Ko dans certains cas, voir l'article du bas).
La secousse d'arbre est correctement utilisée par angular-cli.
Ne pas inclure les .mapfichiers, car utilisé uniquement pour le débogage. De plus, si vous utilisez un module de remplacement à chaud, supprimez-le pour alléger le fournisseur.

Pour emballer pour la production, j'utilise personnellement Webpack (et angular-cli en dépend aussi ), car vous pouvez vraiment configure everythingpour l'optimisation ou le débogage.
Si vous souhaitez l'utiliser Webpack, je conviens que c'est un peu délicat une première vue, mais voir les tutoriels sur le net, vous ne serez pas déçu.
Sinon, utilisez angular-cli, qui fait très bien le travail.

L'utilisation de la compilation anticipée est obligatoire pour optimiser les applications et réduire l'application Angular 2 à 250 Ko .

Voici un dépôt que j'ai créé ( github.com/JCornat/min-angular ) pour tester la taille minimale du bundle Angular, et j'obtiens 384 Ko . Je suis sûr qu'il existe un moyen simple de l'optimiser.

En parlant de grandes applications, en utilisant la configuration AngularClass / angular-starter , la même que dans le référentiel ci-dessus, la taille de mon bundle pour les grandes applications ( plus de 150 composants ) est passée de 8 Mo (4 Mo sans fichiers de carte) à 580 Ko .

Jacques Cornat
la source
Quelle est la configuration spécifique du démarreur angulaire qui aide à réduire la taille du bundle? Est-ce le webpack.config?
MartinJH
2
Oui, c'est la configuration du Webpack qui réduit la taille du bundle.
Jacques Cornat
Merci pour la clarification :)
MartinJH
8

La solution suivante suppose que vous diffusez votre dossier dist / à l'aide de nodejs. Veuillez utiliser le fichier app.js suivant au niveau racine

const express = require('express'),http = require('http'),path = require('path'),compression = require('compression');

const app = express();

app.use(express.static(path.join(__dirname, 'dist')));
app.use(compression()) //compressing dist folder 
app.get('*', (req, res) => {
  res.sendFile(path.join(__dirname, 'dist/index.html'));
})

const port = process.env.PORT || '4201';
app.set('port', port);

const server = http.createServer(app);
server.listen(port, () => console.log('Running at port ' + port))

Assurez-vous d'installer les dépendances;

npm install compression --save
npm install express --save;

Maintenant, construisez l'application

ng build --prod --build-optimizer

Si vous souhaitez compresser davantage la construction, par exemple réduire de 300 Ko (environ), suivez le processus ci-dessous;

Créez un dossier appelé vendorà l'intérieur du srcdossier et dans le dossier du fournisseur, créez un fichier rxjs.ts et collez-y le code ci-dessous;

export {Subject} from 'rxjs/Subject';
export {Observable} from 'rxjs/Observable';
export {Subscription} from 'rxjs/Subscription';

Et puis ajoutez le suivant dans le tsconfig.jsonfichier dans votre application angular-cli. Ensuite, dans le compilerOptions, ajoutez le json suivant;

"paths": {
      "rxjs": [
        "./vendor/rxjs.ts"
      ]
    }

Cela rendra la taille de votre build beaucoup trop petite. Dans mon projet, j'ai réduit la taille de 11 Mo à 1 Mo. J'espère que ça aide

Renil Babu
la source
5

Une chose que je souhaite partager est la façon dont les bibliothèques importées augmentent la taille du fichier dist. J'ai importé le package angular2-moment, alors que je pouvais faire tout le formatage de la date et de l'heure dont j'avais besoin en utilisant le DatePipe standard exporté depuis @ angular / common.

Avec Angular2-Moment "angular2-moment": "^1.6.0",

bloc {0} polyfills.036982dc15bb5fc67cb8.bundle.js (polyfills) 191 Ko {4} [initial] [rendu] bloc {1} main.e7496551a26816427b68.bundle.js (principal) 2,2 Mo {3} [initial] [rendu] bloc {2} styles.056656ed596d26ba0192.bundle.css (styles) 69 octets {4} [initial] [rendu] bloc {3} fournisseur.62c2cfe0ca794a5006d1.bundle.js (fournisseur) 3,84 Mo [initial] [rendu] bloc {4 } inline.0b9c3de53405d705e757.bundle.js (en ligne) 0 octets [entrée] [rendu]

Après avoir supprimé Angular2-moment et utilisé DatePipe à la place

bloc {0} polyfills.036982dc15bb5fc67cb8.bundle.js (polyfills) 191 Ko {4} [initial] [rendu] bloc {1} main.f2b62721788695a4655c.bundle.js (principal) 2,2 Mo {3} [initial] [rendu] bloc {2} styles.056656ed596d26ba0192.bundle.css (styles) 69 octets {4} [initial] [rendu] bloc {3} vendor.e1de06303258c58c9d01.bundle.js (fournisseur) 3,35 Mo [initial] [rendu] bloc {4 } inline.3ae24861b3637391ba70.bundle.js (en ligne) 0 octets [entrée] [rendu]

Notez que l'offre groupée du fournisseur a réduit d'un demi-mégaoctet!

Le fait est que cela vaut la peine de vérifier ce que les packages standard angulaires peuvent faire même si vous êtes déjà familier avec une bibliothèque externe.

kwalski
la source
1

Si vous avez exécuté ng build --prod, vous ne devriez pas avoir de vendorfichiers du tout.

Si je cours juste ng build- j'obtiens ces fichiers:

entrez la description de l'image ici

La taille totale du dossier est d'environ 14 Mo. Waat! :RÉ

Mais si je cours ng build --prod, j'obtiens ces fichiers:

entrez la description de l'image ici

La taille totale du dossier est de 584 Ko.

Un seul et même code. J'ai activé Ivy dans les deux cas. Angular est 8.2.13.

Alors - je suppose que vous n'avez pas ajouté --prodà votre commande de construction?

pesho hristov
la source
1

Si vous utilisez Angular 8+ et que vous souhaitez réduire la taille du bundle, vous pouvez utiliser Ivy. Ivy est le moteur de vue par défaut dans Angular 9 Accédez simplement à src / tsconfig.app.json et ajoutez le paramètre angularCompilerOptions, par exemple:

{
  "extends": ...,
  "compilerOptions":...,
  "exclude": ...,

/* add this one */ 
  "angularCompilerOptions": {
    "enableIvy": true
  }
}
Rachel
la source
1

Cela a réduit la taille dans mon cas:

ng build --prod --build-optimizer --optimization.

Pour Angular 5+ ng-build --prod le fait par défaut. La taille après l'exécution de cette commande est passée de 1,7 Mo à 1,2 Mo, mais pas assez pour mon objectif de production.

Je travaille sur la plate-forme de messagerie Facebook et les applications de messagerie doivent être inférieures à 1 Mo pour fonctionner sur la plate-forme de messagerie. J'ai essayé de trouver une solution pour secouer efficacement les arbres, mais toujours pas de chance.

Mahesh Sharma
la source
1

Il fonctionne à 100% ng build --prod --aot --build-optimizer --vendor-chunk = true

AJAY AVHAD
la source
0

J'ai une application de démarrage angulaire 5 + spring (application.properties 1.3+) avec l'aide de la compression (lien ci-dessous) a pu réduire la taille de la taille de main.bundle.ts de 2,7 Mo à 530 Ko.

De plus, par défaut, --aot et --build-optimizer sont activés avec le mode --prod, vous n'avez pas besoin de les spécifier séparément.

https://stackoverflow.com/a/28216983/9491345

sah1
la source
0

Vérifiez que vous avez une configuration nommée "production" pour ng build --prod, car c'est un raccourci pour ng build --configuration = production Aucune réponse n'a résolu mon problème, car le problème se trouvait juste devant l'écran. Je pense que cela pourrait être assez courant ... J'ai internationalisé l'application avec i18n en renommant toutes les configurations en par exemple production-en. Ensuite, j'ai construit avec ng build --prod en supposant que l'optimisation par défaut est utilisée et devrait être proche de l'optimum, mais en fait, juste ng build a été exécuté, ce qui donne un bundle de 7 Mo au lieu de 250 Ko.

antidote
la source
0

Tiré de la documentation angulaire v9 ( https://angular.io/guide/workspace-config#alternate-build-configurations ):

Par défaut, une configuration de production est définie et la commande ng build a l'option --prod qui se construit en utilisant cette configuration. La configuration de production définit des valeurs par défaut qui optimisent l'application de plusieurs manières, telles que le regroupement de fichiers , la minimisation des espaces blancs excédentaires , la suppression des commentaires et du code mort et la réécriture du code pour utiliser des noms courts et cryptiques ( "minification" ).

De plus, vous pouvez compresser tous vos déploiables avec @ angular-builders / custom-webpack: constructeur de navigateur où votre webpack.config.js personnalisé ressemble à ça:

module.exports = {
  entry: {
  },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].[hash].js'
  },
  plugins: [
    new CompressionPlugin({
      deleteOriginalAssets: true,
    })
  ]
};

Ensuite, vous devrez configurer votre serveur Web pour servir du contenu compressé, par exemple avec nginx que vous devez ajouter à votre nginx.conf:

server {
    gzip on;
    gzip_types      text/plain application/xml;
    gzip_proxied    no-cache no-store private expired auth;
    gzip_min_length 1000;
    ...
}

Dans mon cas, le dossier dist est passé de 25 à 5 Mo après avoir simplement utilisé le --prod dans ng build, puis a encore diminué à 1,5 Mo après la compression.

Bat0u89
la source