原文

react-hot-loader故障排除指南

翻译

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

它应该是什么样子?

页面加载时

clipboard.png

保存一个文件时

clipboard.png

如果您看不到某些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插件,它将提取所有的东西。但谁来创造它呢?

如果觉得我的文章对你有用,请随意赞赏

你可能感兴趣的文章

载入中...
二月 二月

2.1k 声望

发布于专栏

前端江湖

前端基础知识、框架、工程化开发分享,前端技术栈研究。 加油吧,在前端的道路上奔跑。

162 人关注