Что ожидает Webpack 4 от пакета С sideEffects: false
Webpack 4 добавили новую функцию: теперь он поддерживает sideEffects
флаг в package.json
модулей он спакетировал.
Из Webpack 4: выпущен сегодня
За последние 30 дней мы тесно сотрудничали с каждой из фреймворков, чтобы гарантировать, что они готовы поддерживать webpack 4 в их соответствующих кликах и т.д. Даже популярные библиотеки, такие как lodash-es, RxJS, поддерживают флаг sideEffects, поэтому, используя их последние версии вы увидите, что размер мгновенного пакета уменьшается из коробки.
Из документов Webpack
"SideEffects": флаговый флаг в big-module package.json указывает, что модули пакета не имеют побочных эффектов (при оценке) и только экспортируют экспорт. Это позволяет инструментам, таким как webpack, оптимизировать реэкспорт.
Пока вторая ссылка показывает результаты использования флага, она не дает четкого объяснения того, что представляет собой побочный эффект. ES6 включает концепцию побочных эффектов для модулей, описанных здесь, но как это связано с тем, что Webpack рассматривает побочные эффекты.
В контексте sideEffects
то, что модуль должен избегать использовать sideEffects:false
без проблем или, наоборот, что должен делать модуль, чтобы использовать sideEffects:false
без проблем.
Для полноты, несмотря на @SeanLarkin солидный ответ ниже, я хотел бы получить разъяснения по следующему:
-
Очевидно, что побочные эффекты означают что-то конкретное в fp и включают в себя ведение журнала (консоль или в другом месте) и бросание ошибок. Я предполагаю, что в этом контексте они вполне приемлемы?
-
Может ли модуль содержать циклические ссылки и по-прежнему использовать sideEffects: false
?
-
Есть ли способ проверить или что модуль может проверить, что модуль может sideEffects: false
кроме попытки отследить ошибки, вызванные его неправильным использованием?
-
Существуют ли какие-либо другие факторы, которые препятствовали бы тому, чтобы модуль мог использовать sideEffects: false
?
Ответы
Ответ 1
Шон из команды webpack! Я сделаю все возможное, чтобы наша документация продолжалась, чтобы ответить на ваш вопрос здесь!
Согласно спецификации модуля ECMA (я не собираюсь пытаться найти ссылку, поэтому вам придется доверять мне здесь, потому что ее похоронили),
всякий раз, когда модуль реэкспортирует весь экспорт (независимо от того, используется ли он или не использовался), необходимо оценить и выполнить в случае, если один из этих экспорта создал побочный эффект с другим.
Например, я создал небольшой сценарий с фотографией, чтобы лучше визуализировать случай:
На этой фотографии мы видим, что три отдельных модуля с одним импортом импортируются в один модуль, который затем берет эти экспорт по умолчанию и реэкспортирует их из этого модуля:
Вы можете видеть здесь, что ни один из реэкспортов не производится каждым из них, поэтому (если веб-пакет получил сигнал), мы могли бы опустить экспорт b
и c
из даже отслеживаемых или используемых (размер и время выполнения производительности).
Однако в этом случае мы видим, что экспорт c
"осуществляется" локальными изменениями штата, поскольку он переназначен суммированием b
и a
. Таким образом, (почему спецификация требует для этого), мы должны были бы включать в себя как b
и a
, и любой из его зависимостей в связке.
Мы выбрали "sideEffects: false" как способ сохранить как время компиляции, так и размер сборки, поскольку это позволяет нам мгновенно обрезать (явно) экспорт, который разработчики/авторы библиотеки знают, свободны от побочных эффектов (за счет свойства в package.json, или еще 2-3 строки конфигурации).
Хотя технически этот пример очень примитивен, когда вы начинаете работать с Frameworks или Libraries, которые реэкспортируют кучу модулей на более высокий уровень для Developer Experience (Three.js, Angular, lodash-es и т.д.), Тогда прирост производительности является значительным, когда (если они являются сторонними экспортными модулями экспорта), вы отмечаете их таким образом.
Дополнительные разъяснения:
- Очевидно, что побочные эффекты означают что-то конкретное в fp и включают в себя ведение журнала (консоль или в другом месте) и бросание ошибок. Я предполагаю, что в этом контексте они вполне приемлемы?
В случае, если это пытается решить, да. Пока эффекты, созданные против экспорта модулей, не выполняются другими, что приведет к тому, что обрезка не будет приемлемой.
- Может ли модуль содержать циклические ссылки и по-прежнему использовать
sideEffects: false?
Это должно теоретически.
- Есть ли способ проверить или что модуль может использовать
sideEffects: false
кроме попытки отследить ошибки, вызванные его неправильным использованием?
Не то, чтобы я знал, но это было бы отличным инструментом.
- Существуют ли какие-либо другие факторы, которые препятствовали бы тому, чтобы модуль мог использовать
sideEffects: false
?
Если свойство не находится в package.json
или определено в module.rules
или в mode: production
не задано (которое использует оптимизацию).
Ответ 2
Этот параметр sideEffects
очень расплывчатый и недостаточно описан в документах. Документы в основном напоминают "там флаг sideEffects
для модулей, свободных от каких-либо побочных эффектов".
Консенсус в том, что фраза "не имеет побочных эффектов" может быть дешифрована, поскольку "не говорит о вещах, внешних по отношению к модулю на верхнем уровне".
Мое настоящее понимание заключается в том, что этот флаг 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
приводит к <npm-package>/index.js
что в результирующий <npm-package>/index.js
не './lib/b.js'
файл './lib/b.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'
.
В то же время, если './lib/b.js'
верхнего уровня './lib/b.js'
не выходит за пределы этого *.js
файла, то он не имеет никаких "побочных эффектов":
let a = 1
a = a + 1 + computeSomeValue()
export default a
export const b = a + 1
export const c = b + 1
все это не "побочные эффекты".
И есть окончательный результат: если в пакете 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 файл не включен".