热模块更换——更新但不重新渲染
Hot module replacement - Updating but not re-rendering
我是 运行 一个快速服务器,它将充当 API 我的 React 应用程序,该应用程序由 webpack-dev-server 捆绑和提供服务。
我正在尝试让热模块替换工作,并且快到了,当我更改我的文件时,我在控制台中得到了这个:
但应用程序永远不会重新呈现,除非手动刷新。不知道这是否相关,但是当我更新我的 .scss
文件时,它会在不手动执行的情况下刷新,并按我的预期进行更新。
版本:
"webpack": "2.1.0-beta.22"
"webpack-dev-server": "2.1.0-beta.8"
"react-hot-loader": "3.0.0-beta.5"
我尝试了最新的 webpack,但它给了我无法克服的验证错误。
我是 运行 webpack,通过:"webpack": "webpack-dev-server --port 4000 --env.dev"
,我的快递服务器是 运行 http://localhost:3000
。
这是我的 webpack.config.babel.js
:
const webpack = require('webpack');
const { resolve, join } = require('path');
const { getIfUtils, removeEmpty } = require('webpack-config-utils')
const getEntry = (ifDev) => {
let entry
if (ifDev) {
entry = {
app: [
'react-hot-loader/patch',
'webpack/hot/dev-server',
'webpack-dev-server/client?http://localhost:4000/',
'./js/index.js'
],
vendor: ['react']
}
} else {
entry = {
bundle: './js/index.js',
vendor: ['react']
}
}
return entry
}
const config = env => {
const { ifProd, ifDev } = getIfUtils(env)
return {
entry: getEntry(ifDev),
output: {
path: resolve('./public/dist/'),
publicPath: 'http://localhost:4000/',
filename: '[name].bundle.js',
},
context: resolve(__dirname, 'assets'),
devtool: env.prod ? 'source-map' : 'eval',
devServer: {
contentBase: resolve('./public/dist/'),
headers: { 'Access-Control-Allow-Origin': '*' },
publicPath: 'http://localhost:4000/',
hot: true,
noInfo: true,
inline: true
},
bail: env.prod,
module: {
loaders: [
{ test: /\.scss$/, loaders: [ 'style', 'css', 'sass' ], exclude: /node_modules|lib/ },
{ test: /\.(js|jsx)$/, exclude: /node_modules/, loaders: [ 'babel-loader' ] },
{ test: /\.(ttf|eot|svg|woff(2)?)(\?[a-z0-9=&.]+)?$/, loader: 'file-loader' }
]
},
resolve: {
extensions: ['.js', '.jsx']
},
plugins: removeEmpty([
ifDev(new webpack.NoErrorsPlugin()),
ifDev(new webpack.NamedModulesPlugin()),
ifDev(new webpack.HotModuleReplacementPlugin()),
new webpack.DefinePlugin({
'process.env': { NODE_ENV: JSON.stringify((env.prod) ? 'production' : 'development') }
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: Infinity,
filename: 'vendor.bundle.js'
}),
ifProd(new webpack.LoaderOptionsPlugin({
minimize: true,
debug: false
})),
ifProd(new webpack.optimize.UglifyJsPlugin({
compress: { warnings: false },
output: { comments: false },
sourceMap: false
}))
]),
}
}
module.exports = config
这是我的 .babelrc
,我在这里调用 react-hot-loader
{
"presets": [["es2015", { modules: false }], "stage-0", "react"],
"plugins": ["react-hot-loader/babel"],
"env": {
"test": {
"plugins": ["istanbul"],
"presets": ["es2015", "stage-0", "react"]
}
},
"sourceMaps": "inline"
}
HMR 自动为 CSS 工作,因为 style-loader
支持开箱即用。
对于 React,情况并非如此。你需要 react-hot-loader.
使用 npm 安装它,然后更改为:
{ test: /\.(js|jsx)$/, exclude: /node_modules/, loaders: [ 'babel-loader' ] },
收件人:
{ test: /\.(js|jsx)$/, exclude: /node_modules/, loaders: [ 'react-hot-loader', 'babel-loader' ] },
如果你想了解更多,我推荐阅读“Webpack’s HMR & React-Hot-Loader — The Missing Manual”。
使用 React Hot Loader v3 和 Babel 转换,您想在组件的根目录(进行渲染或创建 Redux 提供程序的位置)执行此操作:
render(
<AppContainer>
<Root
store={ store }
/>
</AppContainer>,
document.getElementById('root')
);
if (module.hot) {
module.hot.accept('./containers/Root', () => {
const RootContainer = require('./containers/Root').default;
render(
<AppContainer>
<RootContainer
store={ store }
/>
</AppContainer>,
document.getElementById('root')
);
});
}
使用新版本的 Hot Loader,您必须使用 module.hot.accept
显式接受热更新。
在更复杂的 Redux 项目中(带有路由和热重载 reducer),你可以这样做:
/**
* Starts the React app with the Router, and renders it to the given DOM container
* @param {DOMElement} container
*/
export default function app(container) {
const store = createStore(
combineReducers({
...reducers,
routing: routerReducer,
form: formReducer,
}),
compose(
applyMiddleware(
routerMiddleware(hashHistory),
thunkMiddleware,
promiseMiddleware
),
process.env.NODE_ENV !== 'production' && window.devToolsExtension ? window.devToolsExtension() : (param) => param
)
);
if (module.hot) {
module.hot.accept('./reducers', () => {
const nextReducers = require('./reducers');
const nextRootReducer = combineReducers({
...nextReducers,
routing: routerReducer,
form: formReducer,
});
store.replaceReducer(nextRootReducer);
});
}
const history = syncHistoryWithStore(hashHistory, store);
render({ store, history, container });
store.dispatch(loadEventsWhenLoggedIn());
if (module.hot) {
module.hot.accept('./render', () => {
const newRender = require('./render').default;
newRender({ store, history, container });
});
}
}
(和render.js)
/**
* Starts the React app with the Router, and renders it to the given DOM container
* @param {DOMElement} container
*/
export default function render({ store, history, container }) {
ReactDOM.render(
<Provider store={store}>
<div className='container'>
<Routes history={history} store={store} />
</div>
</Provider>,
container
);
}
有关更多示例,您应该查看 Dan Abramov 的 Redux devtools 示例 repo,例如此文件:https://github.com/gaearon/redux-devtools/blob/master/examples/todomvc/index.js
我遇到了这个问题,添加了 module.hot.accept() 函数,但它仍然无法正常工作。
hmr [已连接]...但没有热替换。
*已删除 node_module、package-lock、json、dist/build 个文件夹...
*已更改 webpack.config.client.production.js --> 已添加
plugins: [
new webpack.ProvidePlugin({
process: "process/browser"
})
],
resolve:{
alias:{
process: "process/browser"
}
}
然后 npm install --save-dev process
,
添加 import process from 'process'
到捆绑入口点(对我来说 main.js)
...
npm install
然后运行它。
我是 运行 一个快速服务器,它将充当 API 我的 React 应用程序,该应用程序由 webpack-dev-server 捆绑和提供服务。
我正在尝试让热模块替换工作,并且快到了,当我更改我的文件时,我在控制台中得到了这个:
但应用程序永远不会重新呈现,除非手动刷新。不知道这是否相关,但是当我更新我的 .scss
文件时,它会在不手动执行的情况下刷新,并按我的预期进行更新。
版本:
"webpack": "2.1.0-beta.22"
"webpack-dev-server": "2.1.0-beta.8"
"react-hot-loader": "3.0.0-beta.5"
我尝试了最新的 webpack,但它给了我无法克服的验证错误。
我是 运行 webpack,通过:"webpack": "webpack-dev-server --port 4000 --env.dev"
,我的快递服务器是 运行 http://localhost:3000
。
这是我的 webpack.config.babel.js
:
const webpack = require('webpack');
const { resolve, join } = require('path');
const { getIfUtils, removeEmpty } = require('webpack-config-utils')
const getEntry = (ifDev) => {
let entry
if (ifDev) {
entry = {
app: [
'react-hot-loader/patch',
'webpack/hot/dev-server',
'webpack-dev-server/client?http://localhost:4000/',
'./js/index.js'
],
vendor: ['react']
}
} else {
entry = {
bundle: './js/index.js',
vendor: ['react']
}
}
return entry
}
const config = env => {
const { ifProd, ifDev } = getIfUtils(env)
return {
entry: getEntry(ifDev),
output: {
path: resolve('./public/dist/'),
publicPath: 'http://localhost:4000/',
filename: '[name].bundle.js',
},
context: resolve(__dirname, 'assets'),
devtool: env.prod ? 'source-map' : 'eval',
devServer: {
contentBase: resolve('./public/dist/'),
headers: { 'Access-Control-Allow-Origin': '*' },
publicPath: 'http://localhost:4000/',
hot: true,
noInfo: true,
inline: true
},
bail: env.prod,
module: {
loaders: [
{ test: /\.scss$/, loaders: [ 'style', 'css', 'sass' ], exclude: /node_modules|lib/ },
{ test: /\.(js|jsx)$/, exclude: /node_modules/, loaders: [ 'babel-loader' ] },
{ test: /\.(ttf|eot|svg|woff(2)?)(\?[a-z0-9=&.]+)?$/, loader: 'file-loader' }
]
},
resolve: {
extensions: ['.js', '.jsx']
},
plugins: removeEmpty([
ifDev(new webpack.NoErrorsPlugin()),
ifDev(new webpack.NamedModulesPlugin()),
ifDev(new webpack.HotModuleReplacementPlugin()),
new webpack.DefinePlugin({
'process.env': { NODE_ENV: JSON.stringify((env.prod) ? 'production' : 'development') }
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: Infinity,
filename: 'vendor.bundle.js'
}),
ifProd(new webpack.LoaderOptionsPlugin({
minimize: true,
debug: false
})),
ifProd(new webpack.optimize.UglifyJsPlugin({
compress: { warnings: false },
output: { comments: false },
sourceMap: false
}))
]),
}
}
module.exports = config
这是我的 .babelrc
,我在这里调用 react-hot-loader
{
"presets": [["es2015", { modules: false }], "stage-0", "react"],
"plugins": ["react-hot-loader/babel"],
"env": {
"test": {
"plugins": ["istanbul"],
"presets": ["es2015", "stage-0", "react"]
}
},
"sourceMaps": "inline"
}
HMR 自动为 CSS 工作,因为 style-loader
支持开箱即用。
对于 React,情况并非如此。你需要 react-hot-loader.
使用 npm 安装它,然后更改为:
{ test: /\.(js|jsx)$/, exclude: /node_modules/, loaders: [ 'babel-loader' ] },
收件人:
{ test: /\.(js|jsx)$/, exclude: /node_modules/, loaders: [ 'react-hot-loader', 'babel-loader' ] },
如果你想了解更多,我推荐阅读“Webpack’s HMR & React-Hot-Loader — The Missing Manual”。
使用 React Hot Loader v3 和 Babel 转换,您想在组件的根目录(进行渲染或创建 Redux 提供程序的位置)执行此操作:
render(
<AppContainer>
<Root
store={ store }
/>
</AppContainer>,
document.getElementById('root')
);
if (module.hot) {
module.hot.accept('./containers/Root', () => {
const RootContainer = require('./containers/Root').default;
render(
<AppContainer>
<RootContainer
store={ store }
/>
</AppContainer>,
document.getElementById('root')
);
});
}
使用新版本的 Hot Loader,您必须使用 module.hot.accept
显式接受热更新。
在更复杂的 Redux 项目中(带有路由和热重载 reducer),你可以这样做:
/**
* Starts the React app with the Router, and renders it to the given DOM container
* @param {DOMElement} container
*/
export default function app(container) {
const store = createStore(
combineReducers({
...reducers,
routing: routerReducer,
form: formReducer,
}),
compose(
applyMiddleware(
routerMiddleware(hashHistory),
thunkMiddleware,
promiseMiddleware
),
process.env.NODE_ENV !== 'production' && window.devToolsExtension ? window.devToolsExtension() : (param) => param
)
);
if (module.hot) {
module.hot.accept('./reducers', () => {
const nextReducers = require('./reducers');
const nextRootReducer = combineReducers({
...nextReducers,
routing: routerReducer,
form: formReducer,
});
store.replaceReducer(nextRootReducer);
});
}
const history = syncHistoryWithStore(hashHistory, store);
render({ store, history, container });
store.dispatch(loadEventsWhenLoggedIn());
if (module.hot) {
module.hot.accept('./render', () => {
const newRender = require('./render').default;
newRender({ store, history, container });
});
}
}
(和render.js)
/**
* Starts the React app with the Router, and renders it to the given DOM container
* @param {DOMElement} container
*/
export default function render({ store, history, container }) {
ReactDOM.render(
<Provider store={store}>
<div className='container'>
<Routes history={history} store={store} />
</div>
</Provider>,
container
);
}
有关更多示例,您应该查看 Dan Abramov 的 Redux devtools 示例 repo,例如此文件:https://github.com/gaearon/redux-devtools/blob/master/examples/todomvc/index.js
我遇到了这个问题,添加了 module.hot.accept() 函数,但它仍然无法正常工作。
hmr [已连接]...但没有热替换。
*已删除 node_module、package-lock、json、dist/build 个文件夹...
*已更改 webpack.config.client.production.js --> 已添加
plugins: [
new webpack.ProvidePlugin({
process: "process/browser"
})
],
resolve:{
alias:{
process: "process/browser"
}
}
然后 npm install --save-dev process
,
添加 import process from 'process'
到捆绑入口点(对我来说 main.js)
...
npm install
然后运行它。