首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >不能让Webpack 2 HMR对工作做出反应

不能让Webpack 2 HMR对工作做出反应
EN

Stack Overflow用户
提问于 2017-04-19 09:12:52
回答 2查看 2.6K关注 0票数 3

目前,我正在努力使HMR工作在我的Webpack 2设置。我会解释我的整个设置,所以我希望这足以让人了解发生了什么。

我的项目结构:

代码语言:javascript
运行
复制
config
  dev.js
  prod.js 
dist
  css
  js
  index.html
node_modules
src
  components
    // some JavaScript components
  shared
  stylesheets
  index.js
.babelrc
package.json
webpack.config.js

这是我的webpack.config.js文件的内容,放在我的项目的根目录中:

代码语言:javascript
运行
复制
function buildConfig(env) {
  return require('./config/' + env + '.js')(env)
}

module.exports = buildConfig;

因此,在这个文件中,我可以选择将不同的环境传递给buildConfig函数。我使用这个选项来使用不同的配置文件进行开发和生产。这是我的package.json文件中的内容:

代码语言:javascript
运行
复制
{
  "main": "index.js",
  "scripts": {
    "build:dev": "node_modules/.bin/webpack-dev-server --env=dev",
    "build:prod": "node_modules/.bin/webpack -p --env=prod"
  },
  },
  "devDependencies": {
    "autoprefixer-loader": "^3.2.0",
    "babel-cli": "^6.18.0",
    "babel-core": "^6.24.1",
    "babel-loader": "^6.2.5",
    "babel-preset-latest": "^6.16.0",
    "babel-preset-react": "^6.16.0",
    "babel-preset-stage-0": "^6.16.0",
    "css-loader": "^0.25.0",
    "extract-text-webpack-plugin": "^2.1.0",
    "json-loader": "^0.5.4",
    "node-sass": "^3.13.1",
    "postcss-loader": "^1.3.3",
    "postcss-scss": "^0.4.1",
    "sass-loader": "^4.1.1",
    "style-loader": "^0.13.1",
    "webpack": "^2.4.1",
    "webpack-dev-server": "^2.4.2"
  },
  "dependencies": {
    "babel-plugin-react-css-modules": "^2.6.0",
    "react": "^15.3.2",
    "react-dom": "^15.3.2",
    "react-hot-loader": "^3.0.0-beta.6",
    "react-icons": "^2.2.1"
  }
}

当然,我的package.json中还有更多的字段,但是我不会在这里展示它们,因为它们是不相关的。

因此,在开发期间,我在我的终端中运行npm run build:dev命令。这将使用来自config文件夹的文件config。这是dev.js文件的内容:

代码语言:javascript
运行
复制
const webpack = require('webpack');
const { resolve } = require('path');
const context = resolve(__dirname, './../src');

module.exports = function(env) {
  return {
    context,
    entry: {
      app: [
        'react-hot-loader/patch',
        // activate HMR for React
        'webpack-dev-server/client?http://localhost:3000',
        // bundle the client for webpack-dev-server
        // and connect to the provided endpoint
        'webpack/hot/only-dev-server',
        // bundle the client for hot reloading
        // only- means to only hot reload for successful updates
        './index.js'
        // the entry point of our app
      ]
    },
    output: {
      path: resolve(__dirname, './../dist'), // `dist` is the destination
      filename: '[name].js',
      publicPath: '/js'
    },
    devServer: {
      hot: true, // enable HMR on the server
      inline: true,
      contentBase: resolve(__dirname, './../dist'), // `__dirname` is root of the project
      publicPath: '/js',
      port: 3000
    },
    devtool: 'inline-source-map',
    module: {
      rules: [
        {
          test: /\.js$/, // Check for all js files
          exclude: /node_modules/,
          use: [{
            loader: 'babel-loader',
            query: {
              presets: ['latest', 'react'],
              plugins: [
                [
                  "react-css-modules",
                  {
                    context: __dirname + '/../src', // `__dirname` is root of project and `src` is source
                    "generateScopedName": "[name]__[local]___[hash:base64]",
                    "filetypes": {
                      ".scss": "postcss-scss"
                    }
                  }
                ]
              ]
            }
          }]
        },
        {
          test: /\.scss$/,
          use: [
            'style-loader',
            {
              loader: 'css-loader',
              options: {
                sourceMap: true,
                modules: true,
                importLoaders: 2,
                localIdentName: '[name]__[local]___[hash:base64]'
              }
            },
            'sass-loader',
            {
              loader: 'postcss-loader',
              options: {
                plugins: () => {
                  return [
                    require('autoprefixer')
                  ];
                }
              }
            }
          ]
        }
      ]
    },
    plugins: [
      new webpack.HotModuleReplacementPlugin(),
      // enable HMR globally
      new webpack.NamedModulesPlugin()
      // prints more readable module names in the browser console on HMR updates
    ]
  }
};

最后但并非最不重要的是我的HMR设置。在我的index.js文件中有这样的设置:

代码语言:javascript
运行
复制
import React from 'react';
import ReactDOM from 'react-dom';
import { AppContainer } from 'react-hot-loader';
import TodoApp from './components/TodoApp';
import './stylesheets/Stylesheets.scss';

const render = (Component) => {
  ReactDOM.render(
      <AppContainer>
        <Component />
      </AppContainer>,
      document.querySelector('#main')
  );
};

render(TodoApp);

// Hot Module Replacement API
if (module.hot) {
  module.hot.accept('./components/TodoApp', () => {
    render(TodoApp)
  });
}

