Closed ghost closed 7 years ago
That error means the weback-hot-server-middleware
is being hit before the compiler is complete which is happening because you're creating and passing two different compilers to weback-dev-middleware
and weback-hot-server-middleware
.
Your app.js
should look more like this:
...
const compiler = webpack([clientConfig, serverConfig]);
// Pass the same `compiler` to both 'webpack-dev-middleware' and 'webpack-hot-server-middleware'
const webpackDevMiddlewareInstance = require('webpack-dev-middleware')(compiler);
const webpackHotServerMiddlewareInstance = require('webpack-hot-server-middleware')(compiler);
app.use(webpackDevMiddlewareInstance);
app.use(webpackHotServerMiddlewareInstance);
...
Additionally, I think you'll run into an error in your server.jsx
as it looks like you're expecting the exported function to take an html
string which you later pass to cheerio.load
... however, it will in fact receive the client stats object (to allow you to reference the webpack assets (with hash) in your html file), the export signature should be this: (stats) => (req, res, next) => void 0
.
It's also worth noting that webpack-hot-middleware
needs to be mounted in-between webpack-dev-server
and webpack-hot-server-middleware
because webpack-hot-server-middleware
doesn't call next
for any requests. You'll also need to filter out the 'server' compiler. I've been meaning to add an example using webpack-hot-middleware
to the docs but for reference it should look something like this:
const compiler = webpack(config);
app.use(webpackDevMiddleware(compiler));
app.use(webpackHotMiddleware(compiler.compilers.find(compiler => compiler.name === 'client')));
app.use(webpackHotServerMiddleware(compiler));
Thanks so much for the help! I'm still getting the same error and a new one now actually though...
The new error is right after webpack bundles build:
error: Error: illegal operation on a directory
at MemoryFileSystem.readFileSync ([...]/node_modules/memory-fs/lib/MemoryFileSystem.js:112:10)
at MultiCompiler.multiCompiler.plugin.ex ([...]/node_modules/webpack-hot-server-middleware/src/index.js:119:33)
Here's the updated app.js:
...
const webpack = require('webpack');
const clientConfig = require(path.join(__dirname, '/config/webpack.config.client.js'));
const serverConfig = require(path.join(__dirname, '/config/webpack.config.server.js'));
const devServerConfig = clientConfig.devServer;
const compiler = webpack([clientConfig, serverConfig]);
app.use(clientConfig.output.publicPath, express.static(clientConfig.output.path));
app.use(express.static(path.join(__dirname, 'public')));
app.use(express.static(path.join(__dirname, 'public/favicons')));
if (process.env.NODE_ENV === 'development') {
const webpackDevMiddlewareInstance = require('webpack-dev-middleware')(compiler);
const webpackHotServerMiddlewareInstance = require('webpack-hot-server-middleware')(compiler);
app.use(webpackDevMiddlewareInstance);
if (devServerConfig.hot) {
app.use(require('webpack-hot-middleware')(compiler.compilers.find(compiler => compiler.name === 'client'), {
log: console.log,
path: '/__webpack_hmr',
heartbeat: 10000
}));
}
app.use(webpackHotServerMiddlewareInstance);
}
var server = http.createServer(app);
server.listen(port, () => console.log('Server started', server.address()));
...
Updated server.jsx:
...
module.exports = function(stats) {
console.log(require('util').inspect(stats, { depth: 3 }));
return function (req, res) {
var routes = require('./routes.jsx');
var store = configureStore();
var css = [];
match({
routes: routes.default,
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) {
var body = ReactDOMServer.renderToString(
<ServerRoot store={store} renderProps={renderProps} onInsertCss={(...styles) => {
styles.forEach(style => css.push(style._getCss()));
}}/>
);
const state = store.getState();
var $ = cheerio.load();
$('#server-style').html(css.join(''));
$('#redux-state').html('window.__REDUX_STATE__ = ' + JSON.stringify(state).replace(/<\/script/g, '<\\/script').replace(/<!--/g, '<\\!--') + ';');
$('#app').html('<div>' + body + '</div>');
res.set('content-type', 'text/html');
res.send($.html());
res.end();
} else {
res.status(404).send('Not found')
}
});
}
}
Let me know if there's anything else I can provide that may be screwing it up. Thanks again.
@DragonFire353 Everything looks alright there in terms of setup so it must be related to to your webpack.config
; it might be that you've given your entry point an explicit name other than 'main'?
Are you able to put up a repo so I can reproduce the issue or maybe at least paste your webpack config?
@DragonFire353 I'm going to close this for now as I think it's a usage issue, feel free to continue the discussion here if you like as I may still be able to help.
Hi,
I am running into a similar issue (related to memory), below you can find my webpack config file and how I use it in the server.
/Users/emmanuel/Projects/javascript/react-isomorphic/node_modules/webpack-dev-middleware/node_modules/memory-fs/lib/MemoryFileSystem.js:
112
throw new MemoryFileSystemError(errors.code.EISDIR, _path);
^
Error
at MemoryFileSystem.readFileSync (/Users/emmanuel/Projects/javascript/react-isomorphic/node_modules/webpack-dev-middleware/node_modu
les/memory-fs/lib/MemoryFileSystem.js:112:10)
at MultiCompiler.multiCompiler.plugin.multiStats (/Users/emmanuel/Projects/javascript/react-isomorphic/node_modules/webpack-hot-serv
er-middleware/src/index.js:119:33)
at MultiCompiler.applyPlugins (/Users/emmanuel/Projects/javascript/react-isomorphic/node_modules/tapable/lib/Tapable.js:26:37)
at MultiCompiler.<anonymous> (/Users/emmanuel/Projects/javascript/react-isomorphic/node_modules/webpack/lib/MultiCompiler.js:76:10)
at Compiler.applyPlugins (/Users/emmanuel/Projects/javascript/react-isomorphic/node_modules/tapable/lib/Tapable.js:26:37)
at Watching._done (/Users/emmanuel/Projects/javascript/react-isomorphic/node_modules/webpack/lib/Compiler.js:78:17)
at Watching.<anonymous> (/Users/emmanuel/Projects/javascript/react-isomorphic/node_modules/webpack/lib/Compiler.js:61:18)
at Compiler.emitRecords (/Users/emmanuel/Projects/javascript/react-isomorphic/node_modules/webpack/lib/Compiler.js:282:37)
at Watching.<anonymous> (/Users/emmanuel/Projects/javascript/react-isomorphic/node_modules/webpack/lib/Compiler.js:58:19)
at /Users/emmanuel/Projects/javascript/react-isomorphic/node_modules/webpack/lib/Compiler.js:275:11
webpack.server.config.js
const webpack = require('webpack');
const path = require('path');
const fs = require('fs');
const SRC_DIR = path.join(__dirname, './src');
const DIST_DIR = path.join(__dirname, './dist');
const clientConfig = {
name: 'client',
context: SRC_DIR,
entry: {
client: ['react-hot-loader/patch',
'webpack-hot-middleware/client',
'./client/index'] },
output: {
path: DIST_DIR,
filename: 'bundle.js',
publicPath: '/static/'
},
module: {
loaders: [
{
test: /\.js$/,
loaders: ['babel-loader', 'eslint-loader'],
exclude: /node_modules/
}
]
},
resolve: {
root: [
SRC_DIR
]
},
target: 'web',
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin()
],
node: {
fs: 'empty' // ,
// process: false
},
bail: false,
devtool: 'inline-source-map',
eslint: {
configFile: './.eslintrc'
}
};
const serverConfig = {
name: 'server',
context: SRC_DIR,
entry: { server: ['../server.babel'] },
output: {
path: DIST_DIR,
filename: 'server.bundle.js',
libraryTarget: 'commonjs2'
},
module: {
loaders: [
{
test: /\.js$/,
loaders: ['babel-loader', 'eslint-loader'],
exclude: /node_modules/
},
{
test: /\.json$/,
loader: 'json-loader'
}
]
},
resolve: {
root: [
SRC_DIR
]
},
target: 'node',
node: {
process: false
},
bail: false,
externals: fs.readdirSync('node_modules')
.filter((x) => !x.includes('.bin'))
.reduce((externals, mod) => {
const mods = externals;
mods[mod] = `commonjs ${mod}`;
return mods;
}, {}),
devtool: 'source-map',
eslint: {
configFile: './.eslintrc'
}
};
module.exports = [clientConfig, serverConfig];
server.js
import path from 'path';
import express from 'express';
import bodyParser from 'body-parser';
// HMR
import webpack from 'webpack';
import webpackDevMiddleware from 'webpack-dev-middleware';
import webpackHotMiddleware from 'webpack-hot-middleware';
import webpackHotServerMiddleware from 'webpack-hot-server-middleware';
import config from './webpack.server.config';
// HMR
import routermgr from './src/infra/route-manager';
const app = express();
...
// HMR
const compiler = webpack(config);
app.use(webpackDevMiddleware(compiler, {
quiet: false,
publicPath: config[0].output.publicPath
}));
app.use(webpackHotMiddleware(compiler.compilers.find((cmp) => cmp.name === 'client'), {
log: () => {}
}));
app.use(webpackHotServerMiddleware(compiler));
routermgr.handle(app);
app.listen(3000, () => {
console.log('Server listening at port 3000');
});
I am pretty sure it is something related to the configuration but I have moved some pieces with no luck.
@emmanuel-mendoza it looks like the entry point to your server bundle is the server itself however webpack-hot-server-middleware
expects it to be a middleware function, e.g. https://github.com/60frames/webpack-hot-server-middleware/blob/master/example/server.js
The idea is for your main server to be just a regular, non bundled express server which use()
s webpackDevMiddleware
, webpackHotMiddleware
and webpackHotServerMiddleware
, e.g. https://github.com/60frames/webpack-hot-server-middleware/blob/master/example/index.js
@richardscarrott thank you for pointing that. I needed to refactor the code because of this and node the code is compiling ok (both client and server), but for some reason the server bundle is not recognizing the request object from express lib. I have played a bit with some webpack options but again I feel stuck on this. This is how my code looks like now: webpack configuration file: https://github.com/emmanuel-mendoza/react-isomorphic/blob/master/webpack.server.config.js server middleware file: https://github.com/emmanuel-mendoza/react-isomorphic/blob/master/src/infra/route-manager.js
@emmanuel-mendoza it looks like your middleware (route-manager.js
) exports a function expecting the req
, res
, next
args however webpack hot server middleware expects it to export a function of this format -- (stats) => (req, res, next) => void
-- so you need to wrap it in another function. e.g. https://github.com/60frames/webpack-hot-server-middleware/blob/master/example/server.js
@richardscarrott I just tried your suggestion (these have been crazy days at work) and now it works like a charm, thank you!
Also stumbled upon this "serverRenderer is not a function" error. I start the server and this error appears in console until bundle is ready. @richardscarrott how do you think, could that be a reason if my server bundle is much smaller than my client bundle?
about illegal operation on a directory
error: if you have multi entry server, make sure to specify the chunkName:
entry: {
index: './src/server.js',
},
app.use(webpackHotServerMiddleware(compiler, { chunkName: 'index' }));
@DragonFire353
Reiterating what @elado has stated. I was getting TypeError: serverRenderer is not a function
error. Turns out it is because the default chunkName used in the middleware is main
.
it is assumed that your webpack.config.js
uses
entry: './src/server.js'
which will generate the main.bundle.js
chunk
if instead you use
entry: {
server: './src/server.js',
},
then you have to specify your chunkName
as an option in the options
app.use(webpackHotServerMiddleware(compiler, { chunkName: 'index' }));
I don't get the error until I try to load the page:
server.jsx:
app.js:
I may be doing something very wrong or incorrectly since I am still relatively new to all of this.
Thanks.