如何在我所开发的同构Web应用中正确使用Webpack热更新。

7
我正在创建一个使用node/express后端和react前端的web应用程序。我已经(我认为)完成了大部分工作,但是浏览器执行热刷新的最后一步并没有按预期工作。我将尝试在此处发布所有相关设置。如果您需要其他信息来查找我犯了什么错误,请告诉我:
我使用node ./server/index.js启动我的应用程序。 webpack.config.js var path = require('path'); var webpack = require('webpack);
let webpackConfig = {
    name: 'server',
    output: {
        path: path.join(__dirname, 'dist'),
        filename: 'bundle.js',
        publicPath: '/dist/',
    },
    resolve: {
      extensions: [
        '', '.js', '.jsx', '.json'
      ]
    },
    module: {
        loaders: [
            { 
                test: /\.(js|jsx)$/,
                loader: 'babel-loader',
                exclude: /node_modules/,
                query:{
                    presets: ['es2015', 'react', 'stage-2']
                }
            },
            {
                test:  /\.json$/, 
                loader: 'json-loader'
            }
        ]
    },
    entry: [
        'webpack-hot-middleware/client',
        './app/client/client.jsx'   
    ],
    plugins: [
        new webpack.DefinePlugin({
            'process.env': {
                NODE_ENV: JSON.stringify('production')
            }
        }),
        new webpack.optimize.OccurenceOrderPlugin(),
        new webpack.HotModuleReplacementPlugin(),
        new webpack.NoErrorsPlugin()
    ]   
};
export default webpackConfig;

index.js 只包括 'babel-register' 和 'server.js'

server/server.js 导入 webpack 模块和 webpack 配置文件 '../webpack.config'; 导入 webpack-dev-middleware 中间件模块; 导入 webpack-hot-middleware 中间件模块;

import express from 'express';

const app = express();
const renderPage = () => {
    return `
            <!doctype html>
            <html>
            <head>
                <title>Brewing Day</title>
                <meta charset='utf-8'>
            </head>
            <body>
                <h1>Hello from server.js!!</h1>
                <div id='root'></div>
                <script src='/dist/bundle.js'></script>
            </body>
            </html>
            `;
};

const compiler = webpack(webpackConfig);
app.use(webpackDevMiddleware(compiler, {
    noInfo: true,
    publicPath: webpackConfig.output.publicPath })
);
app.use(webpackHotMiddleware(compiler));

app.use((req, res, next) => {
  res.status(200).end(renderPage());
});

const server = app.listen(3005, () => {
    const host = server.address().address;
    const port = server.address().port;
    console.log(`Listening at http://${host}:${port}`);
})

export default server;

这里需要翻译的是Webpack配置中的入口文件 app/client/client.jsx

import React from 'react';
import ReactDOM from 'react-dom';
import Application from '../components/application.jsx';

window.addEventListener('load', () => {
    ReactDOM.render(<Application />, document.getElementById('root')
    );
});

在控制台中,启动时会列出以下行:
webpack built cc1194a11614a3ba54a3 in 730ms

当我对包含React组件的client.jsxapplication.jsx进行更改时,我的控制台会出现两行新代码:

webpack building...
webpack built 8d340a8853d3cfe9478d in 195ms

目前为止,一切顺利!

但是,在浏览器中,它没有更新,并在控制台中给出以下警告:

[HMR] The following modules couldn't be hot updated: (Full reload needed)
This is usually because the modules which have changed (and their parents) do not know how to hot reload themselves. See http://webpack.github.io/docs/hot-module-replacement-with-webpack.html for more details.
[HMR]  - ./app/components/application.jsx

我尝试随机添加 module.hot.accept()application.jsx。这样可以消除警告,但是没有更新,需要按 F5 刷新浏览器。

你有什么想法吗?我看到另一个设置几乎与我的相同,没有任何 module.hot.accept() 的调用,在那里这个函数可以正常工作,但我不知道我的设置与另一个设置有何差异。

非常感谢您的任何帮助。


你是否从 application.jsx 导出了你的组件? - booleanhunter
@ashwinator - 是的,我的 application.jsx 文件的最后一行是 export default Application; - Øyvind Bråthen
https://github.com/glenjamin/webpack-hot-middleware/issues/70 - PI.
1个回答

10

经过大量的搜索,我终于找到了解决我的问题的答案。我之前是这样创建我的基础React "class"的:

class Application = () => {
  return (
    <div id="maincontent">
      <MainMenu />
      <ScreenContents />          
    </div>
  )
};

即使React支持,但这在HMR上无法支持。

我不得不像这样明确地创建我的类:

class Application extends React.Component{
  render (){
    return (
      <div id="maincontent">
        <MainMenu />
        <ScreenContents /> 
      </div>
    );
  }
};

然后热模块替换就可以很好地工作了 :)

编辑:根据@akoskm的评论,似乎webpack配置文件中的babel配置也可能是一个问题。因此,这里是相关部分:

Babel设置

var babelSettings = {
    presets: ['react', 'es2015', 'stage-2'],
    env: {
        development: {
            plugins: [
                ['react-transform', {
                    transforms: [
                        { 
                            transform: 'react-transform-hmr',
                            imports: [ 'react' ],
                            locals: [ 'module' ]
                        }
                    ]
                }]
            ]
        }
    }
};

预设和环境等内容可能与您不完全相同,但react-transform是重要的部分。

装载器

{ 
    test: /\.(js|jsx)$/,
    loaders: ['babel?' + JSON.stringify(babelSettings)],
    exclude: /node_modules/
}

这确实有帮助,但我认为还有其他原因,因为我使用了几乎相同的方式来定义我的基本React类:https://github.com/archistackt/kts/blob/master/components/app.js 但我仍然遇到了与你一样的错误。你有任何想法吗? - Akos K
@akoskm - 你解决了这个问题吗?除了创建React类之外,我还在webpack配置中更改了我的babel加载器设置。如果你仍然需要帮助,请告诉我,我们会一起解决它 :) - Øyvind Bråthen
感谢@Øyvind Bråthen。我还没有机会查看这个项目,但我会在接下来的几天里处理它,并且如果我能够使其正常工作,我会让你知道。我之前发布的内容中包含了我目前正在使用的webpack配置文件的存储库链接:https://github.com/archistackt/kts/blob/master/webpack.config.js - Akos K
我刚刚检查了一下,还是不起作用。这是我的 Babel Loader 配置:https://github.com/archistackt/kts/blob/master/webpack.config.js#L22 - Akos K
1
@akoskm - 我已经将我的项目中的 Babel 设置添加进来了,因为它们与你的设置有很大不同。我认为 'react-transform-hmr' 是你拼图中缺失的部分。让我知道结果如何 :) - Øyvind Bråthen
确切地说,我错过了那个配置。我想问一下文档是否有提到,但我已经在这里找到了:https://github.com/gaearon/react-transform-hmr#react。然而,我认为`JSON.stringify(babelSettings)` 方法有点笨拙,所以我将 babelSettings 包含在查询属性中:https://github.com/archistackt/kts/blob/master/webpack.config.js#L41。感谢您的帮助! - Akos K

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接