plugin page htmlwebpackplugin dev cannot body app javascript webpack bundler package.json side-effects

javascript - page - webpack externals



¿Qué espera Webpack 4 de un paquete con sideEffects: false (2)

Webpack 4 ha agregado una nueva característica: ahora es compatible con un indicador sideEffects en el package.json de los módulos que está empaquetando.

De Webpack 4: lanzado hoy

Durante los últimos 30 días, hemos trabajado estrechamente con cada uno de los marcos para asegurarnos de que estén listos para admitir el webpack 4 en sus respectivos cli, etc. Incluso en las bibliotecas populares como lodash-es, RxJS está apoyando la bandera sideEffects, por lo tanto, utilizando sus últimos En la versión que verá, el tamaño del paquete instantáneo disminuye fuera de la caja.

De los documentos de webpack

El "sideEffects": indicador falso en el paquete.json de big-module indica que los módulos del paquete no tienen efectos secundarios (en la evaluación) y solo exponen las exportaciones. Esto permite que herramientas como webpack optimicen las reexportaciones.

Si bien el segundo enlace muestra los resultados del uso de la bandera, no explica claramente qué constituye un efecto secundario. ES6 incluye el concepto de efectos secundarios para módulos como se describe here , pero ¿cómo se relaciona esto con lo que Webpack considera efectos secundarios?

En el contexto del indicador sideEffects , ¿qué debe evitar un módulo para usar sideEffects:false sin problemas o, por el contrario, qué debe hacer un módulo para usar sideEffects:false sin problemas?

Para estar completo, a pesar de la sólida respuesta de @ SeanLarkin a continuación, me encantaría obtener una aclaración sobre lo siguiente:

  1. Obviamente, los efectos secundarios significan algo particular en fp e incluirían el registro (consola o en cualquier otro lugar) y el lanzamiento de errores. Supongo que en este contexto son perfectamente aceptables.

  2. ¿Puede un módulo contener referencias circulares y seguir utilizando sideEffects: false ?

  3. ¿Hay alguna forma de verificar o de que un módulo pueda verificar que un módulo puede sideEffects: false más allá de intentar sideEffects: false errores causados ​​por su uso indebido?

  4. ¿Hay otros factores que impidan que un módulo pueda usar sideEffects: false ?


Esta configuración de sideEffects es muy vaga y no se describe suficientemente en los documentos. La mayoría de los documentos son como "hay un indicador de efectos secundarios para módulos sin efectos secundarios".

El consenso es que la frase "no tiene efectos secundarios" se puede descifrar ya que "no habla con cosas externas al módulo en el nivel superior".

Mi entendimiento actual es que este indicador de sideEffects es solo para "reexportaciones", siendo una "reexportación":

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

en algún lugar del <npm-package>/index.js (o cualquier otro archivo dentro del <npm-package> ).

Si Webpack detecta que la aplicación solo importa a desde <npm-package> y no importa b ningún lugar, entonces Webpack puede simplemente eliminar la export { b } from ''./lib/b'' línea export { b } from ''./lib/b'' de <npm-package>/index.js ''./lib/b.js'' archivo <npm-package>/index.js no incluye ''./lib/b.js'' archivo ''./lib/b.js'' en el paquete resultante (lo que lo hace más pequeño por el tamaño del archivo ''./lib/b.js'' ).

Ahora, si ''./lib/b.js'' tuviera algunas líneas de código de nivel superior haciendo algunos "efectos secundarios", es decir, si ''./lib/b.js'' hizo algo como:

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

entonces se ''./lib/b.js'' tiene "efectos secundarios" porque su código de nivel superior (que se ejecuta al import ''./lib/b'' ) afecta algo que está fuera del alcance de ''./lib/b.js'' archivo / ''./lib/b.js''

Al mismo tiempo, siempre que ''./lib/b.js'' código de nivel superior ''./lib/b.js'' no llegue fuera del archivo *.js , no tendrá ningún "efecto secundario":

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

