Jak zmniejszyć rozmiar pakietu prod?

143

Mam prostą aplikację, zainicjowaną przez angular-cli.

Wyświetla niektóre strony odnoszące się do 3 tras. Mam 3 komponenty. Na jednym z tej strony używam lodashi kątowa 2 moduły HTTP, aby uzyskać pewne dane (przy użyciu RxJS Observables, mapa subscribe). Wyświetlam te elementy za pomocą prostego pliku *ngFor.

Ale pomimo tego, że moja aplikacja jest naprawdę prosta, otrzymuję ogromny (moim zdaniem) pakiet i mapy. Nie mówię jednak o wersjach programu gzip, ale rozmiar przed zgzowaniem. To pytanie jest tylko pytaniem o ogólne zalecenia.

Niektóre wyniki testów:

ng build

Hash: 8efac7d6208adb8641c1 Czas: fragment 10129 ms {0} main.bundle.js, main.bundle.map (main) 18,7 kB {3} [początkowe] [wyrenderowane]

fragment {1} styles.bundle.css, styles.bundle.map, styles.bundle.map (styles) 155 kB {4} [początkowe] [renderowane]

fragment {2} scripts.bundle.js, scripts.bundle.map (skrypty) 128 kB {4} [początkowe] [wyrenderowane]

fragment {3} vendor.bundle.js, vendor.bundle.map (sprzedawca) 3,96 MB [początkowe] [wyrenderowane]

fragment {4} inline.bundle.js, inline.bundle.map (inline) 0 bajtów [wpis] [wyrenderowany]

Czekaj: pakiet 10Mb dostawcy dla tak prostej aplikacji?

ng build --prod

Hash: 09a5f095e33b2980e7cc Czas: fragment 23455ms {0} main.6273b0f04a07a1c2ad6c.bundle.js, main.6273b0f04a07a1c2ad6c.bundle.map (główny) 18,3 kB {3} [początkowe] [wyrenderowane]

chunk {1} styles.bfdaa4d8a4eb2d0cb019.bundle.css, styles.bfdaa4d8a4eb2d0cb019.bundle.map, styles.bfdaa4d8a4eb2d0cb019.bundle.map (styles) 154 kB {4} [początkowe] [wyrenderowane]

fragment {2} scripts.c5b720a078e5464ec211.bundle.js, scripts.c5b720a078e5464ec211.bundle.map (skrypty) 128 kB {4} [początkowe] [wyrenderowane]

fragment {3} vendor.07af2467307e17d85438.bundle.js, vendor.07af2467307e17d85438.bundle.map (dostawca) 3,96 MB [początkowe] [wyrenderowane]

fragment {4} inline.a345391d459797f81820.bundle.js, inline.a345391d459797f81820.bundle.map (inline) 0 bajtów [wpis] [wyrenderowany]

Poczekaj jeszcze raz: taki podobny rozmiar pakietu dostawcy dla prod?

ng build --prod --aot

Hash: 517e4425ff872bbe3e5b Czas: fragment 22856 ms {0} main.95eadabace554e3c2b43.bundle.js, main.95eadabace554e3c2b43.bundle.map (główny) 130 kB {3} [początkowe] [wyrenderowane]

chunk {1} styles.e53a388ae1dd2b7f5434.bundle.css, styles.e53a388ae1dd2b7f5434.bundle.map, styles.e53a388ae1dd2b7f5434.bundle.map (styles) 154 kB {4} [początkowe] [renderowane]

fragment {2} scripts.e5c2c90547f3168a7564.bundle.js, scripts.e5c2c90547f3168a7564.bundle.map (skrypty) 128 kB {4} [początkowe] [wyrenderowane]

fragment {3} vendor.41a6c1f57136df286f14.bundle.js, vendor.41a6c1f57136df286f14.bundle.map (sprzedawca) 2,75 MB [początkowe] [wyrenderowane]

