Создание webpack для производства - минимизированные зависимости

Скажем, есть модуль на npm, называемый "awesomepackage". Я могу зарегистрировать его как зависимость моего приложения через package.json следующим образом:

npm i --save awesomepackage

Проверяя мою папку node_modules, я вижу папку с именем "awesomepackage", которая выглядит так:

- index.js
- package.json
- README.md
- lib/
    - awesomepackage.min.js

и я могу использовать пакет внутри своего собственного приложения так:

import {AwesomeThing} from 'awesomepackage';

Мой вопрос:

Когда я создаю свое приложение с помощью webpack, мой последний bundle.js всегда содержит исходный код из node_modules/awesomepackage/index.js - независимо от каких-либо переменных среды, которые у меня установлены (например, NODE_ENV=production).

Есть ли способ сказать webpack использовать предварительно созданные файлы (например, node_modules/awesomepackage/lib/awesomepackage.min.js), если они отправлены как часть пакета NPM, вместо повторного создания из источника?

Я видел решения которые use resolve.alias и noParse в конфигурации webpack с жестко запрограммированными путями в минированные исходные файлы, но разве это не означает, что в основном преследует цель использования npm и webpack? Я не хочу, чтобы жестко кодировать и поддерживать пути к каждому зависимому файлу сборки!

Я пришел сюда, потому что мой bundle.js подскочил на 2,5 Мб, когда я добавил moment.js - который был изменен на 167kb, включая все локали, но из которых исходный код включает в себя 2 МБ тестов.

Изменить

Понятно, что это больше, чем просто финализация окончательного файла bundle.js в конце. Например: почему кто-то хочет включать сотни ненужных модульных тестов для зависимостей в конечный производственный код? Они этого не делают. Именно поэтому большинство библиотек предоставляют папку dist (или аналогичную) как часть своего модуля npm.

Ответ 1

Давайте рассмотрим ваш пакет момента.

Вы всегда можете использовать

import moment from 'node_modules/moment/min/moment-with-locales.min.js'

Но это не очень хорошая идея.


Нельзя использовать мини файлы в webpack

Если вы используете

import moment from 'moment';

он построит модуль из источника. Но если у вас есть процесс minification в файле конфигурации webpack, он не должен быть намного больше, чем отправленные .min.js файлы. Часто ваша собственная сборка может быть даже меньше оригинальной .min.js!


Эксперимент для момента

