Code Monkey home page Code Monkey logo

webpack-hot-server-middleware's People

Contributors

faceyspacey avatar forabi avatar industrial avatar klis87 avatar maystrenkoyurii avatar mohsen1 avatar okcoker avatar pho3nixf1re avatar richardscarrott avatar roastlechon avatar sompylasar avatar swatinem avatar zinserjan avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

webpack-hot-server-middleware's Issues

Dynamically / lazily loaded chunks throw an error

Hello, I'm trying to implement this with Angular2. Everything seems to be working fine client side, but SSR is not working with "lazy-loaded" chunks Error: Cannot find module './0.server.js'.

I tried using LimitChunkCountPlugin but the rabbit hole seemed to be deeper. Now I looked at the MemoryFileSystem and the file is definitely there.

Eventually I got it to work, but I had to run a build before running the server, which is weird, it seems like it needs the disk files to be there before starting, but it still uses the memory files. I know it doesn't use disk files because deleting their content doesn't change the outcome, and changes to /src files (i.e. rebuilding) doesn't change them, however, if I delete the file from disk, it bugs out again. πŸ˜•

Here's the branch I'm working on https://github.com/S-Intelligent-Technologies/sit-ngx-starter/tree/fm-better-hmr

Breaks with Webpack-3.1.0

I am not sure why this happens, but in my otherwise unchanged setup, updating to Webpack-3.1.0 breaks this package.

[00:08:58] Error: Expected webpack compiler to contain both a 'client' and 'server' config
    at webpackHotServerMiddleware (/Users/sebastian/Workspace/sebastian-software/edge-boilerplate/node_modules/webpack-hot-server-middleware/src/index.js:88:15)
    at addDevMiddleware (/Users/sebastian/Workspace/sebastian-software/edge-boilerplate/node_modules/edge-builder/src/express/dev.js:42:14)
    at Gulp.startDevServer (/Users/sebastian/Workspace/sebastian-software/edge-boilerplate/node_modules/edge-builder/lib/node.commonjs.js:600:3)
    at module.exports (/Users/sebastian/Workspace/sebastian-software/edge-boilerplate/node_modules/orchestrator/lib/runTask.js:34:7)
    at Gulp.Orchestrator._runTask (/Users/sebastian/Workspace/sebastian-software/edge-boilerplate/node_modules/orchestrator/index.js:273:3)
    at Gulp.Orchestrator._runStep (/Users/sebastian/Workspace/sebastian-software/edge-boilerplate/node_modules/orchestrator/index.js:214:10)
    at Gulp.Orchestrator.start (/Users/sebastian/Workspace/sebastian-software/edge-boilerplate/node_modules/orchestrator/index.js:134:8)
    at /Users/sebastian/Workspace/sebastian-software/edge-boilerplate/node_modules/gulp/bin/gulp.js:129:20
    at _combinedTickCallback (internal/process/next_tick.js:95:7)
    at process._tickCallback (internal/process/next_tick.js:161:9)
    at Function.Module.runMain (module.js:607:11)
    at startup (bootstrap_node.js:158:16)
    at bootstrap_node.js:575:3

Webpack is triggered by Gulp as you can see.

This here is the initialization code:

  const clientConfig = configBuilder({
    target: "client",
    env: "development"
  })

  const serverConfig = configBuilder({
    target: "server",
    env: "development"
  })

  const multiCompiler = webpack([ clientConfig, serverConfig ])
  const clientCompiler = multiCompiler.compilers[0]

  server.use(webpackDevMiddleware(multiCompiler, {
    // required
    publicPath: PUBLIC_PATH,

    // display no info to console (only warnings and errors)
    noInfo: true
  }))

  server.use(webpackHotMiddleware(clientCompiler))

  // keeps serverRender updated with arg: { clientStats, outputPath }
  server.use(webpackHotServerMiddleware(multiCompiler, {
    serverRendererOptions: {
      outputPath: CLIENT_OUTPUT
    }
  }))

Do you have any idea for a fix?

serverRenderer is not a function

The error pops us in development when adding webpack-hot-server-middleware. Below is my express.js and config/webpack.dev-client.js.

express.js:

import express from 'express';
import webpack from 'webpack'
const expressStaticGzip = require('express-static-gzip')
import webpackHotServerMiddleware from 'webpack-hot-server-middleware';

const server = express()

import configDevClient from '../../config/webpack.dev-client'
import configDevServer from '../../config/webpack.dev-server'
import configProdClient from '../../config/webpack.prod-client'
import configProdServer from '../../config/webpack.prod-server'

const isProd = process.env.NODE_ENV === 'production';

if (!isProd) {
	const compiler = webpack([configDevClient, configDevServer])

	const clientCompiler = compiler.compilers[0]
	const serverCompiler = compiler.compilers[1]

	const webpackDevMiddleware = require('webpack-dev-middleware')(compiler, configDevClient.devServer)
	const webpackHotMiddleware = require('webpack-hot-middleware')(clientCompiler, configDevClient.devServer)

	server.use(webpackDevMiddleware)
	server.use(webpackHotMiddleware)
	server.use(webpackHotServerMiddleware(compiler))
} else {
	webpack([configProdClient, configProdServer]).run((err, stats) => {
		const render = require('../../build/prod.server.bundle.js').default

		server.use(expressStaticGzip('dist', { enableBrotli: true }))

		server.use(render());
	})
}

