React系列——react-hot-loader bug排除指南(翻译)

2018-01-13 11:04:44来源:segmentfault作者:二月人点击

分享
原文

react-hot-loader故障排除指南


翻译

这个文件可以作为设置React Hot Loader的常见问题的repository,以及解决方案。知道一个问题?你可以随意提交一个PR。


它应该是什么样子?

页面加载时



保存一个文件时



如果您看不到某些message或某些request,或者某些requests失败,则表示配置不正确。将您的设置与React Hot Boilerplate进行比较可能会帮助您发现错误。


常见的TypeScript错误


如果您是TypeScript用户,使用HMR进行设置,将别名模块作为任何类似的东西并不罕见,像下面这样:


const anyModule = module as any;
if (anyModule.hot) {
anyModule.hot.accept('./app', () => render(App));
}

千万不要这样做!!每次进行更改时都会导致整页重新加载。你应该改成下面这种写法:


if ((module as any).hot) {
(module as any).hot.accept('./app', () => render(App));
}

或者


declare const module: any;
if (module.hot) {
module.hot.accept('./app', () => render(App));
}

然后,你就能在控制台看到正确的输出了


[HMR] Updated modules:
// ...
[HMR] App is up to date.
不能build
1、Cannot resolve 'file' or 'directory' react/lib/ReactMount

如果你使用预编译的React而不是react npm包,React Hot Loader配置将需要一些调整。请参考 Usage with External React(链接好像已经不准确了)。


确保你的Webpack.config的resolve.extensions部分中有'.js',否则Webpack将无法在require中明确指定扩展名的情况下找到任何JS文件。


2、SyntaxError: 'import' and 'export' may only appear at the top level

如果您将React Hot Loader与Babel(ex 6to5)一起使用,请确保React Hot Loader停留在Webpack配置中的loaders数组中的Babel左边(这种写法在webpack2时代):


{ test: //.jsx?$/, loaders: ['react-hot', 'babel'], include: path.join(__dirname, 'src') }

Webpack将加载器从右到左,我们需要将Babel的输出提供给React Hot Loader,反之亦然。


3、Error: Invalid path './' (or similar)

如果您在Webpack配置中使用相对输出路径,请使用path.resolve():


var path = require('path');module.exports = {
...,
output: {
path: path.resolve('./my-relative-path'),
...
}
};

如果您使用了WebpackDevServer CLI模式,并且在切换到Node后崩溃,则会出现Error: Invalid path '',您可能没有在输出中指定任何路径。你可以把路径:__dirname放在那里,因为它对于开发配置无关紧要。


4、Module not found: Error: Cannot resolve module 'react-hot'

你可能使用了npm链接来在不同的文件夹中使用一个包的开发版本,而React Hot Loader错误地处理了它。您应该在加载程序配置中使用include,仅选择加载应用程序的文件。

页面引发的错误
Uncaught TypeError: Cannot read property 'NODE_ENV' of undefined
Uncaught TypeError: Cannot read property 'env' of undefined
[socket.io] Cannot use 'in' operator to search for 'document' in undefined

确保你已经排除了:/node_modules/或者更好的办法是,在加载器配置中包含:path.join(__ dirname,'src')(路径取决于你的应用程序),就像这一行一样。您从不需要使用React Hot Loader处理node_modules。如果你使用其他的加载器如jsx?harmony或babel,那么他们很可能也需要包含指定的。


不能热更新

通常,解决这类错误的最好方法是认真的比较你的设置和React Hot Boilerplate,看看有什么不同。


尝试使用WebpackDevServer Node接口而不是CLI!

WebpackDevServer CLI模式的行为与Node API略有不同。如果有疑问,我建议你使用React Hot Boilerplate这样的Node API。


Uncaught RangeError: Maximum call stack size exceeded

当使用WebpackDevServer CLI标志--hot时,不应该再使用HotModuleReplacementPlugin(),反之亦然,它们是互斥的,但是所期望的效果将适用于它们中的任何一个。


No 'Access-Control-Allow-Origin' header is present on the requested resource.

如果您尝试从另一个端口上的URL访问Webpack Dev Server,则可以尝试:


更改WebpackDevServer选项以包含CORS头


new WebpackDevServer(webpack(config), {
publicPath: config.output.publicPath,
hot: true,
headers: { 'Access-Control-Allow-Origin': '*' }
})

确保webpack.config.js中的webpack-dev-server客户端主机和端口与开发服务器的主机和端口匹配:


entry: [
'webpack-dev-server/client?http://localhost:3000', // WebpackDevServer host and port
'webpack/hot/only-dev-server',
'./src/app'
]
以下模块不能热更新:(他们需要全部重新加载!)

如果在编辑根组件时出现此警告,这可能是因为您不会从中导出任何内容,并从那里调用React.render。把你的根组件放在一个单独的文件(例如App.jsx)中,并从index.js中调用React.render。


如果将根组件编写为无状态简单函数而不是使用React.Component,则还会在v1.x中获得此警告。这个问题已经在v3.x中完全解决了。


如果您编辑非组件文件所需的非组件文件,也可能会出现此警告。这意味着热门更新冒泡,但应用程序无法处理它。这个是正常的!只需刷新。


如果你得到这个警告和一个404的hot-update.json文件,你可能使用的是一个古老版本的webpack-dev-server(只是更新它)。


我看到“[WDS] Hot Module Replacement enabled”,但是当我编辑App.js时没有任何反应

如果您正在运行node 0.11.13,则可能需要尝试更新到0.12。有人说这有助于解决这个问题。还要确保你的需求与文件具有相同的文件名。有App.js和require('app')可能会在某些系统上启动监听。


OS X还有一个很少发生的错误,导致一些文件夹在文件系统更改监视方面“断开”。这里有一些建议的修复(已经不存在了)。


我看到“[HMR] Nothing hot updated.”,当我编辑App.js时没有任何反应

如果在入口配置选项中有几个入口点,请确保webpack/hot/only-dev-server位于每个入口点中:


entry: {
app: ['./src/app', 'webpack/hot/only-dev-server'],
editor: ['./src/editor', 'webpack/hot/only-dev-server'],
...,
client: 'webpack-dev-server/client?http://localhost:3000'
}

你不得不在你的主机页面中包含“client.js”以使热更新工作。例如:


<script src="/static/bundle-client.js"></script>
<script src="/static/bundle-app.js"></script>
<script src="/static/bundle-entry.js"></script>

没有webpack/hot/only-dev-server(或者如果你喜欢偶尔重载的webpack/hot/dev-server)的入口点将不知道如何应用热更新。


Syntax error: Unexpected token <

如果您将WebpackDevServer与Express等现有服务器结合使用,并在热更新中获取此错误消息,那是因为Webpack被配置为从当前主机名请求热更新。因此,如果您的Express服务器在8000上,并且Webpack配置中的publicPath配置为/build/,则会从http://localhost:8000/ build/请求热更新,您的情况由Express提供。相反,您需要将publicPath设置为指向WebpackDevServer正在运行的端口。例如,它可以是http://localhost:9000/build/。


没有足够的监听

验证您的系统中是否有足够的可用监听。如果此值太低,Webpack中的文件监听器将无法识别这些更改:


cat /proc/sys/fs/inotify/max_user_watches

将fs.inotify.max_user_watches=524288添加到/etc/sysctl.d/99-sysctl.conf,然后执行sysctl --system。 Ubuntu用户(可能还有其他用户):echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p。


hot-update.json文件的404错误

首先,确保你有最新版本的Webpack和Webpack Dev Server(> = 1.7是好的)。当没有更新可用时,早期版本使用404代码,所以在技术上不是一个错误。


现在,看看他们被请求的路径。 Webpack使用来自Webpack config的output.publicPath来确定这个路径。如果您忘记指定它,Webpack将请求从相对路径到当前路径的更新,所以任何客户端路由都会打断它。


通常情况下,如果你是从根服务脚本的话,你希望它是'/',如果你有一个脚本的虚拟路径,或者像'http://localhost:port/scripts/ 只使用Webpack的脚本,但有另一个主要的服务器,如Express。此配置变量还必须匹配创建WebpackDevServer实例时指定的publicPath选项。看看React Hot Boilerplate来获得一个想法。

其他问题
build变慢了!!

确保你已经包括限制在你的应用程序的模块在加载程序配置。您从不需要使用React Hot Loader处理node_modules。


我的build文件怎么这么大!!

确保你有独立的开发和生产配置。在生产配置中,您不需要在装载程序或webpack-dev-server/client或webpack/hot/only-dev-server中进行反应。他们只是为了发展。为了便于维护,您可以在调用Webpack之前设置环境变量并在config中读取它。


还要确保你在生产配置中有这些插件(在webpack3中,可能略有不同):


// 移除一下react源码中的debugging
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify('production')
}
}),
// 保持哈希在编译之间一致
new webpack.optimize.OccurrenceOrderPlugin(),
// 压缩代码
new webpack.optimize.UglifyJsPlugin({
compressor: {
warnings: false
}
})