Я измеряю дополнительный размер моего bundle.js после добавления moment, а его 190 кБ и оригинальном moment/min/moment-with-locales.min.js размере 207 кБ. Ваш 2,5 МБ, вероятно, добавляет карты (в моей конфигурации с картами moment весом 2,7 МБ). Вы можете проанализировать, что он построен со всеми локалями - webpack может распечатать эту статистику (размеры до мини-кода):

 [373] ./~/moment/moment.js 135 kB {0} [built]
 [374] ./~/moment/locale/af.js 2.62 kB {0} [optional] [built]
 [375] ./~/moment/locale/ar-ma.js 2.12 kB {0} [optional] [built]
 [376] ./~/moment/locale/ar-sa.js 3.16 kB {0} [optional] [built]
 [377] ./~/moment/locale/ar-tn.js 1.97 kB {0} [optional] [built]
 [378] ./~/moment/locale/ar.js 4.59 kB {0} [optional] [built]
 [379] ./~/moment/locale/az.js 3.35 kB {0} [optional] [built]
 [380] ./~/moment/locale/be.js 4.86 kB {0} [optional] [built]
 [381] ./~/moment/locale/bg.js 3.1 kB {0} [optional] [built]
 [382] ./~/moment/locale/bn.js 3.62 kB {0} [optional] [built]
 [383] ./~/moment/locale/bo.js 3.87 kB {0} [optional] [built]
 [384] ./~/moment/locale/br.js 3.44 kB {0} [optional] [built]
 [385] ./~/moment/locale/bs.js 4.7 kB {0} [optional] [built]
 [386] ./~/moment/locale/ca.js 2.97 kB {0} [optional] [built]
 [387] ./~/moment/locale/cs.js 6.4 kB {0} [optional] [built]
 [388] ./~/moment/locale/cv.js 2.33 kB {0} [optional] [built]
 [389] ./~/moment/locale/cy.js 2.92 kB {0} [optional] [built]
 [390] ./~/moment/locale/da.js 2.07 kB {0} [optional] [built]
 [391] ./~/moment/locale/de-at.js 3.03 kB {0} [optional] [built]
 [392] ./~/moment/locale/de.js 2.95 kB {0} [optional] [built]
 [393] ./~/moment/locale/dv.js 2.69 kB {0} [optional] [built]
 [394] ./~/moment/locale/el.js 3.73 kB {0} [optional] [built]
 [395] ./~/moment/locale/en-au.js 2.32 kB {0} [optional] [built]
 [396] ./~/moment/locale/en-ca.js 2.2 kB {0} [optional] [built]
 [397] ./~/moment/locale/en-gb.js 2.38 kB {0} [optional] [built]
 [398] ./~/moment/locale/en-ie.js 2.37 kB {0} [optional] [built]
 [399] ./~/moment/locale/en-nz.js 2.32 kB {0} [optional] [built]
 [400] ./~/moment/locale/eo.js 2.67 kB {0} [optional] [built]
 [401] ./~/moment/locale/es.js 2.97 kB {0} [optional] [built]
 [402] ./~/moment/locale/et.js 3.14 kB {0} [optional] [built]
 [403] ./~/moment/locale/eu.js 2.39 kB {0} [optional] [built]
 [404] ./~/moment/locale/fa.js 3.27 kB {0} [optional] [built]
 [405] ./~/moment/locale/fi.js 3.86 kB {0} [optional] [built]
 [406] ./~/moment/locale/fo.js 2.1 kB {0} [optional] [built]
 [407] ./~/moment/locale/fr-ca.js 2.09 kB {0} [optional] [built]
 [408] ./~/moment/locale/fr-ch.js 2.25 kB {0} [optional] [built]
 [409] ./~/moment/locale/fr.js 2.24 kB {0} [optional] [built]
 [410] ./~/moment/locale/fy.js 2.64 kB {0} [optional] [built]
 [411] ./~/moment/locale/gd.js 2.63 kB {0} [optional] [built]
 [412] ./~/moment/locale/gl.js 2.77 kB {0} [optional] [built]
 [413] ./~/moment/locale/he.js 3.41 kB {0} [optional] [built]
 [414] ./~/moment/locale/hi.js 3.88 kB {0} [optional] [built]
 [415] ./~/moment/locale/hr.js 4.83 kB {0} [optional] [built]
 [416] ./~/moment/locale/hu.js 4 kB {0} [optional] [built]
 [417] ./~/moment/locale/hy-am.js 3.22 kB {0} [optional] [built]
 [418] ./~/moment/locale/id.js 2.94 kB {0} [optional] [built]
 [419] ./~/moment/locale/is.js 4.43 kB {0} [optional] [built]
 [420] ./~/moment/locale/it.js 2.46 kB {0} [optional] [built]
 [421] ./~/moment/locale/ja.js 2.21 kB {0} [optional] [built]
 [422] ./~/moment/locale/jv.js 2.94 kB {0} [optional] [built]
 [423] ./~/moment/locale/ka.js 3.15 kB {0} [optional] [built]
 [424] ./~/moment/locale/kk.js 2.68 kB {0} [optional] [built]
 [425] ./~/moment/locale/km.js 2.02 kB {0} [optional] [built]
 [426] ./~/moment/locale/ko.js 2 kB {0} [optional] [built]
 [427] ./~/moment/locale/ky.js 2.69 kB {0} [optional] [built]
 [428] ./~/moment/locale/lb.js 4.92 kB {0} [optional] [built]
 [429] ./~/moment/locale/lo.js 2.32 kB {0} [optional] [built]
 [430] ./~/moment/locale/lt.js 4.37 kB {0} [optional] [built]
 [431] ./~/moment/locale/lv.js 3.9 kB {0} [optional] [built]
 [432] ./~/moment/locale/me.js 4.1 kB {0} [optional] [built]
 [433] ./~/moment/locale/mk.js 3.11 kB {0} [optional] [built]
 [434] ./~/moment/locale/ml.js 2.81 kB {0} [optional] [built]
 [435] ./~/moment/locale/mr.js 5.39 kB {0} [optional] [built]
 [436] ./~/moment/locale/ms-my.js 2.86 kB {0} [optional] [built]
 [437] ./~/moment/locale/ms.js 2.85 kB {0} [optional] [built]
 [438] ./~/moment/locale/my.js 2.73 kB {0} [optional] [built]
 [439] ./~/moment/locale/nb.js 2.23 kB {0} [optional] [built]
 [440] ./~/moment/locale/ne.js 3.81 kB {0} [optional] [built]
 [441] ./~/moment/locale/nl.js 2.63 kB {0} [optional] [built]
 [442] ./~/moment/locale/nn.js 2.09 kB {0} [optional] [built]
 [443] ./~/moment/locale/pa-in.js 4.01 kB {0} [optional] [built]
 [444] ./~/moment/locale/pl.js 3.94 kB {0} [optional] [built]
 [445] ./~/moment/locale/pt-br.js 2.23 kB {0} [optional] [built]
 [446] ./~/moment/locale/pt.js 2.34 kB {0} [optional] [built]
 [447] ./~/moment/locale/ro.js 2.61 kB {0} [optional] [built]
 [448] ./~/moment/locale/ru.js 7.08 kB {0} [optional] [built]
 [449] ./~/moment/locale/se.js 2.23 kB {0} [optional] [built]
 [450] ./~/moment/locale/si.js 2.43 kB {0} [optional] [built]
 [451] ./~/moment/locale/sk.js 5.49 kB {0} [optional] [built]
 [452] ./~/moment/locale/sl.js 6.16 kB {0} [optional] [built]
 [453] ./~/moment/locale/sq.js 2.45 kB {0} [optional] [built]
 [454] ./~/moment/locale/sr-cyrl.js 4.1 kB {0} [optional] [built]
 [455] ./~/moment/locale/sr.js 4.09 kB {0} [optional] [built]
 [456] ./~/moment/locale/ss.js 3.12 kB {0} [optional] [built]
 [457] ./~/moment/locale/sv.js 2.4 kB {0} [optional] [built]
 [458] ./~/moment/locale/sw.js 2.08 kB {0} [optional] [built]
 [459] ./~/moment/locale/ta.js 4.21 kB {0} [optional] [built]
 [460] ./~/moment/locale/te.js 3.09 kB {0} [optional] [built]
 [461] ./~/moment/locale/th.js 2.4 kB {0} [optional] [built]
 [462] ./~/moment/locale/tl-ph.js 2.14 kB {0} [optional] [built]
 [463] ./~/moment/locale/tlh.js 4.09 kB {0} [optional] [built]
 [464] ./~/moment/locale/tr.js 2.9 kB {0} [optional] [built]
 [465] ./~/moment/locale/tzl.js 3.59 kB {0} [optional] [built]
 [466] ./~/moment/locale/tzm-latn.js 2.11 kB {0} [optional] [built]
 [467] ./~/moment/locale/tzm.js 2.06 kB {0} [optional] [built]
 [468] ./~/moment/locale/uk.js 5.4 kB {0} [optional] [built]
 [469] ./~/moment/locale/uz.js 2.03 kB {0} [optional] [built]
 [470] ./~/moment/locale/vi.js 2.71 kB {0} [optional] [built]
 [471] ./~/moment/locale/x-pseudo.js 2.5 kB {0} [optional] [built]
 [472] ./~/moment/locale/zh-cn.js 4.35 kB {0} [optional] [built]
 [473] ./~/moment/locale/zh-tw.js 3.12 kB {0} [optional] [built]
 [474] ./~/moment/locale ^\.\/.*$ 2.41 kB {0} [optional] [built]