const port = process.env.PORT || 8080

server.listen(port, () => console.log(`Server's running on http://localhost:${port}.`));

webpack.dev-client.js:

const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

const isProd = process.env.NODE_ENV === 'production';

module.exports = {
	name: 'client',
	entry: {
		main: [
			'babel-polyfill',
			'babel-runtime/regenerator',
			'webpack-hot-middleware/client?reload=true',
			'./src/main'
		],
	},
	resolve: {
		extensions: [".js", ".ts"]													// add extensions to entry files above
	},
	mode: 'development',
	output: {
		filename: 'dev.client.bundle.js',
		path: path.resolve(__dirname, '../dist')
	},
	devServer: {
		contentBase: 'dist',
		historyApiFallback: true,
		overlay: true,
		hot: true,
		stats: {
			colors: true
		}
	},
	optimization: {
		splitChunks: {
			chunks: 'all',
			cacheGroups: {
				vendor: {
					name: 'vendor',
					chunks: 'initial',
					minChunks: 2
				}
			}
		}
	},
	devtool: 'source-map',
	module: {
		rules: [
			{
				test: /\.js$/,
				use: [
					{ loader: 'babel-loader' }
				],
				exclude: /node_modules/
			},
			{
				test: /\.ts$/,
				use: [
					{ loader: 'awesome-typescript-loader' }
				],
				exclude: /node_modules/
			},
			{
				test: /\.css$/,
				use: [
					{
						// loader: 'style-loader'
						loader: MiniCssExtractPlugin.loader
					},
					{
						loader: 'css-loader',
						options: {
							sourceMap: true
						}
					}
				]
			},
			{
				test: /\.sass$/,
				use: [
					{ loader: 'style-loader' },
					{ loader: 'css-loader' },
					{ loader: 'sass-loader' }
				]
			},
			{
				test: /\.styl$/,
				use: [
					{ loader: 'style-loader' },
					{ loader: 'css-loader' },
					{ loader: 'postcss-loader' },
					{ loader: 'stylus-loader' }
				]
			},
			{
				test: /\.less$/,
				use: [
					{ loader: 'style-loader' },
					{ loader: 'css-loader' },
					{ loader: 'less-loader' }
				]
			},
			{
				test: /\.html$/,
				use: [
					{
						loader: 'html-loader',
						options: {
							attrs: ['img:src']
						}
					}
				]
			},
			{
				test: /\.pug$/,
				use: [
					{ loader: 'pug-loader' }
				]
			},
			{
				test: /\.hbs$/,
				use: [
					{
						loader: 'handlebars-loader',
						query: {
							inlineRequires: '/images/'
						}
					}
				]
			},
			{
				test: /\.(png|svg|gif|jpe?g)$/,
				use: [
					{
						loader: 'file-loader',
						options: {
							name: 'images/[name].[hash:8].[ext]'
						}
					}
				]
			},
			{
				test: /\.md$/,
				use: [
					{ loader: 'markdown-with-front-matter-loader' }
				]
			}
		]
	},
	plugins: [
		new webpack.HotModuleReplacementPlugin(),
		new MiniCssExtractPlugin({ filename: '[name].css' }),
		new BundleAnalyzerPlugin({
			generateStatsFile: true,
			analyzerMode: 'server',
			openAnalyzer: false
		})
	]
};

The full repo is at https://github.com/ElAnonimo/webpack4

Bundle is returning empty object

Hi. I needed this PR to be able to run my new setup: Babel7 (+ TypeScript), Webpack4, React + Redux, SSR and HMR (universal). It's at https://github.com/Industrial/universal-demo

Could you please try git clone https://github.com/Industrial/universal-demo; cd universal-demo; npm i; npm run start; and then open http://localhost:3000 ?

I am getting the error

Error: The 'server' compiler must export a function in the form of `(options) => (req, res, next) => void`
    at getServerRenderer (/home/tom/Code/Code9/JavaScript/Projects/universal-demo/node_modules/webpack-hot-server-middleware/src/index.js:68:15)
    at doneHandler (/home/tom/Code/Code9/JavaScript/Projects/universal-demo/node_modules/webpack-hot-server-middleware/src/index.js:159:30)
    at SyncHook.eval (eval at create (/home/tom/Code/Code9/JavaScript/Projects/universal-demo/node_modules/tapable/lib/HookCodeFactory.js:17:12), <anonymous>:9:1)
    at SyncHook.lazyCompileHook [as _call] (/home/tom/Code/Code9/JavaScript/Projects/universal-demo/node_modules/tapable/lib/Hook.js:35:21)
    at MultiCompiler.compiler.hooks.done.tap.stats (/home/tom/Code/Code9/JavaScript/Projects/universal-demo/node_modules/webpack/lib/MultiCompiler.js:45:22)
    at AsyncSeriesHook.eval [as callAsync] (eval at create (/home/tom/Code/Code9/JavaScript/Projects/universal-demo/node_modules/tapable/lib/HookCodeFactory.js:24:12), <anonymous>:18:1)
    at AsyncSeriesHook.lazyCompileHook [as _callAsync] (/home/tom/Code/Code9/JavaScript/Projects/universal-demo/node_modules/tapable/lib/Hook.js:35:21)
    at Watching._done (/home/tom/Code/Code9/JavaScript/Projects/universal-demo/node_modules/webpack/lib/Watching.js:99:28)
    at compiler.emitRecords.err (/home/tom/Code/Code9/JavaScript/Projects/universal-demo/node_modules/webpack/lib/Watching.js:73:19)
    at Compiler.emitRecords (/home/tom/Code/Code9/JavaScript/Projects/universal-demo/node_modules/webpack/lib/Compiler.js:295:39)

