Webpack 和外部库:ProvidePlugin vs entry vs global import?

Posted

技术标签:

【中文标题】Webpack 和外部库:ProvidePlugin vs entry vs global import?【英文标题】:Webpack and External Libs: ProvidePlugin vs entry vs global import? 【发布时间】:2017-02-14 18:00:22 【问题描述】:

1。 ProvidePlugin()

看起来是一种常用的方法。有一个关于它的gist,展示了如何将 whatwg-fetch polyfill 包含到 Webpack 构建中。 *** 上的很多答案都使用它here 和here。

new webpack.ProvidePlugin(
  '$': 'jquery',
  'jQuery': 'jquery',
  'fetch': 'imports?this=>global!exports?global.fetch!whatwg-fetch'
)

????优点

有效。 (如果我遗漏了什么,请更新此列表)

????缺点

需要跟踪 Webpack 配置中的全局库。

2。 entry: [...]

当我在this gist 中发现这种方法时,我有点惊讶,但它同样有效。

entry: [
    'babel-polyfill',
    'whatwg-fetch',
    'jquery',
    'webpack-hot-middleware/client',
    path.join(process.cwd(), 'app/app.js')
],

????优点

有效。 我可以完全放弃ProvidePlugin()

????缺点

需要跟踪 Webpack 配置中的全局库。

3。***import

这个很简单,看这个app.js 例子。该文件是 React 应用程序的入口点。

/**
 * app.js
 */

import 'whatwg-fetch';
import 'babel-polyfill';
import 'jquery';

????优点

同样有效。 轻松添加/删除。无需修改 Webpack 配置。

????缺点

看起来这种方法不能单独用于 jQuery 插件,例如bootstrap.js.

观察:在所有三种方法中,我没有注意到包大小有任何变化。

有没有一种推荐的使用 Webpack(和 React)处理全局库的方法?这些解决方案中的任何一个都会导致服务器端渲染出现问题吗?

谢谢!

【问题讨论】:

如果您有多个入口点,entry 根本不是一个好主意。 【参考方案1】:

我不建议将库公开为全局库,除非您确实需要它,即模块系统的重点是显式声明依赖关系,例如

// app.js
import $ from 'jquery';
$.ajax(...);

如果您在全局上确实需要 jQuery,因为第三方脚本在您的页面上需要它,或者可能用于在控制台中进行调试,那么这里有一些关于您列出的方法的信息:

提供插件

ProvidePlugin 不会在全局上公开 jQuery,并且真正旨在修复错误地依赖全局模块的存在的第三方模块,因此我不建议这样做,例如

// app.js
$.ajax(...);

被有效地转译成:

// app.js
require('jquery').ajax(...);

入口和***导入

这些方法不适用于常规的 UMD 模块,例如 jQuery,因为 jQuery 足够聪明,不会在由 commonjs / amd / es6 感知加载器加载时将自身暴露在全局上。

然而,这两种方法非常适合具有副作用的模块,例如 babel-polyfill / whatwg-fetch,因为它们不会导出任何内容,它们会固有地改变全局环境。


因此,我对 jQuery 的建议是使用 expose-loader,它旨在全局公开模块导出,例如

// webpack.config.js

    module: 
        loaders: [
            test: require.resolve('jquery'),
            loader: 'expose-loader?jQuery!expose-loader?$'
        ]
    

你仍然需要在你的应用代码中导入它:

// app.js
import $ from 'jquery';
$.ajax(...)

但如果绝对必要,它可以在全局上供页面上的其他脚本访问:

// console
window.$
window.jQuery

注意:从技术上讲,您可以在使用暴露加载器时在入口点中只 import 'jquery' 一次,然后在其他模块中依赖全局。

不过,正如我所说,如果您不需要公开一个模块,即使您当前碰巧在其他所有模块中使用它,也不建议公开它。

【讨论】:

【参考方案2】:

如果您在使用ProvidePlugin 时在一页中包含多个包(入口点),只需发现提供的lib 将被覆盖。例如 RoR 和 Webpacker,但我认为这并不重要。

例如,您的布局中有:

  javascript_pack_tag 'application',
                      'metronic'

在配置中你有:

  environment.plugins.append('Provide', new webpack.ProvidePlugin(
      $: 'jquery',
      jQuery: 'jquery',
      "window.jQuery": "jquery",
      "window.$": "jquery",
      _: 'underscore',
      Handlebars: 'handlebars'
  ));

如果在application.js 中你需要库,它会改变 JQuery,你将在metronic.js 和浏览器中失去所有这些突变,即使你使用暴露加载器公开 JQuery。

如果我错了,请纠正我,ProvidePlugin 可能只是在每个入口点导入库。

【讨论】:

以上是关于Webpack 和外部库:ProvidePlugin vs entry vs global import?的主要内容,如果未能解决你的问题,请参考以下文章

由于外部库,Webpack 构建非常缓慢

使用 React Router 和 Webpack 2 如何仅在某些路由上需要外部库?

如何使外部库在 webpack 中工作

使用 Vue Web 组件访问 Webpack 外部库

使用 WebPack + TypeScript 定义导入的外部模块

使用 laravel mix 设置外部库