Итак, почему ваша пользовательская сборка меньше? Вы можете использовать более агрессивную оценку. Моя сборка дает мне эту информацию (возможно, в этот момент она потеряет некоторый вес):

Condition always true [./~/moment/moment.js:8,0]
Condition always true [./~/moment/locale/af.js:6,0]
Condition always true [./~/moment/locale/ar-ma.js:7,0]
Condition always true [./~/moment/locale/ar-sa.js:6,0]
Condition always true [./~/moment/locale/ar-tn.js:5,0]
Condition always true [./~/moment/locale/ar.js:8,0]
Condition always true [./~/moment/locale/az.js:6,0]
Condition always true [./~/moment/locale/be.js:8,0]
Condition always true [./~/moment/locale/bg.js:6,0]
Condition always true [./~/moment/locale/bn.js:6,0]
Condition always true [./~/moment/locale/bo.js:6,0]
Condition always true [./~/moment/locale/br.js:6,0]
Condition always true [./~/moment/locale/bs.js:7,0]
Condition always true [./~/moment/locale/ca.js:6,0]
Condition always true [./~/moment/locale/cs.js:6,0]
Dropping unreachable code [./~/moment/locale/cs.js:31,0]
Dropping unreachable code [./~/moment/locale/cs.js:40,0]
Dropping unreachable code [./~/moment/locale/cs.js:49,0]
Dropping unreachable code [./~/moment/locale/cs.js:58,0]
Dropping unreachable code [./~/moment/locale/cs.js:67,0]
Condition always true [./~/moment/locale/cv.js:6,0]
Condition always true [./~/moment/locale/cy.js:6,0]
Condition always true [./~/moment/locale/da.js:6,0]
Condition always true [./~/moment/locale/de-at.js:9,0]
Condition always true [./~/moment/locale/de.js:8,0]
Condition always true [./~/moment/locale/dv.js:6,0]
Condition always true [./~/moment/locale/el.js:6,0]
Condition always true [./~/moment/locale/en-au.js:5,0]
Condition always true [./~/moment/locale/en-ca.js:6,0]
Condition always true [./~/moment/locale/en-gb.js:6,0]
Condition always true [./~/moment/locale/en-ie.js:6,0]
Condition always true [./~/moment/locale/en-nz.js:5,0]
Condition always true [./~/moment/locale/eo.js:8,0]
Condition always true [./~/moment/locale/es.js:6,0]
Condition always true [./~/moment/locale/et.js:7,0]
Condition always true [./~/moment/locale/eu.js:6,0]
Condition always true [./~/moment/locale/fa.js:6,0]
Condition always true [./~/moment/locale/fi.js:6,0]
Condition always true [./~/moment/locale/fo.js:6,0]
Condition always true [./~/moment/locale/fr-ca.js:6,0]
Condition always true [./~/moment/locale/fr-ch.js:6,0]
Condition always true [./~/moment/locale/fr.js:6,0]
Condition always true [./~/moment/locale/fy.js:6,0]
Condition always true [./~/moment/locale/gd.js:6,0]
Condition always true [./~/moment/locale/gl.js:6,0]
Condition always true [./~/moment/locale/he.js:8,0]
Condition always true [./~/moment/locale/hi.js:6,0]
Condition always true [./~/moment/locale/hr.js:6,0]
Condition always true [./~/moment/locale/hu.js:6,0]
Dropping unused variable suffix [./~/moment/locale/hu.js:16,0]
Condition always true [./~/moment/locale/hy-am.js:6,0]
Condition always true [./~/moment/locale/id.js:7,0]
Condition always true [./~/moment/locale/is.js:6,0]
Condition always true [./~/moment/locale/it.js:7,0]
Condition always true [./~/moment/locale/ja.js:6,0]
Condition always true [./~/moment/locale/jv.js:7,0]
Condition always true [./~/moment/locale/ka.js:6,0]
Condition always true [./~/moment/locale/kk.js:6,0]
Condition always true [./~/moment/locale/km.js:6,0]
Condition always true [./~/moment/locale/ko.js:10,0]
Condition always true [./~/moment/locale/ky.js:6,0]
Condition always true [./~/moment/locale/lb.js:6,0]
Condition always true [./~/moment/locale/lo.js:6,0]
Condition always true [./~/moment/locale/lt.js:6,0]
Condition always true [./~/moment/locale/lv.js:7,0]
Condition always true [./~/moment/locale/me.js:6,0]
Condition always true [./~/moment/locale/mk.js:6,0]
Condition always true [./~/moment/locale/ml.js:6,0]
Condition always true [./~/moment/locale/mr.js:7,0]
Condition always true [./~/moment/locale/ms-my.js:6,0]
Condition always true [./~/moment/locale/ms.js:6,0]
Condition always true [./~/moment/locale/my.js:6,0]
Condition always true [./~/moment/locale/nb.js:7,0]
Condition always true [./~/moment/locale/ne.js:6,0]
Condition always true [./~/moment/locale/nl.js:6,0]
Condition always true [./~/moment/locale/nn.js:6,0]
Condition always true [./~/moment/locale/pa-in.js:6,0]
Condition always true [./~/moment/locale/pl.js:6,0]
Condition always true [./~/moment/locale/pt-br.js:6,0]
Condition always true [./~/moment/locale/pt.js:6,0]
Condition always true [./~/moment/locale/ro.js:7,0]
Condition always true [./~/moment/locale/ru.js:8,0]
Condition always true [./~/moment/locale/se.js:6,0]
Condition always true [./~/moment/locale/si.js:6,0]
Condition always true [./~/moment/locale/sk.js:7,0]
Dropping unreachable code [./~/moment/locale/sk.js:32,0]
Dropping unreachable code [./~/moment/locale/sk.js:41,0]
Dropping unreachable code [./~/moment/locale/sk.js:50,0]
Dropping unreachable code [./~/moment/locale/sk.js:59,0]
Dropping unreachable code [./~/moment/locale/sk.js:68,0]
Condition always true [./~/moment/locale/sl.js:6,0]
Condition always true [./~/moment/locale/sq.js:8,0]
Condition always true [./~/moment/locale/sr-cyrl.js:6,0]
Condition always true [./~/moment/locale/sr.js:6,0]
Condition always true [./~/moment/locale/ss.js:6,0]
Condition always true [./~/moment/locale/sv.js:6,0]
Condition always true [./~/moment/locale/sw.js:6,0]
Condition always true [./~/moment/locale/ta.js:6,0]
Condition always true [./~/moment/locale/te.js:6,0]
Condition always true [./~/moment/locale/th.js:6,0]
Condition always true [./~/moment/locale/tl-ph.js:6,0]
Condition always true [./~/moment/locale/tlh.js:6,0]
Condition always true [./~/moment/locale/tr.js:7,0]
Condition always true [./~/moment/locale/tzl.js:6,0]
Condition always true [./~/moment/locale/tzm-latn.js:6,0]
Condition always true [./~/moment/locale/tzm.js:6,0]
Condition always true [./~/moment/locale/uk.js:7,0]
Condition always true [./~/moment/locale/uz.js:6,0]
Condition always true [./~/moment/locale/vi.js:6,0]
Condition always true [./~/moment/locale/x-pseudo.js:6,0]
Condition always true [./~/moment/locale/zh-cn.js:7,0]
Condition always true [./~/moment/locale/zh-tw.js:6,0]

