前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Webpack 踩坑记 - 配置 externals 和 output

Webpack 踩坑记 - 配置 externals 和 output

作者头像
JSCON简时空
发布2020-03-31 15:16:07
发布2020-03-31 15:16:07
3.8K10
代码可运行
举报
文章被收录于专栏:JSCON简时空JSCON简时空
运行总次数:0
代码可运行

webpack 很强大,提供的能力选项配置也很多好让你满足各种不同的打包场景。

但学习成本也跟着上去了,其中一件让人头疼的是输出时的配置,特别容易让人迷惑;

平时用 webpack 可能不会有太大问题,可一旦你开发的包被别人引用的时候,就会存在问题;我最近遇到这么一个场景耗费我很多时间去重新学习 webpack 的打包输出。

本文总结了自己开发库时依赖共同第三方包时的 externals 和 output 配置项。

1、场景

当你开发的包依赖较大的第三方包(reactreact-dom) 的时候,你一般是把这些大的第三方包 externals 出去:

代码语言:javascript
代码运行次数:0
运行
复制
{
  externals: {
    'react': 'React',
    'react-dom': 'ReactDOM'
  }
}

假如你开发了 A、B 两个插件

  • A 依赖 B 、reactreact-dom
  • B 只依赖 reactreact-dom

deps

如果你想发布 A 的话,有两种策略,要么直接依赖(将 B 写到 dependencies 中),要么像 reactreact-dom 一样 externals 掉 B 包(有可能 B 的包也很大)。

请问此时该如何 webpack 配置来支持常用的两种模式?

2、如何解决?

先看一下 webpack 官方在进行打包时候,是根据 package.json 中的 mainFields 字段指定依据哪个字段中的 路径 找到第三方包的,而 externals 字段则是指定以何种方式引入第三方包

客观情况如下:

  • 我们通常的是会把打出来的包放在 browser 字段中;
  • webpack 打包时,选择依赖包是根据 resolve.mainFields 字段找到指定的路径把代码打进去的;默认配置是 ['browser', 'module', 'main'],也就是说会优先找 browser 的字段指定的路径
  • libraryTarget 配置如何暴露 library。如果不设置 library, 那这个library就不暴露。就相当于一个自执行函数
  • libraryTarget 决定了你的 library 运行在哪个环境,哪个环境也就决定了你哪种模式去加载所引入的额外的包。也就是说,externals 应该和 libraryTarget 保持一致。library 运行在浏览器中的,你设置 externals 的模式为 commonjs,那代码肯定就运行不了了。

我们一般容易混淆的是 externals 的使用,比如对 react-dom 的 externals,经常会看到两种写法:

  • {'react-dom': 'reactDom'}
  • {'react-dom': 'react-dom'}

这两种的区别,其实是和你想将第三方以怎样的方式打入到你最终代码有关

还有一种 对象形式,那种是只应用在 umd 的打包方式中

2.1、externals 资料

  • externals:官方文档
  • webpack externals 深入理解:偏向总结
  • 深入浅出webpack之externals的使用:以打包之后的源码拆解开来讲解

2.2、mainFields 参考资料

先通读一下官方文档中的 resolve.mainFields,想看中文的可以看这个链接 解析(resolve)

附其他参考资料:

  • 深入浅出webpack学习(5)--Resolve:详细解读 webpack 中的这个 resolve 字段用法,相比官方文档多了举例
  • package-browser-field-spec:package.json 中 browser 字段的标准写法。
  • 深入理解webpack如何解析代码路径:掘金上的文章,讲解 webpack 的代码路径解析规则

顺带收集几个相关 issue,看看别人遇到的问题现在你是否可以解决:

  • `browser` vs `module` fields in `package.json`:回答了当 package.json 同时包含 browser, module & main fields 字段时候,如何指定我们 webpack 不用默认的 browser 字段

3、解决方案

使用两份输出配置项,主要更改 webpack 的打包的配置项中的 externalsoutput 这两个字段。

3.1、B 包的配置如下

第一份配置是针对 .umd.js 文件的(别人用于 externals ,然后通过 script 脚本标签)

代码语言:javascript
代码运行次数:0
运行
复制
{
    externals: {
      'react': 'React',
      'react-dom': 'ReactDOM'
    },
    output: {
      filename: 'index.umd.js',
      libraryTarget: 'umd',
      library: 'extB',
      path: path.resolve(__dirname, 'dist'),
      umdNamedDefine: true
    }
}

第二份配置是针对 .browser.js 文件的(别人使用的时候直接放在 dependencies中,也会最终打包进去)

代码语言:javascript
代码运行次数:0
运行
复制
{
    externals: {
      'react': 'react', // 这里更改了
      'react-dom': 'react-dom' // 这里更改了
    },
    output: {
      filename: 'index.browser.js', // 这里更改了
      libraryTarget: 'umd',
      library: 'extB',
      path: path.resolve(__dirname, 'dist'),
      umdNamedDefine: true
    }
}

同时还得更改当前文件夹的 package.json 的对应字段如下:

代码语言:javascript
代码运行次数:0
运行
复制
{
  ...
  "main": "dist/index.umd.js",
  "module": "dist/index.umd.js",
  "browser": "dist/index.browser.js",
  ...
}

3.2、A 包的配置

首先,无论是否 externals,都需要在 package.json 中填完对 B 依赖的信息(可以根据实际情况放在 dependencies 字段或者 peerDependencies 字段)

情况 1 :A 包最终要把 B 包打入到最终代码中去,那么和 B 包的 webpack 配置是一样的;

情况 2:A 包最终要把 B 包 externals 掉,基本配置是一样的,只不过有额外的两部需要操作:

  1. 在上述的 externals 中新增 B 包的 externals 配置项(需要区别 {'B': 'B'} 和 {'B': 'extB'})
  2. 在页面中引入 cdn 资源 http://xxx/index.umd.js (注意不是 http://xxx/index.browser.js

4、简化的写法

我们看到上述这么写是能成功的,官方考虑到了这种情况,所以针对 umd 的打包方式,推出 对象形式,让你统一上述两种配置文件(但这种配置只能应用在 umd 的打包方式中);

最终我们把上述两份打包配置合并成一份:

代码语言:javascript
代码运行次数:0
运行
复制
{
    externals: {
      'react': 'react'
      'react-dom': {
        commonjs: 'react-dom', // 这里更改了
        commonjs2: 'react-dom', // 这里更改了
        amd: 'react-dom', // 这里更改了
        root: 'reactDom'
      }
    },
    output: {
      filename: 'index.umd.js', // 这里更改了
      libraryTarget: 'umd',
      library: 'extB',
      path: path.resolve(__dirname, 'dist'),
      umdNamedDefine: true
    }
}

这样就省去了 index.browser.js 这个文件,增加了兼容性。

5、总结

这篇文章是我一整天掉在 webpack 坑里,来回调试了半天所得出的经验总结,特此总结形成文章,方便以后查找。

阅读原文获取更多的信息

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-04-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 JSCON简时空 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1、场景
  • 2、如何解决?
    • 2.1、externals 资料
    • 2.2、mainFields 参考资料
  • 3、解决方案
    • 3.1、B 包的配置如下
    • 3.2、A 包的配置
  • 4、简化的写法
  • 5、总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档