Webpack 4 a ajouté une nouvelle fonctionnalité: il prend désormais en charge un drapeau sideEffects
dans le package.json
des modules qu’il regroupe.
De Webpack 4: publié aujourd'hui
Au cours des 30 derniers jours, nous avons travaillé en étroite collaboration avec chacun des frameworks pour nous assurer qu'ils sont prêts à prendre en charge le Webpack 4 dans leurs cli respectives, etc. version, vous verrez la taille de paquet instantanée diminue de la boîte.
L'indicateur "sideEffects": false dans le package.json de big-module indique que les modules du package n'ont pas d'effets secondaires (sur l'évaluation) et n'exposent que les exportations. Cela permet à des outils tels que webpack d'optimiser les réexportations.
Le deuxième lien montre les résultats de l’utilisation du drapeau, mais il n’explique pas clairement en quoi consiste un effet secondaire. ES6 inclut le concept des effets secondaires pour les modules, comme indiqué ici , mais comment cela est-il lié à ce que Webpack considère comme des effets secondaires.
Dans le contexte de l'indicateur sideEffects
, de quoi un module a-t-il besoin pour éviter d'utiliser sideEffects:false
sans problèmes, ou inversement, que doit faire un module pour utiliser sideEffects:false
sans problèmes.
Pour être complet, malgré la solide réponse de @ SeanLarkin ci-dessous, j'aimerais avoir des éclaircissements sur les points suivants:
Évidemment, effets secondaires ont une signification particulière en fp et incluent la journalisation (sur console ou ailleurs) et la génération d’erreurs. Je suppose que dans ce contexte, ils sont parfaitement acceptables?
Un module peut-il contenir des références circulaires et continuer à utiliser sideEffects: false
?
Existe-t-il un moyen de vérifier ou qu'un module est capable de vérifier qu'un module peut sideEffects: false
au-delà de la recherche d’erreurs causées par une mauvaise utilisation?
Y a-t-il d'autres facteurs qui empêcheraient un module de pouvoir utiliser sideEffects: false
?
Sean de l'équipe webpack! Je ferai de mon mieux au lieu de notre documentation toujours en cours pour répondre à votre question ici!
Selon la spécification de module ECMA (je ne vais pas essayer de trouver le lien, vous devrez donc me faire confiance ici car il est enterré),
lorsqu'un module réexporte , toutes les exportations (qu'elles soient utilisées ou non) doivent être évaluées et exécutées dans le cas où l'une de ces exportations a créé un effet secondaire. avec un autre.
Par exemple, j'ai créé un petit scénario avec une photo pour mieux visualiser le cas:
Sur cette photo, nous voyons que 3 modules individuels avec une seule importation sont importés dans un seul module, qui prend ensuite ces exportations par défaut, et les réexporte à partir de ce module:
Vous pouvez voir ici qu’aucune des réexportations n’est effectuée les unes par les autres. Par conséquent (si Webpack recevait un signal), nous pourrions omettre les exportations b
et c
de la trace ou de l’utilisation (taille et temps de construction avantages de performance).
Cependant, dans ce cas, nous voyons que les exportations c
sont "affectées" par les changements d'état locaux car elles sont réaffectées à la somme de b
et a
. Par conséquent, (c'est pourquoi la spécification appelle cela), nous aurions besoin d'inclure à la fois b
et a
et toutes ses dépendances dans le bundle.
Nous avons choisi "sideEffects: false" pour gagner du temps sur la compilation et sur la taille de la construction, car cela nous permet de primer instantanément (explicitement) les exportations (explicitement) que les développeurs/auteurs de bibliothèques savent sans effet secondaire (au détriment d'une propriété package.json, ou encore 2-3 lignes de configuration).
Bien que, techniquement, cet exemple soit très primitif, lorsque vous commencez à traiter avec des frameworks ou des bibliothèques qui réexportent un ensemble de modules à un niveau supérieur pour l'expérience de développeur (Three.js, Angular, lodash-es, etc.), les gains de performances sont significatifs lorsque (s’ils sont des exportations de modules sans effets secondaires), vous les signalez de cette manière.
Clarifications supplémentaires:
- Évidemment, effets secondaires ont une signification particulière en fp et incluent la journalisation (sur console ou ailleurs) et la génération d’erreurs. Je suppose que dans ce contexte, ils sont parfaitement acceptables?
Dans le cas où cela essaye de résoudre, oui. Tant que les effets créés sur les exportations de modules ne sont pas affectés par d'autres, ce qui rendrait l'élagage inacceptable.
- Un module peut-il contenir des références circulaires et continuer à utiliser
sideEffects: false?
Cela devrait, en théorie.
- Existe-t-il un moyen de vérifier ou qu'un module est capable d'utiliser
sideEffects: false
au-delà de la recherche d’erreurs causées par une mauvaise utilisation?
Pas que je sache, cependant ce serait un excellent outil.
- Y a-t-il d'autres facteurs qui empêcheraient un module de pouvoir utiliser
sideEffects: false
?
Si la propriété n'est pas dans package.json
ou défini dans module.rules
, ou mode: production
n'est pas défini (ce qui exploite l'optimisation).
Ce paramètre sideEffects
est très vague et n’est pas suffisamment décrit dans la documentation. Les documents sont généralement du type "il existe un drapeau sideEffects
pour les modules libres d’effets secondaires".
Le consensus est que l'expression "n'a pas d'effets secondaires" peut être déchiffrée en "ne parle pas aux choses extérieures au module au plus haut niveau".
D'après ce que je comprends actuellement, cet indicateur sideEffects
ne concerne que les "réexportations", le terme "réexportation" étant:
export { a } from './lib/a'
export { b } from './lib/b'
quelque part dans <npm-package>/index.js
(ou tout autre fichier à l'intérieur du <npm-package>
).
Si Webpack détecte que l'application importe uniquement a
de <npm-package>
Et n'importe pas b
, Webpack peut simplement supprimer la ligne export { b } from './lib/b'
De <npm-package>/index.js
A pour résultat de ne pas inclure le fichier './lib/b.js'
Dans le paquet résultant (ce qui le rend plus petit de la taille du fichier './lib/b.js'
).
Maintenant, si './lib/b.js'
Avait des lignes de code de niveau supérieur faisant des "effets secondaires", c'est-à-dire si './lib/b.js'
Faisait quelque chose comme:
window.jQuery = ...
if (!global.Set) global.Set = require('babel-polyfill').Set
new XmlHttpRequest().post('/analytics', data)
alors on dirait que './lib/b.js'
a des "effets secondaires" car son code de niveau supérieur (qui est exécuté sur import './lib/b'
) affecte quelque chose en dehors de la portée du fichier './lib/b.js'
.
Dans le même temps, tant que le code de niveau supérieur './lib/b.js'
N'atteint pas l'extérieur de ce fichier *.js
, Il n'a aucun "effet secondaire":
let a = 1
a = a + 1 + computeSomeValue()
export default a
export const b = a + 1
export const c = b + 1
ce ne sont pas tous des "effets secondaires".
Et il y a un casse-tête final: si un paquet npm contient des fichiers *.css
Qu'un utilisateur peut import
, ces fichiers *.css
Sont tous des "effets secondaires", car:
import 'npm-package/style.css'
n'a pas de variable affectée à ce import
, ce qui signifie en réalité "ce module importé n'est utilisé nulle part dans l'application" pour Webpack. Et donc Webpack supprime simplement le fichier 'npm-package/style.css'
Du bundle dans le cadre du processus "d'arborescence" si le npm-package
A le drapeau sideEffects: false
. Ainsi, au lieu d'écrire sideEffects: false
, Écrivez toujours "sideEffects": ["*.css"]
. Même si votre paquet npm n'exporte aucun fichier CSS, il est possible que cela se produise à l'avenir. Cela vous évitera le bogue "Fichier CSS non inclus" mentionné ci-dessus.