Повторное использование общих модулей

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

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

                   size

module1            20 kB 
  dependencies
    - moduleA      10 kB 
    - moduleB      15 kB
    - moduleC      5  kB
module1.min        50 kB

module2            10 kB 
  dependencies
    - moduleA      10 kB 
    - moduleD      5  kB
module2.min        25 kB

module3            30 kB 
  dependencies
    - moduleA      10 kB 
    - moduleC      5  kB
module3.min        45 kB

Если вы будете использовать только .min версию этих 3 модулей, вы добавите к вашему приложению 50 кБ + 25 кБ + 45 кБ = 120 кБ.

                   size

module1            20 kB 
  dependencies
    - moduleA      10 kB  
    - moduleB      15 kB 
    - moduleC      5  kB 
module1.min        50 kB  <-- this

module2            10 kB  
  dependencies
    - moduleA      10 kB 
    - moduleD      5  kB 
module2.min        25 kB  <-- this

module3            30 kB  
  dependencies
    - moduleA      10 kB 
    - moduleC      5  kB
module3.min        45 kB  <-- this

С другой стороны, если вы будете строить с исходными файлами, общие модули будут добавляться только один раз. Не как ранее moduleA был включен 3 раза, а moduleC 2 раза. Это время будет добавлено к вашему приложению:

                   size

module1            20 kB  <-- this
  dependencies
    - moduleA      10 kB  <-- this
    - moduleB      15 kB  <-- this
    - moduleC      5  kB  <-- this
module1.min        50 kB

module2            10 kB  <-- this
  dependencies
    - moduleA      10 kB 
    - moduleD      5  kB  <-- this
module2.min        25 kB

module3            30 kB  <-- this
  dependencies
    - moduleA      10 kB 
    - moduleC      5  kB
module3.min        45 kB

И, наконец, с помощью этого подхода вы добавляете 95 кБ к вашему приложению.

Ответ 2

Почему бы не просто уменьшить весь веб-пакет bundle.js? (источник)

webpack -p для сборки один раз для производства (минификация)

Наверное, проще, чем пытаться найти способ использования мини-версии отдельных пакетов.