Skip to content

Commit 4e149bd

Browse files
committed
Change request handling order, improve dev server error handling
1 parent eb24b8a commit 4e149bd

File tree

3 files changed

+64
-58
lines changed

3 files changed

+64
-58
lines changed

config/webpackDevServer.ssr.config.js

Lines changed: 36 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -19,45 +19,53 @@ module.exports = function(proxy, allowedHost) {
1919
throw new Error("Webpack compiler with name 'ssr' not found.");
2020
}
2121

22-
// stores current request handler, changes after every compilation
23-
let ssrHandler;
22+
// stores current request handler, changes after every compilation, initially handles pending handler change
23+
let ssrHandler = (request, response, next) => {
24+
installHandler = handler => {
25+
installHandler = handler => ssrHandler = handler;
26+
ssrHandler = handler;
27+
ssrHandler(request, response, next);
28+
};
29+
};
30+
let installHandler = handler => ssrHandler = handler;
2431

2532
// fetch ssr handler after every compilation
26-
multiCompiler.hooks.done.tap('webpackDevServer.ssr', () => {
33+
multiCompiler.hooks.done.tap('webpackDevServer.ssr', multiCompilerStats => {
2734
// make errors inside hook visible
2835
try {
29-
// fetch ssr entry point file name
30-
const filename = path.resolve(paths.appBuild, "..", "dist", "ssr.js");
31-
// read code from in memory fs
32-
const code = compiler.outputFileSystem.readFileSync(filename).toString();
33-
// compile code to node module
34-
const exports = requireFromString(code, filename);
35-
36-
if (exports.devServerHandler) {
37-
// install dev server handler
38-
ssrHandler = exports.devServerHandler(compiler);
39-
} else if (exports.default) {
40-
// install production handler
41-
ssrHandler = exports.default;
42-
} else {
43-
// no handler found
44-
throw new Error("SSR entry point does not export a handler.");
36+
const compilerStats = multiCompilerStats.stats.filter(stats => stats.compilation.name === 'ssr')[0];
37+
38+
if (compilerStats.compilation.errors.length === 0) {
39+
// fetch ssr entry point file name
40+
const filename = path.resolve(paths.appBuild, "..", "dist", "ssr.js");
41+
// read code from in memory fs
42+
const code = compiler.outputFileSystem.readFileSync(filename).toString();
43+
// compile code to node module
44+
const exports = requireFromString(code, filename);
45+
46+
if (exports.devServerHandler) {
47+
// install dev server handler
48+
installHandler(exports.devServerHandler(compiler));
49+
} else if (exports.default) {
50+
// install production handler
51+
installHandler(exports.default);
52+
} else {
53+
// no handler found
54+
throw new Error("SSR entry point does not export a handler.");
55+
}
4556
}
4657
} catch (error) {
4758
console.error(error);
59+
// install error handler
60+
installHandler((request, response, next) => {
61+
// response.send("ERROR HANDLER: " + error.toString());
62+
next(error);
63+
});
4864
}
4965
});
5066

5167
// install request handler in webpack dev server
52-
app.use((request, response, next) => {
53-
// forward to handler if it exists
54-
if (ssrHandler) {
55-
ssrHandler(request, response, next);
56-
} else {
57-
// skip to dev middleware
58-
next();
59-
}
60-
});
68+
app.use((request, response, next) => ssrHandler(request, response, next));
6169
}
6270
};
6371
};

template-typescript/src/index.ssr.tsx

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,11 @@ let readFileSync: (filename: string) => Buffer = fs.readFileSync;
2222

2323
const router = express.Router();
2424

25-
// serve static files from build/ dir
26-
router.use(express.static(
27-
'build',
28-
{
29-
// do not send index.html for '/'
30-
index: false
31-
}
32-
));
25+
// define ssr path pattern, exclude file and hmr requests
26+
const ssrRegex = /^\/(?!static|favicon\.ico|.*hot-update\.js).*/;
3327

3428
// do server-side rendering
35-
router.use((request: express.Request, response: express.Response, next: express.NextFunction) => {
29+
router.use(ssrRegex, (request: express.Request, response: express.Response, next: express.NextFunction) => {
3630
const template = readFileSync('build/index.html')
3731
.toString()
3832
.replace(/%PUBLIC_URL%/g, process.env.PUBLIC_URL || '');
@@ -48,6 +42,15 @@ router.use((request: express.Request, response: express.Response, next: express.
4842
});
4943
});
5044

45+
// serve static files from build/ dir
46+
router.use(express.static(
47+
'build',
48+
{
49+
// do not send index.html for '/'
50+
index: false
51+
}
52+
));
53+
5154
/**
5255
* Export a request handler. This can be plugged into an express instance or deployed as a serverless function.
5356
* An express router itself implements the request handler interface (composite design pattern).
@@ -70,12 +73,8 @@ export const devServerHandler = (compiler: any) => {
7073
)
7174
);
7275

73-
// wrap the production router to handle some requests in another way
76+
// ignore in-memory file requests, will be handled by the webpack dev middleware
7477
const devServerRouter = express.Router();
75-
76-
// skip all requests to static files, the webpack dev middleware will handle them
77-
const notAStaticFile = /^\/(?!static|favicon\.ico).*/;
78-
devServerRouter.use(notAStaticFile, router);
79-
78+
devServerRouter.use(ssrRegex, router);
8079
return devServerRouter;
8180
};

template/src/index.ssr.js

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,11 @@ let readFileSync = fs.readFileSync;
2222

2323
const router = express.Router();
2424

25-
// serve static files from build/ dir
26-
router.use(express.static(
27-
'build',
28-
{
29-
// do not send index.html for '/'
30-
index: false
31-
}
32-
));
25+
// define ssr path pattern, exclude file and hmr requests
26+
const ssrRegex = /^\/(?!static|favicon\.ico|.*hot-update\.js).*/;
3327

3428
// do server-side rendering
35-
router.use((request, response, next) => {
29+
router.use(ssrRegex, (request, response, next) => {
3630
const template = readFileSync('build/index.html')
3731
.toString()
3832
.replace(/%PUBLIC_URL%/g, process.env.PUBLIC_URL || '');
@@ -48,6 +42,15 @@ router.use((request, response, next) => {
4842
});
4943
});
5044

45+
// serve static files from build/ dir
46+
router.use(express.static(
47+
'build',
48+
{
49+
// do not send index.html for '/'
50+
index: false
51+
}
52+
));
53+
5154
/**
5255
* Export a request handler. This can be plugged into an express instance or deployed as a serverless function.
5356
* An express router itself implements the request handler interface (composite design pattern).
@@ -70,12 +73,8 @@ export const devServerHandler = compiler => {
7073
)
7174
);
7275

73-
// wrap the production router to handle some requests in another way
76+
// ignore in-memory file requests, will be handled by the webpack dev middleware
7477
const devServerRouter = express.Router();
75-
76-
// skip all requests to static files, the webpack dev middleware will handle them
77-
const notAStaticFile = /^\/(?!static|favicon\.ico).*/;
78-
devServerRouter.use(notAStaticFile, router);
79-
78+
devServerRouter.use(ssrRegex, router);
8079
return devServerRouter;
8180
};

0 commit comments

Comments
 (0)