2

我目前正在尝试使用我的 webpack 项目设置热模块替换。在我对源代码中的反应组件进行更改的那一刻,我看到模块在没有刷新的情况下在浏览器中重新加载,然后是页面的完全刷新。

这是我在控制台中看到的。

WDS 似乎运行两次?

然后控制台中的这两行:

  • 项目清单

dev-server.js:28 [HMR] 找不到更新。需要完全重新加载!(匿名函数)@ dev-server.js:28(匿名函数)@

  • 项目清单

index.js:238request.onreadystatechange @ index.js:37 dev-server.js:29 [HMR] (可能是因为重启了 webpack-dev-server)

如您所见,'client:37 [WDS] 应用程序已更新。重新编译...' 似乎运行了两次...这可能就是为什么它既是热交换又是完全重新加载的原因。

有任何想法吗?

这是我的 webpack.config

module.exports = {
  devtool: 'eval',
  cache: true,

  entry: {
    index: [
        'react-hot-loader/patch',
        'webpack-dev-server/client?http://localhost:8080',
        'webpack/hot/only-dev-server',
        './js/src/index.js'
    ],
    login: './login/index.js',
  },

  output: {
    path: path.join(__dirname, 'dist'),
    publicPath: '/dist/',
    filename: '[name].js',
    chunkFilename: '[name].js'
  },

  module: {

    loaders: [

      // Transpile ES6 JSX to ES5 JS
      {
        test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        loader: 'babel',
      },

      // SCSS
      {
        test: /\.scss$/,
        loaders: [
          'style',
          'css?importLoaders=1&localIdentName=[local]-[hash:base64:5]',
          'postcss-loader',
          'resolve-url',
          'sass'
        ]
      },

        {
            test: /\.json$/,
            loaders: ['json-loader'],
        }
    ]

  },

  postcss: function () {
    return {
      defaults: [autoprefixer],
      cleaner:  [autoprefixer({ browsers: ['last 2 versions'], cascade: true })]
    };
  },

  plugins: [
    new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /en|de|fr|zh|ja|it/),
    new webpack.HotModuleReplacementPlugin(),
    new webpack.IgnorePlugin(/ReactContext/),
    new webpack.DefinePlugin({ 'process.env.apiEndPointUrl': '"'+apiEndPointUrl+'"' }),
    new JsonBundlerPlugin({
        fileInput: '**/locales/*.json',
        omit: /\/locales|\/?components|\/?services|\/?scenes|\/?features/g,
        rootDirectory: 'src'
    }),
  ],

  resolve: {
    extensions: ['', '.js', '.json', '.jsx']
  }
};

这是我在 npm 任务中运行的 devServer.js 文件。

const webpack = require('webpack');
const WebpackDevServer = require('webpack-dev-server');
const opener = require('opener');
const config = require('./webpack.config.js');
const host = 'localhost';
const port = 8080;

new WebpackDevServer(webpack(config), {
        publicPath: config.output.publicPath,
        hot: true,
        historyApiFallback: true,
        stats: {
            colors: true // color is life
        },
    })
    .listen(port, host, (err) => {
        if (err) {
            console.log(err);
        }
        console.log(`Listening at ${host}:${port}`);
        opener(`http://${host}:${port}`);
    });
4

1 回答 1

1

你和我都试图做的是使用 webpack 2 的代码片段和 webpack 1 安装和配置文件。

我的解决方案是密切遵循此处找到的 React HMR 的 webpack 2 指南:https ://webpack.js.org/guides/hmr-react/

npm i --save-dev babel-core babel-loader babel-preset-es2015 babel-preset-react babel-preset-stage-2 react-hot-loader@3.0.0-beta.6 webpack@2.1.0-beta.25 webpack-dev-server@2.1.0-beta.0

npm i --save react react-dom

.babelrc

{
  "presets": [["es2015", {"modules": false}], "stage-2", "react"],
  "plugins": ["react-hot-loader/babel"]
}

webpack.config.js

const { resolve } = require('path');
const webpack = require('webpack');

const publicPath = '/';
const contentBase = resolve(__dirname, 'dist');

module.exports = {
  entry: [
    'react-hot-loader/patch',
    'webpack-dev-server/client?http://localhost:8080',
    'webpack/hot/only-dev-server',
    './index.js'
  ],
  output: {
    filename: 'bundle.js',
    path: contentBase,
    publicPath: publicPath
  },
  devtool: 'inline-source-map',
  devServer: {
    hot: true,
    contentBase: contentBase,
    publicPath: publicPath
  },
  module: {
    rules: [
      {
        test: /\.jsx?$/,
        use: ['babel-loader'],
        exclude: /node_modules/
      }
    ],
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NamedModulesPlugin()
  ],
  resolve: {
    extensions: ['.json', '.js', '.jsx']
  }
};

现在这是新的重要部分

index.js

import React from 'react';
import ReactDOM from 'react-dom';

import { AppContainer } from 'react-hot-loader';
// AppContainer is a necessary wrapper component for HMR

import App from './components/App';

const render = (Component) => {
  ReactDOM.render(
    <AppContainer>
      <Component/>
    </AppContainer>,
    document.getElementById('root')
  );
};

render(App);

// Hot Module Replacement API
if (module.hot) {
  module.hot.accept('./components/App', () => {
    const NewApp = require('./components/App').default
    render(NewApp)
  });
}

现在您的 App.jsx 可能是一个实际的组件,例如

import * as React from 'react';

class App extends React.Component {

  ...

  render() {
    return <div>hello world!</div>
  }
}

export default App;

在这种情况下,保留该 index.js 文件。但是,您的 App.jsx 可能还有更多功能,例如使用 react-router 或 redux 等。在这种情况下,您的 App.jsx 可能类似于以下内容

import * as React from 'react';
import { Router, Route, IndexRoute, browserHistory } from 'react-router';

export default <Router history={browserHistory}>
  <Route component={Main}>
    <Route path="page-one" component={PageOne} />
  </Route>
</Router>;

在这种情况下,您需要修改 index.js 中的 render 方法,使其如下所示

const render = (content) => {
  ReactDOM.render(
    <AppContainer>
      {content}
    </AppContainer>,
    document.getElementById('root')
  );
};

我只是从命令行使用 webpack-dev-server,所以我还没有尝试过使用 express 服务器的中间件。祝你好运,编码愉快!

于 2017-01-16T16:53:35.530 回答