I don't know what I'm doing wrong anymore :-(

My entry chunk is renamed to an async chunk

I am having issues when adding magic comments to my dynamic import using react-reloadable, Instead of receiving "main" i get "Home" which is a loadable component.

Here is my server config.

const path = require('path');
const webpack = require('webpack');
const externals = require('./node-externals');
const FriendlyErrorsWebpackPlugin = require('friendly-errors-webpack-plugin');

module.exports = {
name: 'server',
target: 'node',
externals,
entry: './server/renderer.js',
mode: 'development',
output: {
filename: 'dev-server-bundle.js',
chunkFilename: '[name].js',
path: path.resolve(__dirname, '../build'),
libraryTarget: 'commonjs2'
},
devtool: 'inline-sourcemaps',
module: {
rules: [
{
test: /.js$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader'
}
]
},
{
test: /.css$/,
use: {
loader: 'css-loader',
options: {
minimize: true
}
}
},
{
test: /.scss$/,
use: [
{
loader: 'css-loader',
options: {
minimize: true
}
},
{
loader: 'postcss-loader'
},
{
loader: 'sass-loader'
}
]
},
{
test: /.(jpg|png|gif)$/,
use: [
{
loader: 'file-loader',
options: {
name: '/images/[name].[ext]',
emitFile: false
}
}
]
}
]
},
plugins: [
new FriendlyErrorsWebpackPlugin(),
new webpack.optimize.LimitChunkCountPlugin({
maxChunks: 1
}),
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('development')
}
})
]
};

Hangs when errors are thrown inside server bundle

The middleware seems to hang with no output when my server bundle encounters an error. Only upon exiting the process does the error trace print to stddout.

Middleware implementation is standard:

const compiler = webpack([client, server]);
  app.use(
    webpackDevMiddleware(compiler, {
      noInfo: true,
      stats: {
        warnings: false,
        colors: true,
        timings: true
      },
      publicPath: client.output.publicPath
    })
  );
  app.use(webpackHotMiddleware(compiler.compilers[0], { path: '/__hmr' }));
  app.use(webpackHotServerMiddleware(compiler));

I can reproduce by throwing anywhere in the render/server bundle. Otherwise the middleware works normally. Is this a limitation or something I haven't configured correctly?

Server middleware fires twice for each request?

clone the repo

  980  git clone https://github.com/60frames/webpack-hot-server-middleware.git
  981  cd webpack-hot-server-middleware/example/
  982  yarn

edit the server middleware:

module.exports = function serverRenderer({ clientStats, serverStats, foo }) {
    return (req, res, next) => {
	console.log("here");
        res.status(200).send(`
cescoferraro in ~/go/src/github.com/cescoferraro/webpack-hot-server-middleware/example
$ yarn start
yarn start v0.22.0
$ node index.js 
Server started: http://localhost:6060/
here
here

Why the server middleware get fired twice by hitting the browser only once?? I am seeing this behavior on my actual project and it breaks isomorphic-syle-loader.

JavaScript heap out of memory

This memory error is happening more often with webpack3.
I wonder if we could debounce the saving hook.
I find myself saving each file multiple times for formating reasons that dont actually matter to the result I expect to see.


<--- Last few GCs --->

  439036 ms: Mark-sweep 1218.2 (1439.7) -> 1217.6 (1439.7) MB, 947.7 / 0.0 ms [allocation failure] [GC in old space requested].
  439964 ms: Mark-sweep 1217.6 (1439.7) -> 1217.6 (1439.7) MB, 928.0 / 0.0 ms [allocation failure] [GC in old space requested].
  440895 ms: Mark-sweep 1217.6 (1439.7) -> 1229.9 (1408.7) MB, 930.6 / 0.0 ms [last resort gc].
  441901 ms: Mark-sweep 1229.9 (1408.7) -> 1245.4 (1407.7) MB, 1005.2 / 0.0 ms [last resort gc].


<--- JS stacktrace --->

==== JS stack trace =========================================

Security context: 0x104cc3fcfb39 <JS Object>
    1: DoJoin(aka DoJoin) [native array.js:~129] [pc=0xa2d363e0857] (this=0x104cc3f04381 <undefined>,w=0x16dc614e4c89 <JS Array[4429]>,x=4429,N=0x104cc3f043c1 <true>,J=0x104cc3f04411 <String[0]: >,I=0x104cc3fb46c9 <JS Function ConvertToString (SharedFunctionInfo 0x104cc3f52dc9)>)
    2: Join(aka Join) [native array.js:180] [pc=0xa2d36a50492] (this=0x104cc3f04381 <undefined>,w=0x16dc614e4c89 <JS...

FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - JavaScript heap out of memory
 1: node::Abort() [/Users/cesco/.nvm/versions/node/v6.10.1/bin/node]
 2: node::FatalException(v8::Isolate*, v8::Local<v8::Value>, v8::Local<v8::Message>) [/Users/cesco/.nvm/versions/node/v6.10.1/bin/node]
 3: v8::internal::V8::FatalProcessOutOfMemory(char const*, bool) [/Users/cesco/.nvm/versions/node/v6.10.1/bin/node]
 4: v8::internal::Factory::NewRawTwoByteString(int, v8::internal::PretenureFlag) [/Users/cesco/.nvm/versions/node/v6.10.1/bin/node]
 5: v8::internal::Runtime_StringBuilderConcat(int, v8::internal::Object**, v8::internal::Isolate*) [/Users/cesco/.nvm/versions/node/v6.10.1/bin/node]
 6: 0xa2d335092a7

filtering websocket webpack-hot-reloading calls from react-hot-server-middleware

I am using webpack-hot-reloading and react-hot-server-middleware`:

  app.use(require('webpack-dev-middleware')(multiCompiler, { serverSideRender: true }));
  app.use(require('webpack-hot-middleware')(clientCompiler));

But my websocket calls are coming through to the middleware and I have some poor code to filter them out:

    export default ({ clientStats }: { clientStats: any }) => async (req: Request, res: Response, next: any) => {
      // TODO: find a better way of filtering websocket hot reloading
      if (some(['sockjs', 'hot-update.json'], part => req.url.indexOf(part) > -1)) {
        next();
        return;
      }
    
      // render html
    `);
    };

Is there a better way?

url driven serverRendererOptions data?

Hi!
whether it is possible connect serverRendererOptions with fetched data?

app.use('/urlPath/:id',webpackHotServerMiddleware(compiler, {
	serverRendererOptions: {
		data: fetchedData // how to?
	}
}));

like this:

app.get('/path/:id', (req, res) => {
    firebaseDatabase.getData(req.params.id).then(resp => {
res.send(resp)
......

Error: The 'server' compiler must export a function in the form of `(options) => (req, res, next) => void`

My server.js:

import React from 'react';
import ReactDOMServer from 'react-dom/server';
import App from './src/components/App';
import data from './src/testData.json';

export default options => (req, res, next) => {
  res.status(200).send(`
  <!doctype html>
  <html>
  <head>
      <title>App</title>
  </head>
  <script>window._initialData = ${JSON.stringify(data.contests)}</script>
  <body>
      <div id="root">
          ${ReactDOMServer.renderToString(<App initialContests={data.contests}/>)}
      </div>
      <script src="/bundle.js"></script>
  </body>
  </html>
  `);
};

MemoryFileSystemError

const SERVER = require("./www/server.bundle").default;
const express = require("express");
const webpack = require('webpack');
const webpackDevMiddleware = require('webpack-dev-middleware');
const webpackHotMiddleware = require('webpack-hot-middleware');
// const webpackHotServerMiddleware = require('webpack-hot-server-middleware');
const app = express();
const PORT = 3000;
const compiler = webpack(require('./build/webpack/prod.js'));
app.use(webpackDevMiddleware(compiler));
app.use(webpackHotMiddleware(compiler.compilers.find(compiler => compiler.name === 'client')));
// app.use(webpackHotServerMiddleware(compiler));
app.use(SERVER);
app.listen(PORT, console.log.bind("listening at http://localhost:" + PORT));

If I uncomment the lines (webpackHotServerMiddleware itself) above, my build errors

/home/cescoferraro/code/go/src/github.com/cescoferraro/spotify/node_modules/webpack-dev-middleware/node_modules/memory-fs/lib/MemoryFileSystem.js:112
			throw new MemoryFileSystemError(errors.code.EISDIR, _path);
         ^
Error
    at MemoryFileSystem.readFileSync (/home/cescoferraro/code/go/src/github.com/cescoferraro/spotify/node_modules/webpack-dev-middleware/node_modules/memory-fs/lib/MemoryFileSystem.js:112:10)
    at MultiCompiler.multiCompiler.plugin.multiStats (/home/cescoferraro/code/go/src/github.com/cescoferraro/spotify/node_modules/webpack-hot-server-middleware/src/index.js:119:33)
    at MultiCompiler.applyPlugins (/home/cescoferraro/code/go/src/github.com/cescoferraro/spotify/node_modules/tapable/lib/Tapable.js:25:14)
    at MultiCompiler.<anonymous> (/home/cescoferraro/code/go/src/github.com/cescoferraro/spotify/node_modules/webpack/lib/MultiCompiler.js:76:10)
    at Compiler.applyPlugins (/home/cescoferraro/code/go/src/github.com/cescoferraro/spotify/node_modules/tapable/lib/Tapable.js:25:14)
    at Watching._done (/home/cescoferraro/code/go/src/github.com/cescoferraro/spotify/node_modules/webpack/lib/Compiler.js:93:17)
    at /home/cescoferraro/code/go/src/github.com/cescoferraro/spotify/node_modules/webpack/lib/Compiler.js:76:18
    at Compiler.emitRecords (/home/cescoferraro/code/go/src/github.com/cescoferraro/spotify/node_modules/webpack/lib/Compiler.js:350:37)
    at /home/cescoferraro/code/go/src/github.com/cescoferraro/spotify/node_modules/webpack/lib/Compiler.js:59:19
    at /home/cescoferraro/code/go/src/github.com/cescoferraro/spotify/node_modules/webpack/lib/Compiler.js:343:11
    at next (/home/cescoferraro/code/go/src/github.com/cescoferraro/spotify/node_modules/tapable/lib/Tapable.js:118:11)
    at Compiler.<anonymous> (/home/cescoferraro/code/go/src/github.com/cescoferraro/spotify/node_modules/webpack/lib/performance/SizeLimitsPlugin.js:115:3)
    at Compiler.applyPluginsAsyncSeries1 (/home/cescoferraro/code/go/src/github.com/cescoferraro/spotify/node_modules/tapable/lib/Tapable.js:122:13)
    at Compiler.afterEmit (/home/cescoferraro/code/go/src/github.com/cescoferraro/spotify/node_modules/webpack/lib/Compiler.js:340:8)
    at Compiler.<anonymous> (/home/cescoferraro/code/go/src/github.com/cescoferraro/spotify/node_modules/webpack/lib/Compiler.js:335:14)
    at /home/cescoferraro/code/go/src/github.com/cescoferraro/spotify/node_modules/webpack/node_modules/async/dist/async.js:356:16

Avoid passing in compiler options to `serverRenderer`

It doesn't make sense to pass in the compiler options to serverRenderer as there is no corresponding compiler options in production. -- see #18

Prob want to do something like this instead:

// server.js
app.use(webpackHotServerMiddleware(compiler, {
    serverRendererOptions: {
        // Consumers can add whatever they want here.
        foo: 'bar'
    }
}))

// serverRenderer.js
export default (clientStats, serverStats, options) => (req, res, next) => {
    console.log(clientStats); // Stats
    console.log(serverStats); // Stats
    console.log(options.foo); // 'bar'
}

// OR

export default (stats, options) => (req, res, next) => {
    console.log(stats.client); // Stats
    console.log(stats.server); // Stats
    console.log(options.foo); // 'bar'
}

// OR

export default options => (req, res, next) => {
    console.log(options.clientStats); // Stats
    console.log(options.serverStats); // Stats
    console.log(options.foo); // 'bar'
}

Get back to 100% coverage

Coverage has dipped below 100% due to the 958d897 because the source file always exists.

I think the only way to get into the catch would be to trigger an error somewhere other than the webpack bundle although that's not particularly useful as a test so could just put some instanbul ignore comments in the catch.

It'd also be nice to look into testing source maps more seriously buy trigger an error and checking the stack trace is mapped to the source files.

webpackDevMiddleware fails to host files at publicPath

I've fallen back to using new WriteFilePlugin()

and

app.use(
  publicPath,
  express.static(outputPath),
)

I.e. hosting the files from the file system manually. But I shouldn't have to do that. I noticed this PR to webpack-dev-middleware:

webpack/webpack-dev-middleware#151

So I'm curious how this package successfully hosted files if webpack-dev-middleware itself is struggling to host files from a multi-compiler.

...ps. otherwise, amazing package! I love that require-from-string implementation, pure magic!

webpack-loaders

Great work @richardscarrott!

I dont know if people have made requests about this by now but i will try:
I am working on extensive-react-server with preconfigured setup, fully editable.
Here i am using webpack-hot-server-middleware as a feature in development mode.

The problem is: Using custom plugins og loaders with webpack

Works fine when i use babel-loader
Crashes when i add style-loader returing a 404 Not Found

Any way around this?

Integration with koa middlewares.

I'm trying to get library up with koa2 server based middleware, but i end up with the error below.


/Users/prithviraju/Sites/site/node_modules/memory-fs/lib/MemoryFileSystem.js:112
                        throw new MemoryFileSystemError(errors.code.EISDIR, _path);
         ^
Error
    at MemoryFileSystem.readFileSync (/Users/prithviraju/Sites/site/node_modules/memory-fs/lib/
MemoryFileSystem.js:112:10)
    at MultiCompiler.multiCompiler.plugin.multiStats (/Users/prithviraju/Sites/site/node_module
s/webpack-hot-server-middleware/src/index.js:119:33)
    at MultiCompiler.applyPlugins (/Users/prithviraju/Sites/site/node_modules/tapable/lib/Tapab
le.js:61:14)

I'm using koa connect library to achieve the compatibility by wrapping connect middleware, but stuck with the error. Its possibly related to #7 and because of the function signature of entry point needed (stats) => (req, res, next) => void, not sure how to make it a koa based one, tried wrapping in koa connect, but no avail.
Please point me in some direction.

Add a way to manage state/resources

Hello,

first, thanks for webpack-hot-server-middleware - it's been a pleasure to use so far!

Today, I ran into the following problem: My server renderer needs to regularly pull resources from a 3rd-party API, which is then used to render the application. To achieve that, I added a simple function that is called using setInterval. Now when a new webpack build replaces the old one, I need to clear that timer again in order to 1) allow for garbage-collection of the old build 2) stop that old timer to avoid accumulating multiple versions.

I've solved the problem by allowing the serverRenderer-Module to export a dispose function, which is called before the new build is activated. A quick & dirty implementation is here: aflatter@754a049

Is there another way to solve this without touching webpack-hot-server-middleware? I've thought about passing in the timer logic as an option to the server renderer, but then I lose hot-reloading of that logic.

If there is no other way, I'd love to get input on a possible API that might also allow keeping state between two different builds:

// serverRenderer.js
export function serverRenderer({clientStats, serverStats, state}) {
  // Before this server renderer is replaced, this function is called and has the chance to return a new state that will be passed to the next server renderer.
  const replacementHandler = () => {
    const {versions} = state || {}
    return {versions: versions + 1}
  }

  // This is the actual function that handles incoming requests.
  const requestHandler = (req, res, next) => {
    res.status(200).send(`Hello world, I am server renderer #${state.versions}!`)
  }

  return {replacementHandler, requestHandler}
})

Would you accept that kind of functionality? Thanks!

is it possible to call the default route from another route in express

Hi,

In webpack-hot-server-middleware you have your serverRender function and you set up dev and prod like this:

const express = require('express');
const path = require('path');
const app = express();

if (process.env.NODE_ENV !== 'production') {
    const webpack = require('webpack');
    const webpackDevMiddleware = require('webpack-dev-middleware');
    const webpackHotMiddleware = require('webpack-hot-middleware');
    const webpackHotServerMiddleware = require('webpack-hot-server-middleware');
    const config = require('./webpack.config.js');
    const compiler = webpack(config);
    app.use(webpackDevMiddleware(compiler, {
      serverSideRender: true
    }));
    app.use(webpackHotMiddleware(compiler.compilers.find(compiler => compiler.name === 'client')));
    app.use(webpackHotServerMiddleware(compiler));
} else {
    const CLIENT_ASSETS_DIR = path.join(__dirname, '../build/client');
    const CLIENT_STATS_PATH = path.join(CLIENT_ASSETS_DIR, 'stats.json');
    const SERVER_RENDERER_PATH = path.join(__dirname, '../build/server.js');
    const serverRenderer = require(SERVER_RENDERER_PATH);
    const stats = require(CLIENT_STATS_PATH);
    app.use(express.static(CLIENT_ASSETS_DIR));
    app.use(serverRenderer(stats));
}

Say I have a non root url like some-root is it possible for me to call the serverRenderer function without redirecting? All I can think to do is this.

express.Router().post('/other-route', (_: Request, res: Response) => {
  // do stuff

  res.redirect('/');
});

Access the compiler instance from the 'serverRenderer' middleware

I was wondering if it would be possible to expose a reference to the compiler in the serverRenderer middleware as you do with the stats.

I want to access a file in the outputFS of the compiler (in memory) and use it to render the HTML of the page in the Server-Side Rendering way.

Would it be possible? I would like to know what you think about this, as I think it would bring flexibility to the serverRenderer middleware.

Fix TS types

Following the Koa example, it seems some TS definitions are missing or out of sync with the lib.

Adding middleware requires any casting, such as:

app.use(webpackHotServerMiddleware(compiler, {
  createHandler: (webpackHotServerMiddleware as any).createKoaHandler,
}) as any);

... because:

  1. webpackHotServerMiddleware, by default, returns an Express middleware signature, not Koa.
  2. webpackHotServerMiddleware.createKoaHandler (and probably other handlers) are lacking definitions.

Production setup

Is there any suggested setup for production?

In my mind, it would be something like:

app.use(webpackDevMiddleware(compiler, {
    noInfo: true
}));

if (procsss.env.NODE_ENV !== 'production') {
  app.use(webpackHotServerMiddleware(compiler));
} else {
  app.use((req, res) => {
    const stat = require(dist + '/stat.json')
    const server = require(dist + '/server')
    server(stat)(req, res)
  });
}

app.listen(6060, () => {
    console.log('Server started: http://localhost:6060/');
});

TypeError: serverRenderer is not a function on initial page load

I was getting an error from the title when I started my server and opened my browser before compilation was finished. After compilation was done, everything started to work perfectly. So it seems that webpack-dev-middleware didn't put serving responses on hold during code compilation, despite the fact my setup was according to the docs.

What helped me was adding serverSideRender: true to webpack-dev-middleware, but it was not mentioned in the docs, that's why I am asking, if anyone experienced similar issue? I yes, I could create a PR to mention this in the docs.

Access to compiler in serverRenderer

Hello,
first of all, thank you for this awesome library, it's saving me.

I would like to inject data into an html file that is generated from a template, and kept in memory, by html-webpack-plugin. Data to inject could be html metas, preloaded state (it's for a react-redux app), etc.

I read that one way to do it is to access the file in memory, which requires access to the compiler:

const filename = path.join(compiler.outputPath, 'index.html')
compiler.outputFileSystem.readFile(filename, (err, result) => {
  // do something
})

Is it possible the pass the compiler to the serverRenderer function ? Or is there a better way to access webpack ouputs ?

Request: Make an example of using vue-router and vue's "createBundleRenderer"

There is an example repository at https://github.com/vuejs/vue-hackernews-2.0 but I find it really hard to understand how webpack-hot-server-middleware would go into that. Probably some code in the hackernews example could be done with this middleware, but I'm not sure.

Also I don't get how to use Vue's JSON output (vue-ssr-client-manifest.json and vue-ssr-server-bundle.json instead of the server bundle JS output) with this middleware.

Could you prepare a minimal example setup on how to use this middleware with Vue.js and vue-router (isomorphic instantiation of a Vue "app", waiting for vue-router async hooks etc.) with express?

Probably it's much to ask and the existing examples are considered being enough for most users, but I have a hard time understanding the different plugins, Vue instantiation, SSR etc. Or is all the code in the hackernews example needed and webpack-hot-server-middleware wouldn't help in any way?

Thanks you - Vue's SSR is driving me a bit insane...

serverRender is not a function

Environment

- node : "v10.9.0"
- webpack: "^4.16.5"
- webpack-hot-server-middleware: "^0.5.0"

My Repository

https://github.com/nemixe/universal-training

The code that i think caused this problem

server/index.js

const webpack = require('webpack')
const express = require('express')
const webpackDevMiddleware = require('webpack-dev-middleware')
const webpackHotMiddleware = require('webpack-hot-middleware')
const webpackHotServerMiddleware = require('webpack-hot-server-middleware')
const clientConfigDev = require('../webpack/client.dev')
const serverConfigDev = require('../webpack/server.dev')
const clientConfigProd = require('../webpack/client.prod')
const serverConfigProd = require('../webpack/server.prod')

const { publicPath } = clientConfigDev.output
const outputPath = clientConfigDev.output.path
const DEV = process.env.NODE_ENV === 'development'
const app = express()

let isBuilt = false

const done = () =>
  !isBuilt &&
  app.listen(3000, () => {
    isBuilt = true
    console.log('Build Complete')
  })

if (DEV) {
  const compiler = webpack([clientConfigDev, serverConfigDev])
  const clientCompiler = compiler.compilers[0]
  const options = { publicPath, stats: { color: true } }
  const devMiddleware = webpackDevMiddleware(compiler, options)

  app.use(devMiddleware)
  app.use(webpackHotMiddleware(clientCompiler))
  app.use(webpackHotServerMiddleware(compiler))

  devMiddleware.waitUntilValid(done)
} else {
  webpack([clientConfigProd, serverConfigProd]).run((err, stats) => {
    const clientStats = stats.toJson().children[0]
    const serverRender = require('../build/server.js').default

    app.use(publicPath, express.static(outputPath))
    app.use(serverRender({ clientStats }))

    done()
  })
}

i have an issue with the development mode when i open my app in browser, it said serverRenderer is not a function, everything is okay with production mode

Can't get the webpack-config to work for this

I cannot get the webpack.config.js folder to allow both entry points for client and server.

I copied the example:

module.exports = [
    {
        name: 'client',
        target: 'web',
        entry: './client.js'
        ...
    }, {
        name: 'server',
        target: 'node',
        entry: './server.js'
        ...
    }
];

Which makes my code look like this:

module.exports = {
    {
       name: 'client',
       target: 'web',
       entry: './src/index.js'
   }, {
       name: 'server',
       target: 'node',
       entry: './tools/server.js'
   },
    output: {
        path: __dirname + '/public',
        publicPath: "/",
        filename: 'bundle.js'
    },
...

But then I get this error:

SyntaxError: /Users/ryan/Desktop/df/coding/rc/webpack.config.js: Unexpected token (33:4)
  31 | 
  32 | module.exports = {
> 33 |     {
     |     ^
  34 |        name: 'client',
  35 |        target: 'web',
  36 |        entry: './src/index.js'

On top of this: I have multiple entry points for the client side for react-hot-loader and webpack-hot-middleware, so my actual code is more like this

entry: {
       client: [
               'webpack-hot-middleware/client?reload=true', //note that it reloads the page if hot module reloading fails.
               'react-hot-loader/patch', // RHL patch
               './src/index.js'
           ],
       server: './tools/server.js'
   },
    output: {
        path: __dirname + '/public',
        publicPath: "/",
        filename: '[name].bundle.js'
    },

And this brings up tons more errors.
Essentially, how do I set up webpack config with the webpack-hot-middleware and react-hot-loader?

TypeError: serverRenderer is not a function

I don't get the error until I try to load the page:

server.jsx:

import React from 'react';
import ReactDOMServer from 'react-dom/server';
import { match } from 'react-router/es6';
import { ServerRoot } from 'Root';
import configureStore from 'store';
import cheerio from 'cheerio';

module.exports = function(indexHTML) {
    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(indexHTML);

                $('#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')
            }
        });
    }
}

app.js:

...
var webpack = require('webpack');
var clientConfig = require(path.join(__dirname, '/config/webpack.config.client.js'));
var serverConfig = require(path.join(__dirname, '/config/webpack.config.server.js'));
var devServerConfig = clientConfig.devServer;

app.use(serverConfig.output.publicPath, express.static(serverConfig.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') {
    var compiler = webpack(clientConfig);

    var serverCompiler = webpack([clientConfig, serverConfig]);

    const webpackDevMiddlewareInstance = require('webpack-dev-middleware')(compiler, devServerConfig);
    const webpackHotServerMiddlewareInstance = require('webpack-hot-server-middleware')(serverCompiler);

    app.use(webpackDevMiddlewareInstance);
    app.use(webpackHotServerMiddlewareInstance);

    if (devServerConfig.hot) {
        app.use(require('webpack-hot-middleware')(compiler, {
            log: console.log,
            path: '/__webpack_hmr',
            heartbeat: 10000
        }));
    }

    webpackDevMiddlewareInstance.waitUntilValid(function () {
        compiler.outputFileSystem.readFile(path.join(compiler.outputPath, 'index.html'), function (err, result) {
            if (err) throw err;

            ready(result);
        });
    });
} else
    ready(fs.readFileSync(path.join(__dirname, 'builds/client/index.html')));

function ready(indexHTML) {
    app.use('*', require('./builds/server/server.js')(indexHTML));
    ...
}

I may be doing something very wrong or incorrectly since I am still relatively new to all of this.

Thanks.

JavaScript heap out of memory, bundles not cleared

We're seeing a lot of out-of-memory errors using this library.

I've looked at #29 and think this is another reason. After doing some heap traces I see that bundles remain in memory after every change. The nodejs module object has a children array, which includes every generated bundle.

This issue has been fixed upstream in require-from-string@2, so a simple dep update should fix the issue here.

Error: listen EADDRINUSE :::3000 occurs

Hi guys!
I added this middleware to my side project. Webpack complies the assets but app crashes with Error: listen EADDRINUSE :::3000. Port is avaible at the moment when app starts, I even changed the port. Without this middleware the app starts with no errors.
Could anyone share some thoughts what could cause the error?

serve plugin generated files

my setup

// ./build/webpack/vendor.js
module.exports = [require("./vendor"), require("./client"), require("./server")];

// hot.js
const app = require("express")();
const vendor = require('webpack')(require('./build/webpack/vendor.js'));
vendor.run(function (err, stats) {
		console.log("DLL READY");
		const compiler = require('webpack')(require('./build/webpack/dev.js'));
		app.use(require('webpack-dev-middleware')(compiler));
		app.use(require('webpack-hot-middleware')(compiler.compilers.find(compiler => compiler.name === 'client')));
		app.use(require('webpack-hot-server-middleware')(compiler, {chunkName: 'server'}));
		app.use(require("morgan")('combined'));
		app.listen(3000, "0.0.0.0");
	}
);

my webpack's client config generates some file like

let client = [
	...server,
	new FaviconsWebpackPlugin({
		logo: './src/icon/icon.png',
		prefix: 'icons/'
	}),
	new SWPrecacheWebpackPlugin(
		{
			cacheId: 'spotify',
			filename: 'sw.js',
			maximumFileSizeToCacheInBytes: 4194304,
			minify: true,
			runtimeCaching: [{
				handler: 'cacheFirst',
				urlPattern: /[.]mp3$/,
			}],
		}
	),
	new StatsWebpackPlugin('stats.json', {
		chunkModules: true,
		exclude: [/node_modules/]
	}),
];

in my development locahost:3000/stats.json return my SPA html page instead of the actual json object. It work fine in production where I am just serving static files, look

Trying out Webpack4 + Babel + dev / hot / hot-server

Hi!

In this repo I am trying to get a simple app working with SSR, HMR and the new Webpack 4 and Babel 7 (and TypeScript with that).

Right now I'm stuck on this error: TypeError: serverRenderer is not a function at node_modules/webpack-hot-server-middleware/src/index.js:13:3.

Somehow my webpack compiler object is not emitting a 'done' event, and the server renderer is never fetched.

To reproduce:

git clone https://github.com/Inuldustrial/universal-demo;
cd universal-demo;
npm i;
npm run start;

You will see the complete webpack config, a successful compile and that error in the browser when you visit the page.

Thanks for your time,

Tom

Only create webpack.config for server, omit client

According to the docs, it looks like I have to pass a webpack.config that consists of both "client" and "server". Is there any way to pass the server config only, and omit the client (client is not needed at this moment)?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.