因此,当我在浏览器中运行我的npm start build:dev并转到http://localhost:3000时,我看到我的站点按预期工作。这是控制台中的输出:

代码语言:javascript
运行
复制
dev-server.js:49 [HMR] Waiting for update signal from WDS...
only-dev-server.js:66 [HMR] Waiting for update signal from WDS...
TodoApp.js:102 test
client?344c:41 [WDS] Hot Module Replacement enabled.

test文本来自TodoApp组件中的呈现函数。此函数如下所示:

代码语言:javascript
运行
复制
render() {
  console.log('test');
  return(
      <div styleName="TodoApp">
        <TodoForm addTodo={this.addTodo} />
        <TodoList todos={this.state.todos} deleteTodo={this.deleteTodo} toggleDone={this.toggleDone} updateTodo={this.updateTodo} />
      </div>
  );
}

所以现在重要的事情。我更新此呈现函数的返回,该函数将触发HMR启动。我将呈现函数更改为以下内容。

代码语言:javascript
运行
复制
render() {
  console.log('test');
  return(
      <div styleName="TodoApp">
        <p>Hi Stackoverflow</p>
        <TodoForm addTodo={this.addTodo} />
        <TodoList todos={this.state.todos} deleteTodo={this.deleteTodo} toggleDone={this.toggleDone} updateTodo={this.updateTodo} />
      </div>
  );
}

这是我在控制台中得到的输出:

代码语言:javascript
运行
复制
client?344c:41 [WDS] App updated. Recompiling...
client?344c:41 [WDS] App hot update...
dev-server.js:45 [HMR] Checking for updates on the server...
TodoApp.js:102 test
log-apply-result.js:20 [HMR] Updated modules:
log-apply-result.js:22 [HMR]  - ./components/TodoApp.js
dev-server.js:27 [HMR] App is up to date.

你会说这很好。但是我的网站没有更新任何东西.

然后,我将index.js中的HMR代码更改为:

代码语言:javascript
运行
复制
// Hot Module Replacement API
if (module.hot) {
  module.hot.accept();
}

而且它是有效的。我只是不明白。如果这是我的HMR代码,它为什么不能工作:

代码语言:javascript
运行
复制
// Hot Module Replacement API
if (module.hot) {
  module.hot.accept('./components/TodoApp', () => {
    render(TodoApp)
  });
}

顺便说一下,这个设置是基于来自https://webpack.js.org/guides/hmr-react/的设置

我希望任何人都能帮我。如果有人需要更多的信息,请毫不犹豫地问。提前感谢!

更新

忘记张贴我的.babelrc文件。就是这样:

代码语言:javascript
运行
复制
{
  "presets": [
    ["es2015", {"modules": false}],
    // webpack understands the native import syntax, and uses it for tree shaking

    "react"
    // Transpile React components to JavaScript
  ],
  "plugins": [
    "react-hot-loader/babel"
    // EnablesReact code to work with HMR.
  ]
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-04-19 15:56:25

导入是静态的,在module.hot.accept中标识了更新之后,您再次呈现完全相同的组件,因为TodoApp仍然保存您的模块的旧版本,而HMR意识到这一点,不会刷新或更改应用程序中的任何内容。

您想要使用import()。要使其与babel一起工作,您需要添加babel-plugin-syntax-dynamic-import,否则它将报告语法错误,因为它不希望import用作函数。如果在webpack配置中使用react-hot-loader/babel,则不需要react-hot-loader/patch,因此.babelrc中的插件变成:

代码语言:javascript
运行
复制
"plugins": [
  "syntax-dynamic-import"
]

在您的render()函数中,您现在可以导入TodoApp并呈现它。

代码语言:javascript
运行
复制
const render = () => {
  import('./components/TodoApp').then(({ default: Component }) => {
    ReactDOM.render(
      <AppContainer>
        <Component />
      </AppContainer>,
      document.querySelector('#main')
    );
  });
};

render();

// Hot Module Replacement API
if (module.hot) {
  module.hot.accept('./components/TodoApp', render);
}

import()是一个解决模块问题的承诺,您希望使用default导出。

尽管上述情况是正确的,webpack文档并不要求您使用动态导入,因为webpack从盒子中处理ES模块,这也是在博士- Webpack 2中描述的,而且因为out也在处理HMR,所以它知道在这种情况下该做什么。要使其工作,您不能将模块转换为公共组件。这是用["es2015", {"modules": false}]完成的,但是在webpack配置中也配置了latest预置,这也转换了模块。为了避免混淆,您应该使用.babelrc中的所有babel配置,而不是将一些配置拆分到加载程序选项中。

从您的webpack配置中完全删除babel-loader中的预置,它将工作,因为您已经在您的.babelrc中有必要的预置。babel-preset-latest是不推荐的,如果您想使用这些特性,您应该开始使用babel-preset-env,这也取代了es2015。因此,您在.babelrc中的预设是:

代码语言:javascript
运行
复制
"presets": [
  ["env", {"modules": false}],
  "react"
],
票数 6
EN

Stack Overflow用户

发布于 2017-04-25 11:47:56

在GitHub上检查这个GitHub,或者在index.js中使用这个:

代码语言:javascript
运行
复制
import React from 'react'
import ReactDOM from 'react-dom'
import { AppContainer } from 'react-hot-loader'

import App from './components/App'

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

render(App)

if(module.hot) {
    module.hot.accept();
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43491310

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档