fragment {4} inline.97c0403c57a46c6a7920.bundle.js, inline.97c0403c57a46c6a7920.bundle.map (inline) 0 bajtów [wpis] [wyrenderowany]

ng build --aot

Hash: 040cc91df4df5ffc3c3f Czas: fragment 11011 ms {0} main.bundle.js, main.bundle.map (main) 130 kB {3} [początkowe] [wyrenderowane]

fragment {1} styles.bundle.css, styles.bundle.map, styles.bundle.map (styles) 155 kB {4} [początkowe] [renderowane]

fragment {2} scripts.bundle.js, scripts.bundle.map (skrypty) 128 kB {4} [początkowe] [wyrenderowane]

fragment {3} vendor.bundle.js, vendor.bundle.map (sprzedawca) 2,75 MB [początkowe] [wyrenderowane]

fragment {4} inline.bundle.js, inline.bundle.map (inline) 0 bajtów [wpis] [wyrenderowany]

Oto kilka pytań dotyczących wdrażania mojej aplikacji w wersji prod:

  • Dlaczego pakiety dostawców są tak ogromne?
  • Czy trzęsące się drzewo jest właściwie używane przez angular-cli?
  • Jak zwiększyć rozmiar tego pakietu?
  • Czy pliki .map są wymagane?
  • Czy funkcje testowania są zawarte w pakietach? Nie potrzebuję ich w prod.
  • Ogólne pytanie: jakie są zalecane narzędzia do pakowania? Może angular-cli(używanie Webpacka w tle) nie jest najlepszą opcją? Czy możemy zrobić lepiej?

Przeszukałem wiele dyskusji na temat przepełnienia stosu, ale nie znalazłem żadnego ogólnego pytania.

BlackHoleGalaxy
źródło
Aby dowiedzieć się więcej o optymalizacji aplikacji Angular 2, sprawdź to: github.com/mgechev/angular-performance-checklist#introduction
Timathon,
1
Ale myślę, że nie powinno nas to aż tak bardzo przejmować, angular-cli będzie ewoluować i sprawy będą się układać coraz lepiej. Jeśli potrzebujesz jakiejś funkcji, której nie ma angular
Timathon
Chociaż uważam, że @Timathon ma w pewnym sensie rację, jeśli ktoś próbuje wdrożyć Angular2 w środowisku produkcyjnym, powinien dbać o rozmiary pakietów, ponieważ ma to bezpośredni wpływ na wydajność aplikacji. Kątowa lista kontrolna wydajności to świetne źródło informacji, które można poprawić. zespół kątowy pracuje nad zmniejszeniem rozmiarów wiązek. Podekscytowany, aby zobaczyć, dokąd to zmierza!
Jack Clancy,

Odpowiedzi:

76

Aktualizacja luty 2020

Ponieważ ta odpowiedź była bardzo popularna, pomyślałem, że najlepiej będzie zaktualizować ją o nowsze optymalizacje Angular:

  1. Jak powiedział inny respondent, ng build --prod --build-optimizerjest to dobra opcja dla osób używających mniej niż Angular v5. W przypadku nowszych wersji jest to wykonywane domyślnie zng build --prod
  2. Inną opcją jest użycie fragmentacji modułów / leniwego ładowania, aby lepiej podzielić aplikację na mniejsze części
  3. Silnik renderujący Ivy jest domyślnie dostępny w Angular 9, oferuje lepsze rozmiary pakietów
  4. Upewnij się, że twoje depozyty stron trzecich są wstrząsane drzewem. Jeśli jeszcze nie używasz Rxjs v6, powinieneś.
  5. Jeśli wszystko inne zawiedzie, użyj narzędzia takiego jak analizator pakietów webpack, aby zobaczyć, co powoduje wzdęcia w twoich modułach
  6. Sprawdź, czy pliki są spakowane gzipem

