谈谈webpack对npm模块导入的解析

探讨了在使用Webpack构建项目时,遇到的react-split-pane模块更新导致的commonjs与ESModule导入方式冲突问题。分析了Webpack的resolve.mainFields配置对模块解析的影响,并提出了通过修改导入方式或调整配置来解决此问题的方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题描述

在一次运营后台的常规更新时,发现有一个外部依赖包不能正常工作。经排查发现,react-split-pane在前几天发了一个新版0.1.81,该版本同时提供commonjses module两种包导入方式:
1531204143470-612af1fb-84e6-4f81-8da0-b6
 
原来我们采用的CMD写法 const ReactSplitPane = require('react-split-pane') 失效了。 
 

原因分析

 
翻查webpack官方文档后,发现webpack会对包导入会进行解析,不管是采用CMD方式还是ES6 import方式。 解析的依据是配文件的 resolve.mainFields 属性, 该属性用于配置采用package.json的哪个字段作为模块的入口文件。
 
以react-split-pane 模块为例,当 resolve.mainFields = ['browser', 'module', 'main'] 时 , webpack在解析 如 const ReactSplitPane = require('react-split-pane')
import ReactSplitPane from 'react-split-pane' 的时候,会优先使用 dist/index.esm.js 。 由于采用
export default 导出的模块必须使用 import x from 'xx' 的方式(或 使用 const x = require('x').default的方式) 导入, 否则导入后的模块会引用不正确.
 
如果 resolve.mainFiels 没有显式指定,则根据webpack的 target 的取值来决定其默认值
 
  • 当 target的值为 webworkerweb 或者没有指定时,mainFields = ['browser', 'module', 'main']
  • 当 target 为其他任意值(包括node), mainFields = ['module', 'main']
 

后续

 
随着ES6的普及,相信会有越来越多的第三方模块提供 es module 版本,而mainFields的默认值中, module 总是排在 main之前 ,因此类似的问题还会发生。要从根本上解决这个问题,有以下的办法
 
  • 借助 js-codemod等工具,将所有对第三方模块的导入方式 从commonjs 方式改成 ES6 import方式。 因为采用module.exports= .. 导出的包均可以使用import x from '...' 的方式导入,但export default x 导出的包不能直接用require('x')导入.
  • 显式指定mainFields , 把main的优先级提高 或干脆不使用es module。但这种做法无法利用webpack提供的tree shaking 能力减少构建后bundle的体积, 也无法用上一些浏览器已支持的es6特性
  • 利用npm shrinkwrap锁定包版本,缺点是无法及时享受依赖bugfix更新
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值