Czego Webpack 4 oczekuje od Pakietu z sideEffects: false

Webpack 4 dodał nową funkcję: obsługuje teraz flagę sideEffects w package.json modułów, które łączy.

From Webpack 4: released today

W ciągu ostatnich 30 dni ściśle współpracowaliśmy z każdym z frameworków, aby upewnić się, że są one gotowe do obsługi webpack 4 w odpowiednich cli itp. Nawet popularne biblioteki, takie jak lodash-es, rxjs wspierają flagę sideEffects, więc używając ich najnowszej wersji zobaczysz natychmiastowy Rozmiar pakietu maleje po wyjęciu z pudełka.

From Webpack docs

"sideEffects": false flag w pakiecie big-module.json wskazuje, że moduły pakietu nie mają skutków ubocznych (na ewaluację), a jedynie eksponują eksport. Pozwala to narzędziom takim jak webpack zoptymalizować reeksport.

Podczas gdy drugi link pokazuje wyniki użycia flagi, nie wyjaśnia jasno, co stanowi efekt uboczny. ES6 zawiera koncepcję efektów ubocznych dla modułów jak opisano tutaj , ale jak to się odnosi do tego, co Webpack uważa za skutki uboczne.

W kontekście znacznika sideEffects, czego moduł musi unikać, aby używać sideEffects:false bez problemów, lub odwrotnie, co moduł musi zrobić, aby używać sideEffects:false bez problemów.

Dla kompletności, pomimo solidnej odpowiedzi @SeanLarkin poniżej, chciałbym uzyskać wyjaśnienie co następuje:

  1. Oczywiście skutki uboczne oznacza coś szczególnego w fp i byłoby obejmują logowanie (konsola lub gdzie indziej) i wyrzucanie błędów. Zakładam, że w tym kontekście są one całkowicie akceptowalne?

  2. Czy moduł może zawierać odniesienia okrągłe i nadal używać sideEffects: false?

  3. Czy Jest jakiś sposób, aby zweryfikować lub że moduł jest w stanie zweryfikować, że moduł może sideEffects: false poza próbą wytropienia błędów spowodowanych jego niewłaściwym użyciem?

  4. Czy są jakieś inne czynniki, które uniemożliwiałyby korzystanie z modułu sideEffects: false?

Author: Undistraction, 2018-03-07

2 answers

Sean z zespołu webpack! Dołożę wszelkich starań, aby zamiast naszej dokumentacji nadal w toku odpowiedzieć na twoje pytanie tutaj!

Zgodnie ze specyfikacją modułu ECMA (nie zamierzam próbować znaleźć linku, więc musisz mi zaufać, ponieważ jest zakopany),

Ilekroć moduł reexports wszystkie eksporty (niezależnie od tego, czy są używane czy nie) muszą zostać ocenione i wykonane w przypadku, gdy jeden z tych eksportów stworzył efekt uboczny z innym.

Dla przykład stworzyłem mały scenariusz ze zdjęciem, aby lepiej zwizualizować sprawę:

Na tym zdjęciu widzimy, że 3 pojedyncze moduły z pojedynczym importem są importowane do jednego modułu, który następnie pobiera te domyślne eksport i reexportuje je z tego modułu:

Przykład braku skutków ubocznych Z ponownie zaimportowanych modułów

Widać tutaj, że żaden z reeksportów nie jest dokonywany przez siebie, dlatego (jeśli webpack otrzymał sygnał), możemy pominąć eksport b i c z parzystego śledzone lub używane(korzyści z wydajności w zakresie rozmiaru i czasu budowy).

Tutaj wpisz opis obrazka

Jednak w tym przypadku widzimy, że eksport c jest "dokonywany" przez lokalne zmiany stanu, ponieważ jest przypisywany do sumowania b i a. W związku z tym (dlatego wymaga tego Specyfikacja), musielibyśmy włączyć zarówno b, jak i a oraz wszystkie jej zależności do pakietu.

Wybraliśmy "sideEffects: false" jako sposób na zaoszczędzenie zarówno czasu kompilacji, jak i rozmiaru kompilacji ponieważ pozwala nam to na natychmiastowe przycinanie (jawnie) eksportów, o których deweloperzy/autorzy bibliotek wiedzą, że są wolne od efektów ubocznych (kosztem właściwości w pakiecie.json, lub 2-3 więcej linii config).