Niektórzy twierdzą, że użycie kompilacji AOT może zmniejszyć rozmiar pakietu dostawcy do 250kb. Jednak w przykładzie BlackHoleGalaxy używa kompilacji AOT i nadal pozostaje z pakietem dostawcy o wielkości 2,75 MB z ng build --prod --aot10 razy większym niż przypuszczalne 250 kb. Nie jest to niezgodne z normą dla aplikacji angular2, nawet jeśli używasz wersji 4.0. 2,75 MB to wciąż za dużo dla każdego, kto naprawdę dba o wydajność, zwłaszcza na urządzeniu mobilnym.

Jest kilka rzeczy, które możesz zrobić, aby poprawić wydajność swojej aplikacji:

1) AOT i Tree Shaking (angular-cli robi to po wyjęciu z pudełka). W Angular 9 AOT jest domyślnie dostępny w środowisku prod i dev.

2) Korzystanie z renderowania po stronie serwera Angular Universal AKA (nie w CLI)

3) Web Workers (znowu nie w CLI, ale bardzo pożądana funkcja)
patrz: https://github.com/angular/angular-cli/issues/2305

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

Możesz nie potrzebować ich wszystkich w jednej aplikacji, ale są to niektóre z obecnie dostępnych opcji optymalizacji wydajności Angular. Wierzę / mam nadzieję, że Google zdaje sobie sprawę z nieoczekiwanych niedociągnięć w zakresie wydajności i planuje poprawić to w przyszłości.

Oto odniesienie, które mówi bardziej szczegółowo o niektórych koncepcjach, o których wspomniałem powyżej:

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

Jack Clancy
źródło
Mój minimalny projekt to 384kB, patrz github.com/JCornat/min-angular. Jestem pewien, że jest łatwy sposób na jego optymalizację, ale jest blisko 250kB!
Jacques Cornat
2
@JacquesCornat wygląda dobrze! Ale Twoja aplikacja ma tylko jeden komponent. Pytanie brzmi, jak zarządzać rozmiarami pakietów lub większymi aplikacjami. Często AOT nie zmniejsza wystarczająco rozmiarów pakietów, a ludzie są zmuszeni szukać innych sposobów optymalizacji. Gorąco polecam wszystkim wypróbowanie analizatora pakietów webpack. Bardzo pomocny / łatwy sposób, aby zobaczyć, co powoduje wzdęcia
Jack Clancy
Niestety, narzędzia takie jak sw-precacheodmawiają obsługi pakietów dostawców większych niż 2 MB.
1
@JackClancy „Pytanie brzmi, jak zarządzać rozmiarami pakietów lub większymi aplikacjami”. Żadne jego pytanie nie brzmi "jak zwiększyć rozmiar tego pakietu?" i mówi o swojej minimalnej aplikacji z 3 komponentami. W każdym razie, mówiąc o dużych pakietach, używając konfiguracji AngularClass / angular-starter, takiej samej jak w moim repozytorium, rozmiar mojego pakietu dla dużych aplikacji wzrósł z 8 MB (4 MB bez plików map) do 580kB.
Jacques Cornat,
1
Dzięki, uratowałeś mnie. --prod zmniejszył rozmiar aplikacji z 6 MB do 1,2 MB. Nadal nie jest doskonały, ale akceptuje, ponieważ jest przeznaczony tylko do użytku na komputerze.
Wiaczesław Ciwina
22

Użyj najnowszej wersji kątowej CLI i użyj polecenia ng build --prod --build-optimizer Zdecydowanie zmniejszy to rozmiar kompilacji dla prod env.

Oto, co robi optymalizator kompilacji pod maską:

Optymalizator kompilacji ma dwa główne zadania. Po pierwsze, jesteśmy w stanie oznaczyć części aplikacji jako czyste, co poprawia potrząsanie drzewem zapewniane przez istniejące narzędzia, usuwając dodatkowe części aplikacji, które nie są potrzebne.

Drugą rzeczą, którą robi optymalizator kompilacji, jest usunięcie dekoratorów Angular z kodu uruchomieniowego aplikacji. Dekoratory są używane przez kompilator i nie są potrzebne w czasie wykonywania i można je usunąć. Każde z tych zadań zmniejsza rozmiar pakietów JavaScript i zwiększa szybkość uruchamiania aplikacji dla użytkowników.

