无法使Webpack 2 HMR React工作
目前我正努力让HMR在我的Webpack 2设置中工作。我会解释我的整个设置,所以我希望这足以让某人了解正在发生的事情。无法使Webpack 2 HMR React工作
我的项目结构:
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
文件的内容,摆在我的项目的根目录:
function buildConfig(env) {
return require('./config/' + env + '.js')(env)
}
module.exports = buildConfig;
在这个文件
所以我的选择将不同的环境传递给buildConfig
函数。我使用这个选项来使用不同的配置文件进行开发和生产。这是我package.json
文件中的内容:在我的package.json
{
"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"
}
}
我有,当然更多的领域,但我会因为他们是无关的不是他们在这里显示。
所以在开发过程中,我在终端中运行了npm run build:dev
命令。这将使用config
文件夹中的文件dev.js
。这是dev.js
文件的内容:
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
文件:
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
我看到我的网站工作正常。这是在控制台输出:
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
组件。此功能如下所示:
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启动。我将渲染函数更改为此。
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>
);
}
这是输出我在控制台中看到:
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.
你会说这是很好的。 但我的网站不更新任何东西。
然后,我改变了HMR代码在我index.js
这样:
// Hot Module Replacement API
if (module.hot) {
module.hot.accept();
}
和它的作品。我只是不明白。
// Hot Module Replacement API
if (module.hot) {
module.hot.accept('./components/TodoApp',() => {
render(TodoApp)
});
}
BTW这个设置是根据设置从https://webpack.js.org/guides/hmr-react/
我希望有人能帮助我:为什么,如果这是我的HMR代码不发挥作用。如果有人需要更多信息,请不要犹豫。提前致谢!
UPDATE
忘记而我.babelrc
文件。这是它:
{
"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.
]
}
进口是静态的,更新已module.hot.accept
被确定之后,你再次渲染完全相同的部件,如TodoApp
仍持有旧版本的模块和HMR意识到并没有按” t刷新或更改您应用中的任何内容。
您想使用Dynamic import: import()
。为了使它与babel一起工作,您需要添加babel-plugin-syntax-dynamic-import
,否则它会报告语法错误,因为它不会将import
用作函数。该react-hot-loader/babel
不需要,如果你在你的WebPack配置使用react-hot-loader/patch
,所以你在你的.babelrc
插件成为:
"plugins": [
"syntax-dynamic-import"
]
在你render()
功能,你现在可以导入TodoApp
和渲染。
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模块开箱,在react-hot-loader
docs - Webpack 2还描述了,因为的WebPack也处理HMR它会知道该怎么做。为了这个工作,你不能将模块转换为commonjs。您使用["es2015", {"modules": false}]
来完成此操作,但是您的webpack配置中还配置了latest
预设,这也会转换模块。为避免混淆,您应该在.babelrc
中拥有所有babel配置,而不是将某些配置拆分为加载器选项。
完全从您的webpack配置中删除babel-loader
中的预设,它将工作,因为您已在.babelrc
中拥有必要的预设。 babel-preset-latest
已被弃用,如果您想使用这些功能,您应该开始使用babel-preset-env
,这也取代了es2015
。所以,你在.babelrc
预设是:
"presets": [
["env", {"modules": false}],
"react"
],
谢谢,这确实是问题!我的'.babelrc'文件中的设置被'webpack.config'文件覆盖。 – DavidWorldpeace
通过webpack.config使用.babelrc的任何理由?为什么不使用webpack.config? –
@JohnLeidegren'.babelrc'适用于使用Babel的所有内容。如果您在webpack配置中配置它,它将只适用于webpack。 webpack之外的Babel有很多用途。一个例子是测试,因为问题[意外的令牌 - 对现有的React + Web应用程序的赞赏](https://stackoverflow.com/questions/45372145/unexpected-token-jest-for-existing-react-web-包 - 应用程序)显示。 –
入住这issue在GitHub上或使用此在您的index.js:
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();
}
你有没有在你的'.babelrc'文件中禁用ES2015模块? https://webpack.js.org/guides/hmr-react/#babel-config –
O耶对不起,我忘了发布我的'.babelrc'文件的内容。现在就做这个。 – DavidWorldpeace