estos no son todos los "efectos secundarios".

Y hay una respuesta final: si un paquete npm tiene algún archivo *.css que un usuario pueda import entonces estos archivos *.css son todos "efectos secundarios", porque:

import ''npm-package/style.css''

no tiene una variable asignada a esta import que efectivamente significa que "este módulo importado no se usa en ninguna parte de la aplicación" para Webpack. Y así, Webpack simplemente descarta el ''npm-package/style.css'' del paquete como parte del proceso de "sacudir el árbol" si el npm-package sideEffects: false tiene sideEffects: false flag. Entonces, en lugar de escribir sideEffects: false siempre escribe "sideEffects": ["*.css"] . Incluso si su paquete npm no exporta ningún archivo CSS, podría hacerlo en un futuro y esto protegerá contra el error mencionado anteriormente "archivo CSS no incluido".


Sean del equipo webpack! ¡Haré mi mejor esfuerzo en lugar de nuestra documentación aún en progreso para responder su pregunta aquí!

De acuerdo con la especificación del módulo ECMA (no voy a intentar encontrar el enlace, así que tendrás que confiar en mí porque está enterrado),

siempre que un módulo reexporte todas las exportaciones (independientemente de si se usan o no) se deben evaluar y ejecutar en el caso de que una de esas exportaciones haya creado un efecto secundario con otro.

Por ejemplo, he creado un pequeño escenario con una foto para visualizar mejor el caso:

En esta foto vemos que se importan 3 módulos individuales con una sola importación a un solo módulo, que luego toma las exportaciones predeterminadas y las reexporta desde ese módulo:

Aquí puede ver que ninguna de las reexportaciones se efectúa entre sí, por lo tanto (si se le diera una señal al paquete web), podríamos omitir las exportaciones b incluso de ser rastreadas o usadas (beneficios de tamaño y tiempo de compilación).

Sin embargo, en este caso, vemos que las exportaciones c son "efectuadas" por cambios de estado locales porque se reasignan a la suma de b y a . Por lo tanto, (por lo que la especificación exige esto), deberíamos incluir b y a y cualquiera de sus dependencias en el paquete.

Elegimos "sideEffects: false" como forma de ahorrar tanto en tiempo de compilación como en tamaño de compilación porque esto nos permite eliminar (explícitamente) instantáneamente las exportaciones que los desarrolladores / autores de bibliotecas saben que están libres de efectos secundarios (a expensas de una propiedad en un package.json, o 2-3 líneas más de configuración).

Aunque técnicamente este ejemplo es muy primitivo, cuando comienza a trabajar con Frameworks o Bibliotecas que reexportan un montón de módulos hasta un nivel más alto para Developer Experience (Three.js, Angular, lodash-es, etc.), entonces las mejoras de rendimiento son significativas cuando (Si se trata de exportaciones de módulos libres de efectos secundarios), debe marcarlos de esta manera.

Aclaraciones adicionales:

  1. Obviamente, los efectos secundarios significan algo particular en fp e incluirían el registro (consola o en cualquier otro lugar) y el lanzamiento de errores. Supongo que en este contexto, ¿son perfectamente aceptables?

En el caso de que esto se trate de resolver, sí. Siempre y cuando los efectos creados contra las exportaciones de módulos no sean afectados por otros, esto causaría que la poda no sea aceptable.

  1. ¿Puede un módulo contener referencias circulares y seguir utilizando sideEffects: false?

Debería, en teoría.

  1. ¿Hay alguna forma de verificar o de que un módulo pueda usar sideEffects: false más allá de intentar sideEffects: false errores causados ​​por su uso incorrecto?

No que yo sepa, sin embargo, esta sería una gran herramienta.

  1. ¿Hay otros factores que impidan que un módulo pueda usar sideEffects: false ?

Si la propiedad no está en package.json o está definida en module.rules , o mode: production no está establecida (lo que aprovecha la optimización).