Uwaga : jedna aktualizacja dla Angular 5 i ng build --prodnowszych , automatycznie zajmie się powyższym procesem :)

Shubhendu Vaid
źródło
1
Jeśli chodzi o kąt 6 w tej chwili, sprzedawca ma nadal 4 MB za instalację tylko kątownika / materiału i
bazy Firebase
To jest problem z kątownikiem / materiałem, nawet ja napotkałem ten błąd. Prawdopodobnie przyczyną jest nieprawidłowe potrząsanie drzewem. Z nowym silnikiem renderującym IVY prawdopodobnie zostałoby to rozwiązane.
Shubhendu Vaid
14

Lodash może dodać fragment kodu błędu do twojego pakietu, w zależności od tego, jak z niego importujesz. Na przykład:

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

Osobiście nadal chciałem mieć mniejsze ślady z moich funkcji użytkowych. Np. flattenMoże przyczynić się 1.2Kdo Twojego pakietu po zminimalizowaniu. Zbudowałem więc zbiór uproszczonych funkcji lodash. Moja realizacja flattenprzyczynia się dookoła 50 bytes. Możesz to sprawdzić tutaj, aby sprawdzić, czy działa dla Ciebie: https://github.com/simontonsoftware/micro-dash

Eric Simonton
źródło
1
2 / Wypróbowałem wskazówki "loadash-es" z komentarza powyżej. Zmniejsza rozmiar pakietu o 0,08 MB.
Stefdelec
To nie jest dużo! Czy nadal masz coś jeszcze, co przywozi lody w starym stylu? Nie uzyskasz żadnej pomocy, chyba że wszystko zostanie zaimportowane w nowy sposób.
Eric Simonton
Chyba wszystko wymieniłem. W przeciwnym razie rozmiar nie zmieniłby się. Podałem kolejną wskazówkę poniżej (rzecz gzip), która naprawdę nam pomogła.
Stefdelec
Ciekawy. Do jakiej części Twojego pakietu przyczynia się / była lodash? (Np source-map-explorer. Używając .)
Eric Simonton
Dzięki tej zmianie importu rozmiar naszego rozpakowanego pakietu zmniejszył się z 1,0 MB do 663 kB (213,4 kB -> 126 kB w opakowaniu). Musieliśmy aktualizować każdy import w całej aplikacji, ale nie było to trudne ani czasochłonne.
Mychal Hackman
11

Po pierwsze, pakiety dostawców są ogromne po prostu dlatego, że Angular 2 opiera się na wielu bibliotekach. Minimalny rozmiar aplikacji Angular 2 to około 500 KB (w niektórych przypadkach 250 KB, patrz dolny wpis).
Potrząsanie drzewami jest prawidłowo używane przez angular-cli.
Czy nie zawierają .mapplików, ponieważ używane tylko do debugowania. Ponadto, jeśli używasz gorącego modułu zastępczego, usuń go, aby odciążyć dostawcę.

Do pakowania do produkcji osobiście używam Webpacka (i angular -cli też na nim polega ), ponieważ naprawdę można configure everythingoptymalizować lub debugować.
Jeśli chcesz skorzystać Webpack, zgadzam się, że pierwszy widok jest nieco trudny, ale zobacz tutoriale w sieci, nie będziesz rozczarowany.
W przeciwnym razie użyj angular-cli, które wykonają zadanie naprawdę dobrze.

Korzystanie z kompilacji z wyprzedzeniem jest obowiązkowe, aby zoptymalizować aplikacje i zmniejszyć aplikację Angular 2 do 250 KB .

Oto repozytorium, które utworzyłem ( github.com/JCornat/min-angular ), aby przetestować minimalny rozmiar pakietu Angulara i otrzymałem 384kB . Jestem pewien, że istnieje łatwy sposób na jego optymalizację.

