Проблема с WDS при горячей замене модуля, затем полная перезагрузка страницы сразу после
В настоящее время я пытаюсь настроить замену ГОРЯЧЕГО МОДУЛЯ с моим проектом веб-пакета. В тот момент, когда я делаю изменения в компоненте реагирования в исходном коде, я вижу, что модуль перезагружается в браузере без обновления, после чего происходит полное обновление страницы.
Вот что я вижу в консоли.
WDS, кажется, работает ДВАЖДЫ?
- следующая строка - 404, когда для GET http://localhost:8088/dist/0580e96e5dacd24618e5.hot-update.json 404 (не найдено) я удалил это для конфиденциальности компании:)
тогда эти две строки в консоли:
- Элемент списка
dev-server.js:28 [HMR] Не удается найти обновление. Необходимо выполнить полную перезагрузку!(Анонимная функция) @ dev-server.js:28(анонимная функция) @
- Элемент списка
index.js:238request.onreadystatechange @ index.js:37 dev-server.js:29 [HMR] (возможно, из-за перезапуска webpack-dev-server)
Как видите, клиент: 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']
}
};
Вот файл devServer.js, который я запускаю в своей задаче npm.
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}`);
});
1 ответ
То, что вы и я оба пытались сделать, это использовать фрагменты кода, предназначенные для webpack 2, с файлом установки и конфигурации webpack 1.
Мое решение состояло в том, чтобы внимательно следовать руководству по Webpack 2 для React HMR, которое можно найти здесь: 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 может иметь немного больше, например, использовать response-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, чтобы он выглядел следующим образом
const render = (content) => {
ReactDOM.render(
<AppContainer>
{content}
</AppContainer>,
document.getElementById('root')
);
};
Я просто использую webpack-dev-server из командной строки, поэтому я еще не пробовал это с промежуточным ПО с экспресс-сервера. Удачи в этом и удачного кодирования!