哦,不要忘记从生产配置中删除devtool:'eval'。否则Uglify根本不会丑化任何东西。


我只能通过 / 刷新访问我的单页应用程序(SPA)

问题是,默认情况下,WebpackDevServer不能正确处理HTML5历史记录,并且服务器不会按照它应该的路由URL。你可以通过设置historyApiFallback:true来解决这个问题。这是一个完整的例子:


var webpack = require('webpack');
var WebpackDevServer = require('webpack-dev-server');var config = require('./webpack.config');var port = 4000;
var ip = '0.0.0.0';new WebpackDevServer(webpack(config), {
publicPath: config.output.publicPath,
historyApiFallback: true,
}).listen(port, ip, function (err) {
if(err) {
return console.log(err);
}console.log('Listening at ' + ip + ':' + port);
});

在此之后,您应该可以通过任何已经定义的网址访问您的SPA。


React Hot Loader: this component is not accepted by Hot Loader

问题在于React Hot Loader无法替换新版本的某个Component的旧版本。原因总是一样的 - 新旧组件相同的时候,React Hot Loader不能理解它。


为什么?组件不会被提取为顶级变量。只有这样的组件React Hot Loader才能消化。


const SuperComponent =
connect()( <-- last HoC
withSomeStuff( <-- first HoC
Component<-- a real component
)
);

SuperComponent是一个顶级变量。和组件是。但是,使用SomeStuff也会产生一个(时态的)组件,对于React Hot Loader是绝对不可见的。


解决


const WithSomeStuffComponent = withSomeStuff(Component);
const SuperComponent = connect()(WithSomeStuffComponent);

所以是的 - 使用高阶函数组合和React Hot Loader是不可行的。所有的时间变量,步骤,备件必须分开。(笔者本人也遇到了这个问题,刚好在这里找到了答案)


PS:有可能创建一个babel插件,它将提取所有的东西。但谁来创造它呢?

最新文章

123

最新摄影

闪念基因

微信扫一扫

第七城市微信公众平台