Что ожидает Webpack 4 от пакета с побочными эффектами: false

Webpack 4 добавил новую функцию: теперь он поддерживает тег sideEffects флаг в package.json модули это связывать.

С Webpack 4: выпущен сегодня

за последние 30 дней мы тесно сотрудничали с каждым из фреймворков, чтобы гарантировать, что они готовы поддерживать webpack 4 в своих соответствующих cli и т. д. Даже популярные библиотеки, такие как lodash-es, RxJS поддерживают флаг sideEffects, поэтому, используя их последнюю версию, вы будет видеть мгновенный размер пакета уменьшается из коробки.

С Webpack документы

"побочные эффекты": ложный флаг в пакете big-module.json указывает, что модули пакета не имеют побочных эффектов (при оценке) и предоставляют только экспорт. Это позволяет таким инструментам, как webpack, оптимизировать реэкспорт.

хотя вторая ссылка показывает результаты использования флага, она четко не объясняет, что представляет собой побочный эффект. ES6 включает концепцию побочных эффектов для модулей, как описано здесь, но как это связано с тем, что Webpack считает побочными эффектами.

в контексте sideEffects флаг, что нужно модулю, чтобы избежать использования sideEffects:false без проблем или, наоборот, что должен делать модуль, чтобы использовать sideEffects:false без проблем.

для полноты, несмотря на твердый ответ @SeanLarkin ниже, я хотел бы получить разъяснения по поводу следующий:

  1. очевидно, побочные эффекты означают что-то конкретное в fp и включают ведение журнала (консоль или в другом месте) и выброс ошибок. Я предполагаю, что в этом контексте они вполне приемлемы?

  2. может ли модуль содержать круговые ссылки и по-прежнему использовать sideEffects: false?

  3. есть ли способ проверить или что модуль может проверить, что модуль может sideEffects: false помимо попыток отслеживать ошибки вызвано его неправильным использованием?

  4. есть ли какие-либо другие факторы, которые помешали бы модулю использовать sideEffects: false?

2 ответов


Шон из команды webpack! Я сделаю все возможное вместо того, чтобы наша документация все еще продолжается, чтобы ответить на ваш вопрос здесь!

согласно спецификации модуля ECMA (я не собираюсь пытаться найти ссылку, поэтому вам придется доверять мне здесь, потому что ее похоронили),

каждый раз, когда модуль ре-экспорта весь экспорт (независимо от того, используется или не используется) должен быть оценен и выполнен в случае, если один из этих экспорта создал побочный эффект с другим.

например, я создал небольшой сценарий с фотографией, чтобы лучше визуализировать случай:

на этой фотографии мы видим, что 3 отдельных модуля с одним импортом импортируются в один модуль, который затем принимает экспорт по умолчанию и ре-экспорта их из этого модуля:

Example of No Side Effects from Reexported Modules

вы можете видеть здесь, что ни один из реэкспортов не осуществляется друг другом, поэтому (если webpack был дан сигнал), мы могли бы опустить экспорт b и c от даже трассировки или использования (размер и время сборки преимущества производительности).

enter image description here

однако в данном случае мы видим, что экспорт c "осуществляется" локальными изменениями состояния, потому что он переназначается на суммирование b и a. Поэтому (именно поэтому спецификация призывает к этому), нам нужно будет включить оба b и a и любой из его зависимостей в пакете.

мы выбрали "sideEffects: false" как способ сэкономить время компиляции и размер сборки, потому что это позволяет нам мгновенно обрезать (явно) экспорт, который разработчики/авторы библиотеки знают, свободны от побочных эффектов (за счет свойства в пакете.json, или еще 2-3 строки конфигурации).

хотя технически этот пример очень примитивен, когда вы начинаете иметь дело с фреймворками или библиотеками, которые повторно экспортируют кучу модулей до более высокого уровня для разработчика Опыт (Три.js, Angular, lodash-es и т. д.), то прирост производительности значителен, когда (если они являются sideEffect Free module exports) вы помечаете их таким образом.

Дополнительные Разъяснения:

  1. очевидно, что побочные эффекты означают что-то конкретное в fp и включают ведение журнала (консоль или в другом месте) и выбрасывание ошибок. Я предполагаю, что в этом контексте они вполне приемлемы?

в случай, который это пытается решить, да. До тех пор, пока эффекты, созданные против экспорта модулей, не будут реализованы другими, что приведет к недопустимости обрезки.

  1. может ли модуль содержать круговые ссылки и по-прежнему использовать sideEffects: false?

это должно, теоретически.

  1. есть ли способ проверить или что модуль способен использовать sideEffects: false за попыткой отслеживать ошибки, вызванные его злоупотребление?

не то, что я знаю, однако это был бы отличный инструмент.

  1. есть ли какие-либо другие факторы, которые помешали бы модулю использовать sideEffects: false?

если свойство не находится в package.json или определена в module.rules или mode: production не установлен (что использует оптимизацию).


этой sideEffects настройка очень расплывчата и недостаточно описана в документах. Документы в основном как "там sideEffects флаг для модулей свободных всех побочных эффектов".

сошлись на том, что "не имеет противопоказания" фраза может быть decyphered как "не разговаривать с внешнего модуля на высшем уровне".

мое текущее понимание заключается в том, что этот sideEffects флаг предназначен только для "реэкспорта", а "реэкспорт":

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

где-то в <npm-package>/index.js (или любой другой файл внутри <npm-package>).

если Webpack обнаруживает, что приложение импортирует только a С <npm-package>, и не импортирует b в любом месте, то Webpack может просто бросить export { b } from './lib/b' строку с <npm-package>/index.js в результате не включая './lib/b.js' файл в результирующем пакете (что делает его меньше на размер ).

теперь, если './lib/b.js' были некоторые строки верхнего уровня кода, делающие некоторые "побочные эффекты", т. е. если './lib/b.js' что-то сделал например:

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

затем './lib/b.js' было бы сказано, что имеют "побочные эффекты", потому что его код верхнего уровня (который выполняется при import './lib/b') влияет на что-то за пределами .

в то же время, как './lib/b.js' код верхнего уровня не выходит за пределы этого *.js файл, то он не имеет никаких "побочных эффектов":

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

это все не "побочные эффекты".

и есть окончательный gotcha: если пакет npm имеет любой *.css файлы, которые пользователь может import потом эти *.css файлы будут все "побочные эффекты", потому что:

import 'npm-package/style.css'

не имеет переменной, назначенной этому import что фактически означает ,что" этот импортированный модуль не используется нигде в приложении " для Webpack. И поэтому Webpack просто отбрасывает 'npm-package/style.css' файл из пакета как часть процесса "встряхивания дерева", если npm-package есть sideEffects: false флаг. Итак, вместо того, чтобы писать sideEffects: false всегда пишу "sideEffects": ["*.css"]. Даже если ваш пакет npm не экспортирует файлы CSS, он может сделать это в будущем, и это защитит от вышеупомянутой ошибки "файл CSS не включен".