Chociaż technicznie ten przykład jest bardzo prymitywny, kiedy zaczynasz zajmować się frameworkami lub bibliotekami, które reeksportują kilka modułów na wyższy poziom dla doświadczenia programistów (trzy.js, Angular, lodash-es, itp.), wtedy wzrost wydajności jest znaczący, gdy (jeśli są sideeffect free module exports) oznaczasz je w ten sposób.

Dodatkowe Wyjaśnienia:

  1. oczywiście efekty uboczne oznaczają coś szczególnego w fp i obejmują logowanie (konsolę lub gdzie indziej) i wyrzucanie błędów. Zakładam, że w tym kontekście są one całkowicie akceptowalne?

W przypadku, gdy to próbuje rozwiązać, tak. Tak długo, jak efekty utworzone przeciwko eksportowi modułów nie są realizowane przez inne, które spowodowałyby przycinanie, aby nie było dopuszczalne.

  1. czy moduł może zawierać odniesienia kołowe i nadal używać sideEffects: false?
Teoretycznie powinno.
  1. czy jest jakiś sposób, aby zweryfikować lub czy moduł jest w stanie użyć sideEffects: false poza próbami wytropienia błędów spowodowanych jego niewłaściwym użyciem?

Nic mi o tym nie wiadomo, ale byłoby to świetne narzędzie.

  1. czy są jakieś inne czynniki, które uniemożliwiłyby modułowi możliwość użycia sideEffects: false?

Jeśli właściwość nie jest w package.json lub zdefiniowana w module.rules, lub mode: production nie jest ustawiona(co wykorzystuje optymalizację).

 22
Author: Sean Larkin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-03-14 14:28:06

To ustawienie jest bardzo niejasne i nie jest wystarczająco opisane w dokumentach. Dokumenty mówią głównie: "istnieje flaga sideEffects dla modułów bez żadnych efektów ubocznych".

Konsensus jest taki, że zdanie" nie ma efektów ubocznych" można rozcyfrować jako "nie rozmawia z rzeczami zewnętrznymi modułu na najwyższym poziomie".

Obecnie rozumiem, że ta flaga jest tylko dla "reeksportu", a" reeksportu " jest:

export { a } from './lib/a'
export { b } from './lib/b'

Gdzieś w <npm-package>/index.js (lub jakikolwiek inny plik wewnątrz <npm-package>).

Jeśli Webpack wykryje, że aplikacja importuje tylko a z <npm-package> i nie importuje b w dowolnym miejscu, to Webpack może po prostu upuścić linię export { b } from './lib/b' z <npm-package>/index.js, co powoduje, że nie obejmuje './lib/b.js' plik w wynikowym pakiecie (co czyni go mniejszym o rozmiar pliku './lib/b.js').

Teraz, jeśli './lib/b.js' miał jakieś linie kodu najwyższego poziomu robiące jakieś "efekty uboczne", tzn. jeśli './lib/b.js' zrobił coś like:

  • window.jQuery = ...
  • if (!global.Set) global.Set = require('babel-polyfill').Set
  • new XmlHttpRequest().post('/analytics', data)

Wtedy './lib/b.js' można by powiedzieć, że ma "skutki uboczne", ponieważ jego kod najwyższego poziomu (który jest wykonywany na import './lib/b') wpływa na coś poza zakresem './lib/b.js' pliku.

W tym samym czasie, dopóki './lib/b.js' Kod najwyższego poziomu nie sięga poza plik *.js, to nie ma żadnych "skutków ubocznych":

let a = 1
a = a + 1 + computeSomeValue()
export default a
export const b = a + 1
export const c = b + 1

To nie są "skutki uboczne".

I jest finał: jeśli pakiet npm ma dowolne pliki *.css, które użytkownik może import, wtedy te pliki *.css są "efektami ubocznymi", ponieważ:

import 'npm-package/style.css'

Nie ma żadnej zmiennej przypisanej do tego import, co w praktyce oznacza "ten importowany moduł nie jest używany nigdzie w aplikacji" dla Webpack. Tak więc Webpack po prostu odrzuca plik 'npm-package/style.css' Z Pakietu jako część procesu "Tree-shaking", jeśli npm-package mA flagę sideEffects: false. Więc zamiast pisać sideEffects: false zawsze pisz "sideEffects": ["*.css"]. Nawet jeśli Twój Pakiet npm nie eksportuje wszelkie pliki CSS może to zrobić w przyszłości i będzie to chronić przed wspomnianym" CSS file not included " błąd.

 3
Author: asdfasdfads,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-30 09:04:26