Mówiąc o dużych aplikacjach, używając konfiguracji AngularClass / angular-starter , takiej samej jak w powyższym repozytorium, rozmiar mojego pakietu dla dużych aplikacji ( ponad 150 komponentów ) wzrósł z 8 MB (4 MB bez plików map) do 580 kB .

Jacques Cornat
źródło
Jaka konkretna konfiguracja Angular-Starter pomaga zmniejszyć rozmiar pakietu? Czy to plik webpack.config?
MartinJH
2
Tak, to konfiguracja pakietu internetowego zmniejsza rozmiar pakietu.
Jacques Cornat
8

Poniższe rozwiązanie zakłada, że ​​udostępniasz swój dist / folder za pomocą nodejs. Użyj następującego pliku app.js na poziomie głównym

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

Upewnij się, że instalujesz zależności;

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

Teraz utwórz aplikację

ng build --prod --build-optimizer

Jeśli chcesz dalej skompresować kompilację, powiedz zmniejsz 300kb (w przybliżeniu) z, a następnie postępuj zgodnie z poniższą procedurą;

Utwórz folder o nazwie vendorwewnątrz srcfolderu i wewnątrz folderu dostawcy, utwórz plik rxjs.ts i wklej w nim poniższy kod;

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

A następnie dodaj następujący ciąg do tsconfig.jsonpliku w aplikacji angular -cli. Następnie compilerOptionsdodaj następujący plik JSON;

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

Spowoduje to, że rozmiar kompilacji będzie o wiele za mały. W moim projekcie zmniejszyłem rozmiar z 11mb do 1mb. Mam nadzieję, że to pomoże

Renil Babu
źródło
6

Jedną rzeczą, którą chcę się podzielić, jest to, jak importowane biblioteki zwiększają rozmiar dyst. Miałem zaimportowany pakiet angular2-moment, podczas gdy mogłem wykonać całe formatowanie daty i czasu, którego potrzebowałem, używając standardowego DatePipe wyeksportowanego z @ angular / common.

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

chunk {0} polyfills.036982dc15bb5fc67cb8.bundle.js (polyfills) 191 kB {4} [początkowe] [wyrenderowane] chunk {1} main.e7496551a26816427b68.bundle.js (główne) 2,2 MB {3} [początkowe] [wyrenderowane] fragment {2} styles.056656ed596d26ba0192.bundle.css (style) 69 bajtów {4} [początkowy] [renderowany] fragment {3} vendor.62c2cfe0ca794a5006d1.bundle.js (sprzedawca) 3,84 MB [początkowa] [wyrenderowany] fragment {4 } inline.0b9c3de53405d705e757.bundle.js (inline) 0 bajtów [wpis] [wyrenderowany]

Po usunięciu Angular2-moment i zamiast tego użycie DatePipe

chunk {0} polyfills.036982dc15bb5fc67cb8.bundle.js (polyfills) 191 kB {4} [początkowe] [wyrenderowane] chunk {1} main.f2b62721788695a4655c.bundle.js (główne) 2,2 MB {3} [początkowe] [wyrenderowane] fragment {2} styles.056656ed596d26ba0192.bundle.css (styles) 69 bajtów {4} [początkowy] [renderowany] fragment {3} vendor.e1de06303258c58c9d01.bundle.js (sprzedawca) 3,35 MB [początkowy] [wyrenderowany] fragment {4 } inline.3ae24861b3637391ba70.bundle.js (inline) 0 bajtów [wpis] [wyrenderowany]

Zwróć uwagę, że pakiet sprzedawcy zmniejszył się o pół megabajta!

Chodzi o to, że warto sprawdzić, co potrafią standardowe pakiety kątowe, nawet jeśli znasz już bibliotekę zewnętrzną.

kwalifikski
źródło
1

Jeśli biegałeś ng build --prod- vendorw ogóle nie powinieneś mieć plików.

Jeśli uruchomię tylko ng build- otrzymuję te pliki:

wprowadź opis obrazu tutaj

