【问题标题】:Building webpack for production - minified dependencies为生产构建 webpack - 最小化依赖项
【发布时间】:2023-03-15 12:18:01
【问题描述】:

假设 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 包的一部分提供,而不是从源代码重新构建?

我在 webpack 配置中看到了解决方案 that use resolve.aliasnoParse ,其中包含指向缩小源文件的硬编码路径,但这不是主要违背了使用 npm 和 webpack 的目的吗?我不想硬编码和维护每个依赖项的缩小构建文件的路径!

我来到这里是因为当我添加 moment.js 时,我的 bundle.js 增加了 2.5mb - 这是 167kb,包括所有语言环境,但其中的源代码包含 2mb 的测试。

编辑

显然,它不仅仅是在最后缩小最终的bundle.js 文件。例如:为什么有人想在最终生产代码中包含数百个不必要的依赖项单元测试?他们没有。这就是为什么大多数库都提供 dist(或类似的)文件夹作为其 npm 模块的一部分的原因。

【问题讨论】:

  • 使用webpack.DefinePlugin设置process.env.NODE_ENV,这将结束开发代码(使用提到的环境变量),如if (process.env.NODE_ENV !== 'production')将被静态评估为if (false),然后被minifier删除作为无法访问的代码。
  • 目前 - 通货膨胀是由加载所有语言环境引起的。如果您不需要所有这些 - 按照stackoverflow.com/q/25384360/251311的建议加载只是必要的
  • “为什么有人要在最终生产代码中包含数百个不必要的依赖项单元测试”——确实没有人这样做。
  • @zerkms (1) 设置 process.env.NODE_ENV 不会导致 webpack 加载缩小的依赖项。 (2) 如果通货膨胀是由于包含语言环境,我会看到 167kb 的通货膨胀,但我看到超过 2mb - 大约是他们的 tests.js 文件 (3) 的大小。
  • 1.如果库实现时考虑到这一点(如 reactjs),它确实如此。如果不是 - 缩小是缩小器的工作,webpack 只是一个加载器。通常,您是否加载源并自己或 dist 缩小它们都无关紧要。前者实际上可能更好,因为您使用 never minifier 版本。 2. 这很奇怪 - 我正在使用 momentjs,而且我的 dev 和 prod 构建中肯定没有测试。

标签: javascript node.js npm webpack build-tools


【解决方案1】:

让我们考虑一下你的时刻包。

你可以随时使用

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

但这不是一个好主意。


你不应该在 webpack 中使用压缩文件

如果你使用

import moment from 'moment';

它将从源代码构建模块。但是如果你在 webpack 配置文件中有缩小过程,它不应该比交付的 .min.js 文件大很多。通常你自己的构建可能比原来的 .min.js 还要小!


暂时实验

在添加moment 后,我测量了bundle.js 的额外大小,它的190 kB 和原始moment/min/moment-with-locales.min.js 大小为207 kB。您的 2.5 MB 可能是您添加了地图(在我的配置中使用地图 moment 权重 2.7 MB)您可以分析 it is build with all locales - 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

如果您只使用这 3 个模块的 .min 版本,您将为您的应用程序添加 50 kB + 25 kB + 45 kB = 120 kB

                   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 kB 添加到您的应用程序中。

【讨论】:

  • 是的!应该是源地图
  • 出色的答案,很好的解释
  • 你花了很多时间写出来,但你没有展示你是如何缩小你的源代码的。您的构建示例在哪里?你所解释的一切都很好,但除非你展示你是如何获得这些缩减文件的,否则它毫无价值。
【解决方案2】:

为什么不直接缩小整个 webpack bundle.js? (source)

webpack -p 构建一次用于生产(缩小)

可能比试图找到某种方法来使用单个包的缩小版本更容易。

【讨论】:

  • 但是我正在重新处理每个依赖项的整个源代码!如果这是公认的方法,为什么大多数 NPM 包都包含预构建文件?
  • 它们包括缩小版,因为很多人使用不同的环境设置。您仍然可以直接require('node_modules/someModule/minified.min.js') 或其他任何方式。为什么在构建过程中重新处理每个依赖项的整个源代码很重要?这是否会以某种方式严重影响您的机器?此外,2.5mb 在应用程序的宏伟计划中非常小。如果我是你,如果没有必要,我不会太在意微优化。
  • 例如:moment.js 包含一个 167kb moment/dist/moment-with-locales.min.js 文件,但 webpack 使用 moment/moment.js 会引入 2mb 的不必要的单元测试!显然,包的所有者提供了单元测试有用的开发源,还提供了一个可分发的、缩小的、测试专用的、优化的文件,用于生产。
  • 我明白了;这就是我正在做的。但这只是没有意义 - 我还没有看到任何开源包这样做......每次构建包时重新编译每个依赖项的整个源代码是否真的是行业标准,或者明确引用(阅读:硬编码)每个依赖项的缩小构建文件?如果是这样,为什么有人会打扰包含构建/缩小的文件,甚至根本没有dist 文件夹?
  • 请再次阅读我的问题。比起“计算能力”,我更关心包含不必要开发代码的最终捆绑包。
猜你喜欢
  • 2010-11-30
  • 2021-07-20
  • 1970-01-01
  • 2019-04-22
  • 2010-11-26
  • 1970-01-01
  • 1970-01-01
  • 2020-02-15
  • 2011-04-18
相关资源
最近更新 更多