2017-02-16 44 views
3

我使用的快遞中間件代替的WebPack-dev的服務器:如何使用webpack 2和webpackDevMiddleware獲取react-hot-loader?

const config = require("../webpack.config.js"); 

if(process.env.NODE_ENV === 'development') { 
    const webpack = require('webpack'); 
    const webpackDevMiddleware = require('webpack-dev-middleware'); 
    const webpackHotMiddleware = require('webpack-hot-middleware'); 
    const compiler = webpack(config); 

    app.use(webpackDevMiddleware(compiler, { 
     stats: {colors: true}, 
    })); 
    app.use(webpackHotMiddleware(compiler)); 
} 

我已經試過react-hot-loader/patchreact-hot-loader/babelreact-hot-loader/webpack[email protected]

module.exports = { 
    context: path.join(__dirname, 'client'), 
    entry: [ 
     'webpack-hot-middleware/client', 
     'react-hot-loader/patch', 
     './entry.less', 
     './entry', 
    ], 
    output: { 
     path: path.join(__dirname, 'public'), 
     filename: 'bundle.js', 
     publicPath: '/', 
    }, 
    module: { 
     rules: [ 
      { 
       test: /\.jsx/, 
       use: [ 
        { 
         loader: 'babel-loader', 
         options: { 
          plugins: ['transform-react-jsx', 'transform-class-properties', 'react-hot-loader/babel'], 
         }, 
        }, 
        'react-hot-loader/webpack' 
       ], 
      }, 

但他們都不來工作。我剛剛得到這個錯誤信息:

[HMR]以下模塊不能熱更新:(全部重新加載需要) 這通常是因爲它改變了模塊(和他們的父母)不知道如何熱重新加載自己。有關更多詳細信息,請參閱http://webpack.github.io/docs/hot-module-replacement-with-webpack.html。 logUpdates @ bundle.js:29964 applyCallback @ bundle.js:29932 (匿名)@ bundle.js:29940個 bundle.js:29972
[HMR] - ./client/components/CrawlForm.jsx

使它工作的訣竅是什麼?

N.B. CSS熱加載工作得很好,所以我得到了這部分工作。

回答

2

我花了好幾天才終於破案。這裏是我的代碼工作:

的WebPack配置對象

const clientConfig = { 
    entry: { 
    client: [ 
     'react-hot-loader/patch', 
     'webpack-hot-middleware/client', 
     'babel-polyfill', 
     './src/client/client.js', 
    ], 
    }, 
    output: { 
    path: path.resolve(__dirname, './build/public'), 
    filename: '[name].js', 
    publicPath: '/', 
    }, 
    devtool: 'inline-source-map', 
    plugins: [ 
    new webpack.HotModuleReplacementPlugin(), 
    new webpack.NoEmitOnErrorsPlugin(), 
    new webpack.LoaderOptionsPlugin({ 
     debug: true, 
    }), 
    new CopyWebpackPlugin([ 
     { from: './src/assets/fonts', to: 'fonts' }, 
     { from: './src/assets/images', to: 'images' }, 
    ]), 
    new webpack.EnvironmentPlugin(['GOOGLE_MAP_API_KEY']), 
    ], 
    module: { 
    rules: [ 
     { 
     test: /(\.js|\.jsx)$/, 
     loader: 'babel-loader', 
     exclude: /node_modules/, 
     options: { 
      presets: [['es2015', { loose: true }], 'react', 'stage-2'], 
     }, 
     }, 
     { 
     test: /\.scss$/, 
     use: [ 
      'style-loader', 
      'css-loader', 
      'sass-loader', 
     ], 
     }, 
    ], 
    }, 
}; 

服務器index.js

我使用這兩種開發中間件和熱中間件和你一樣。我也從react-hot-loader導入AppContainer幷包裝我的組件。

import express from 'express'; 
import React from 'react'; 
import routes from 'components/Routes'; 
import html from './html'; 
import { renderToString } from 'react-dom/server'; 
import { match, RouterContext } from 'react-router'; 
import { Provider } from 'react-redux'; 
import makeStore from 'store'; 
import Immutable from 'immutable'; 
import setupNameless from './setupNameless'; 
import db from './database'; 
import { actions } from '../client/constants'; 
import webpack from 'webpack'; 
import webpackHotMiddleware from 'webpack-hot-middleware'; 
import webpackDevMiddleware from 'webpack-dev-middleware'; 
import { clientConfig as wpConfig } from '../../webpack.config.js'; 
import { AppContainer } from 'react-hot-loader'; 
import dotenv from 'dotenv'; 

dotenv.config(); 

const compiler = webpack(wpConfig); 

db(); 

const app = express(); 
app.use(webpackDevMiddleware(compiler, { 
    publicPath: wpConfig.output.publicPath, 
    // noInfo: true, 
    stats: { 
    colors: true, 
    }, 
})); 
app.use(webpackHotMiddleware(compiler)); 
app.use(express.static('build/public')); 

const { commander: nameless, apiPrefix } = setupNameless(app); 

app.use((req, res, next) => { 
    // make DB call here to fetch jobs. 
    nameless.exec('jobs', actions.GET_JOBS).then((jobs) => { 

    const store = makeStore(Immutable.fromJS({ 
     // filters: {}, 
     app: { 
     apiPrefix, 
     search: { 
      query: '', 
      options: {}, 
     }, 
     }, 
     jobs, 
    })); 

    match({ 
     routes, 
     location: req.originalUrl, 
    }, (error, redirectLocation, renderProps) => { 
     if (error) { 
     res.status(500).send(error.message); 
     } else if (redirectLocation) { 
     res.redirect(302, redirectLocation.pathname + redirectLocation.search); 
     } else if (renderProps) { 
     // You can also check renderProps.components or renderProps.routes for 
     // your "not found" component or route respectively, and send a 404 as 
     // below, if you're using a catch-all route. 
     try { 
      res.status(200).send(html(renderToString(
      <AppContainer> 
       <Provider store={store}> 
       <RouterContext {...renderProps} /> 
       </Provider> 
      </AppContainer> 
     ), store.getState())); 
     } catch (err) { 
      next(err); 
     } 
     } else { 
     res.status(404).send('Not found'); 
     } 
    }); 
    }, (e) => { 
    next(e); 
    }).catch(e => { 
    next(e); 
    }); 
}); 

app.use(logErrors); 

function logErrors(err, req, res, next) { 
    console.error(err.stack); 
    next(err); 
} 

app.listen(process.env.PORT || 3000,() => { 
    console.log(`App listening on port ${process.env.PORT || 3000}`); 
}); 

Client.js

這是使它工作的法寶。我必須添加if (module.hot)代碼,並且還從react-hot-loader中導入AppContainer。另一個重要方面是將key={Math.random()}添加到我的<Router />組件。

import { match, Router, browserHistory as history } from 'react-router'; 
import routes from './components/Routes'; 
import ReactDOM from 'react-dom'; 
import React from 'react'; 
import { Provider } from 'react-redux'; 
import makeStore from './store'; 
import Immutable from 'immutable'; 
import createLogger from 'redux-logger'; 
import createSagaMiddleware from 'redux-saga'; 
import sagas from './sagas'; 
import { AppContainer } from 'react-hot-loader'; 

const logger = createLogger(); 
const sagaMiddleware = createSagaMiddleware(); 

const store = makeStore(
    Immutable.fromJS(window.__INITIAL_STATE__), 
    logger, 
    sagaMiddleware 
); 

sagaMiddleware.run(sagas); 

ReactDOM.render(
    <AppContainer> 
    <Provider store={store}> 
     <Router history={history} routes={routes} /> 
    </Provider> 
    </AppContainer>, 
    document.getElementById('app')); 

if (module.hot) { 
    module.hot.accept('./components/Routes',() => { 
    const nextRoutes = require('./components/Routes').default; 
    ReactDOM.render(
     <AppContainer> 
     <Provider store={store}> 
      <Router key={Math.random()} history={history} routes={nextRoutes} /> 
     </Provider> 
     </AppContainer>, 
     document.getElementById('app')); 
    }); 
} 

好運

+0

哇...比以前更復雜了。 ''和'if(module.hot)'位爲我工作。謝謝!! – mpen

1

Dan Abramov複述和realseanp借用一些代碼,完整的說明是:

  1. yarn add [email protected]
  2. 更新webpack.config.js
    1. 添加react-hot-loader/patchwebpack-hot-middleware/client到您的entry
    2. 頂部添加react-hot-loader/babelbabel-loaderplugins
    3. 添加new HotModuleReplacementPlugin()到您的WebPack插件
  3. 添加webpack-dev-middlewarewebpack-hot-middlware表示:

    // server/entry.jsx 
    const express = require('express'); 
    const path = require('path'); 
    const cons = require('consolidate'); 
    const fs = require('fs'); 
    
    const port = 5469; 
    const app = express(); 
    
    app.disable('x-powered-by'); 
    app.engine('hbs', cons.handlebars); 
    app.set('view engine', 'hbs'); 
    app.set('views', path.join(__dirname, '../views')); 
    
    const wpConfig = require("../webpack.config.js"); 
    
    if(process.env.NODE_ENV === 'development') { 
        const webpack = require('webpack'); 
        const webpackDevMiddleware = require('webpack-dev-middleware'); 
        const webpackHotMiddleware = require('webpack-hot-middleware'); 
        const compiler = webpack(wpConfig); 
    
        app.use(webpackDevMiddleware(compiler, { 
         stats: {colors: true}, 
        })); 
        app.use(webpackHotMiddleware(compiler)); 
    } 
    
    app.use(require('./routes')); 
    
    app.use(express.static(wpConfig.output.path)); 
    
    app.listen(port, function() { 
        console.log(`Listening on http://localhost:${port}`); 
    }); 
    
  4. 添加<AppContainer>react.hot到您的客戶入口點:

    // client/entry.jsx 
    import ReactDOM from 'react-dom'; 
    import App from './components/App'; 
    import { AppContainer } from 'react-hot-loader'; 
    
    function render(Root) { 
        ReactDOM.render(<AppContainer><Root/></AppContainer>, document.getElementById('react-root')); 
    } 
    
    render(App); 
    
    if(module.hot) { 
        module.hot.accept('./components/App',() => { 
         render(require('./components/App').default); 
        }); 
    } 
    
2

我遇到了一些麻煩誤差疊加呈現運行時錯誤以及從中恢復。我注意到webpack-dev-server在發生錯誤時會完全重新加載。

這可以用下面的代碼片段進行模擬:

if (module.hot) module.hot.accept('./App',() => { 
    try { 
    render(App) 
    } catch (e) { 
    location.reload(); 
    } 
}); 

我的工作fork of react-hot-boilerplate可在Github上。

0

我還添加了每一個點,我的應用程序,但它沒有工作 的問題是在publicPath在我webpack.config.js 我有

publicPath: '/client/dist' 

然後我改

publicPath: '/' 

現在它的工作原理

相關問題