Całkowity rozmiar folderu to ~ 14 MB. Waat! :RE

Ale jeśli uruchomię ng build --prod- otrzymuję te pliki:

wprowadź opis obrazu tutaj

Całkowity rozmiar folderu to 584 KB.

Jeden i ten sam kod. W obu przypadkach włączyłem Ivy. Angular to 8.2.13.

Więc - myślę, że nie dodałeś --proddo swojego polecenia budowania?

pesho hristov
źródło
1

Jeśli używasz Angular 8+ i chcesz zmniejszyć rozmiar pakietu, możesz użyć Ivy. Ivy jest domyślnym silnikiem widoku w Angular 9 Po prostu przejdź do src / tsconfig.app.json i dodaj parametr angularCompilerOptions, na przykład:

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

/* add this one */ 
  "angularCompilerOptions": {
    "enableIvy": true
  }
}
Rachel
źródło
1

To zmniejszyło rozmiar w moim przypadku:

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

W przypadku Angular 5+ ng-build --prod robi to domyślnie. Rozmiar po uruchomieniu tego polecenia zmniejszył się z 1,7 MB do 1,2 MB, ale nie wystarcza do moich celów produkcyjnych.

Pracuję na platformie Facebook Messenger, a aplikacje do komunikatorów muszą mieć mniej niż 1 MB, aby mogły działać na platformie Messenger. Próbowałem wymyślić sposób na efektywne potrząsanie drzewami, ale bez skutku.

Mahesh Sharma
źródło
1

Działa w 100% ng build --prod --aot --build-optimizer --vendor-chunk = true

AJAY AVHAD
źródło
0

Mam kątową aplikację rozruchową 5 + sprężynową (application.properties 1.3+) dzięki kompresji (link załączony poniżej) udało mi się zmniejszyć rozmiar pliku main.bundle.ts z 2,7 MB do 530 KB.

Również domyślnie --aot i --build-optimizer są włączone w trybie --prod, więc nie trzeba ich określać osobno.

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

sah1
źródło
0

Sprawdź, czy masz konfigurację o nazwie "produkcja" dla ng build --prod, ponieważ jest to skrót od ng build --configuration = production Brak odpowiedzi rozwiązał mój problem, ponieważ problem znajdował się tuż przed ekranem. Myślę, że może to być dość powszechne ... Umiędzynarodowiłem aplikację z i18n zmieniając nazwy wszystkich konfiguracji na np. Production-en. Następnie zbudowałem za pomocą ng build --prod, zakładając, że domyślna optymalizacja jest używana i powinna być bliska optymalnej, ale w rzeczywistości została wykonana tylko kompilacja ng, co dało pakiet 7 MB zamiast 250 KB.

antidotum
źródło
0

Zaczerpnięte z Angular Docs v9 ( https://angular.io/guide/workspace-config#alternate-build-configurations ):

Domyślnie zdefiniowana jest konfiguracja produkcyjna, a polecenie ng build ma opcję --prod, która buduje przy użyciu tej konfiguracji. Konfiguracja produkcyjna ustawia wartości domyślne, które optymalizują aplikację na wiele sposobów, takich jak łączenie plików , minimalizowanie nadmiaru białych znaków , usuwanie komentarzy i martwego kodu oraz przepisywanie kodu w celu użycia krótkich, tajemniczych nazw ( „minifikacja” ).

Dodatkowo możesz skompresować wszystkie wdrażane pliki za pomocą @ angular-builders / custom-webpack: kreator przeglądarek, w którym Twój niestandardowy webpack.config.js wygląda tak:

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

Następnie będziesz musiał skonfigurować serwer WWW, aby obsługiwał skompresowaną zawartość, np. Z nginx musisz dodać do swojego nginx.conf:

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

W moim przypadku folder dist skurczył się z 25 do 5 MB po samym użyciu --prod w kompilacji ng, a następnie skurczył się dalej do 1,5 MB po kompresji.

Bat0u89
źródło