为何在Webpack入口文件中使用window会影响React热重载?
这个问题我之前踩过坑,核心原因和Webpack热重载(HMR)的工作机制、模块依赖追踪逻辑密切相关,具体可以拆解成这几点:
静态依赖分析失效:Webpack的HMR是靠静态扫描模块间的导入导出关系来追踪依赖的,它只能识别模块系统内的依赖项。而
window.__DEV__是直接访问全局对象的属性,Webpack没法通过静态分析识别出哪些模块依赖这个全局变量,当相关代码变动时,HMR就没法精准定位需要更新的模块,自然热重载就出问题了。模块缓存异常:开发环境下Webpack会缓存已加载的模块。当你在代码里直接读取
window.__DEV__时,这个值会在模块初始化时被读取一次并缓存起来。后续热重载更新模块时,模块可能不会重新读取这个全局变量,依然沿用旧的缓存值,导致更新后的代码行为不符合预期,甚至引发报错。破坏React热重载的纯净性要求:React的热重载工具(比如react-hot-loader)要求组件模块尽量保持“纯净”——也就是依赖关系清晰、没有全局状态的意外引入。直接使用
window全局变量会让模块的依赖变得模糊,react-hot-loader没法正确替换更新后的组件模块,甚至无法保留组件的状态,最终导致热重载失效或者页面异常。
解决办法
最规范的方式是用Webpack的DefinePlugin来注入__DEV__变量,这样Webpack可以静态替换这个变量,完全不影响HMR的正常工作:
// webpack.config.js const webpack = require('webpack'); module.exports = { // ...其他配置项 plugins: [ new webpack.DefinePlugin({ __DEV__: JSON.stringify(process.env.NODE_ENV === 'development') }) ] };
之后在代码里直接使用__DEV__即可,不用再挂载到window上:
// index.js const __DEV__ = __DEV__; // 直接使用DefinePlugin注入的变量
这样Webpack能正常追踪依赖,React的热重载也能稳定运行了。
内容的提问来源于stack exchange,提问作者SKing7

