-
-
Notifications
You must be signed in to change notification settings - Fork 376
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support for server-side rendering #118
Conversation
If `options.serverSideRender` is true, the middleware will set the `stat` object, which is generated by webpack, to `res`, and all requests will wait for building.
Support for options.serverSideRender
I think the feature/idea is sound (I also do SSR), but wanted to ask a couple questions:
Again, I think exposing
|
@ericclemmons I agree with setting the property on AFIK inspecting EDITED: use |
@@ -194,8 +197,16 @@ module.exports = function(compiler, options) { | |||
|
|||
// The middleware function | |||
function webpackDevMiddleware(req, res, next) { | |||
var goNext = function() { | |||
if (!options.serverSideRender) return next() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Build fails because of this; it should be if(
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
Thanks, looks good now. @ericclemmons, you also agree? EDIT: one more thing, could you document it in the README? |
@SpaceK33z Sure, if this feature is good to be merged :) |
Looks good to me as well (with README update)! |
Updated README |
Very nice work @wuct. Thank you. |
@SpaceK33z You are welcome! Thanks for merging :) |
Released in |
…eware * 'master' of https://github.com/webpack/webpack-dev-middleware: committed too quickly... Add not-functional test for server side render More tests fix typos Start with some tests! Fix inconsistencies with semi colons Use valid license for npm Document `reporter` option Add changelog for 1.7.0 1.7.0 Removing watching/watching.running check (webpack#100) Improve eslint linting and remove js-beautify Support for server-side rendering (webpack#118)
Hi @wuct, I wondered how are you setting Also, when you say 'server-side rendering' do you mean rendering the app universally / isomorphically or just rendering an empty html page? |
@richardscarrott Sorry for late replying. In production, we use a pre-built stat file which is generated by webpack-stats-plugin. Here is some simplified version of our code: if (process.env.NODE_ENV !== 'production') {
app.use(webpackMiddleware(compiler, { serverSideRender: true })
}
app.use((req, res) => {
const { assetsByChunkName } = process.env.NODE_ENV !== 'production'
? res.locals.webpackStats.toJson()
: require('./path/to/stat.json')
// then use assetsByChunkName to render index.html
}) And yes, actually we are using React to rendering our app universally. To do this, we use webpack to create two bundles by providing two different webpack config files. One bundle is for client-side rendering, the other is for server-side rendering. In the development mode, we not only use The entire version of all server logic is: if (process.env.NODE_ENV !== 'production') {
app.use(webpackMiddleware(compiler, { serverSideRender: true })
app.use(webpackSeverRenderMiddleware(serverCompiler))
}
app.use((req, res) => {
const { assetsByChunkName } = process.env.NODE_ENV !== 'production'
? res.locals.webpackStats.toJson()
: require('./path/to/stat.json')
const renderer = process.env.NODE_ENV !== 'production'
? res.serverBundle
: require('./path/to/prebuilt/serverBundle')
// render all the stuff then response to client
render(assetsByChunkName, req, res)
}) Hope this answer is helpful :) |
@wuct Thanks for the reply! Funnily enough I just put out something super similar to your Really though, it's not this change in The main reason I raise this is I think the documentation added with this PR is a little misleading as it says 'Server-Side Rendering', as does the option name. I wonder if it's worth updating the docs or even just delegate this functionality to another middleware, I think it could be done quite easily, something like this? function webpackStatsMiddleware(compiler) {
let latestStats;
compiler.plugin('done', stats => latestStats = stats);
return (req, res, next) => {
req.locals.webpackStats = latestStats;
next();
}
}
app.use(webpackDevMiddleware(compiler));
app.use(webpackStatsMiddleware(compiler)); |
@richardscarrott I really like your approach that separates different functionality into different middleware. It is much simpler then mine. I agree with you current doc is confusing. I would like to revert this PR and maybe add links to @SpaceK33z how do you think? |
@richardscarrott, your example would not work completely. If the compiler is still compiling, and you refresh the page, this would mean you still get the old version. This can be very confusing. This is exactly what webpack-dev-middleware fixes. When making a request with the compiler still busy, it will delay the request till the compiler is done. @wuct, we could remove it for the next major version, and maybe add a link to your package instead. However, I would like to have a clear upgrade path for people who might be using this PR. |
@SpaceK33z I'm not sure that's true by the virtue of the middleware stack as I did notice that If that became a problem I think this would work: function webpackStatsMiddleware(compiler, options = {}) {
let latestStats;
compiler.plugin('done', stats => latestStats = stats);
return (req, res, next) => {
options.waitUntilValid(() => {
req.locals.webpackStats = latestStats;
next();
});
}
}
const webpackDev = webpackDevMiddleware(compiler);
app.use(webpackDev);
app.use(webpackStatsMiddleware(compiler, {
waitUntilValid: webpackDev.waitUntilValid
})); Which would then allow you to mount it before |
@richardscarrott, ahhh you're right, I didn't realise you could use that trick. Ignore my previous comment ;). |
Hmmm, I forgot that without |
Yeah it would be great if the name is a bit more generic. I'd accept a PR that changes the name to something sane (don't know a good one myself atm). Maybe also an idea to add a reference to @wuct's |
@wuct / @SpaceK33z my personal opinion is that If the feature is going to stay then perhaps something along the lines of Or, I wonder if the functionality could be made more generic by perhaps providing an |
Hi all, |
@jhk2020 AFAIK, the only reason for the |
@wuct if your code is splitted because of how it is written for the client side. How the requirement of the other chunk works as it is in-memory ? I would get module not found right. |
@jhk2020 @coreyleelarson In addition to getting the |
@clempat do you mind to share the relevant part of your webpack config? |
@wuct I will try to be the most specific possible. I use webpack 2. I have two Webpack configuration, one for client and one for server. Each has a different entry point but share the same code. I use react and react-router. In react-router I use System.import for code spliting. Which would be interesting mostly for client. But this is part of the shared code. Fyi I use commonjs2 as libraryTarget for server. If I build and run the build all works fine on both side. ProblemThe problem come on dev server so with in-memory files. I use a similar configuration to yours presented there. If I was not spliting the code all would be fine. But as it is splitted. I get an error like Possible solutionsI was thinking about few possibility.
I hope I gave enough information to understand the problem I face. And I am thankful to you for any input you could bring... |
@clempat As you have discovered when
Having done this you still need to access the server entry which can only be done by reading it in from the memory fs and loading the module from buffer or string, which is how |
@richardscarrott Thanks a lot. It works perfectly !!! Perfect !! I will just need to check why i have |
Found it easily. https://github.com/ReactTraining/react-router/blob/master/docs/guides/ServerRendering.md#async-routes thanks for all |
Although it should be setted mode option to development when using webpack-dev-middleware, but I found that even it was not setted correctly, webpack-dev-middleware can still work well except writing files to outputFileSystem. In my case, I create a server via koa, and use 2 middleware(webpackDevMiddleware&serverSideRenderMiddleware). In webpackDevMiddleware, I provide serverSideRender option(with true value), and in serverSideRenderMiddleware I try to read emitted files by webpack via res.locals.webpack.outputFileSystem, but failed. I debugged with toTreeSync function which is provided by memfs to check outputFileSsytem‘s directory structure, and I got '/', which means the directory is empty: ` app.use( app.use(async (ctx: Koa.Context, next) => { Finally, I found I forgot to set the mode option. So, I want to add a note here. Make sure the mode option be correct. |
In order to use this middleware to develop a server-side rendering application, we need access to the
stats
. This PR is aimed to give the access to consumers.How it works
If
options.serverSideRender
is true, the webpack-dev-middleware will set thestat
object, which is generated by the latest build, tores.locals
, then callnext()
to trigger the next middleware.During the webpack building process, all requests, inclusive of non-files request, will be pending until the build is finished.