middleware.js 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. 'use strict';
  2. const mime = require('mime');
  3. const urlJoin = require('url-join');
  4. const DevMiddlewareError = require('./DevMiddlewareError');
  5. const { getFilenameFromUrl, handleRangeHeaders, handleRequest, ready } = require('./util');
  6. module.exports = function wrapper(context) {
  7. return function middleware(req, res, next) {
  8. // fixes #282. credit @cexoso. in certain edge situations res.locals is
  9. // undefined.
  10. res.locals = res.locals || {};
  11. function goNext() {
  12. if (!context.options.serverSideRender) {
  13. return next();
  14. }
  15. return new Promise(((resolve) => {
  16. ready(context, () => {
  17. res.locals.webpackStats = context.webpackStats;
  18. resolve(next());
  19. }, req);
  20. }));
  21. }
  22. if (req.method !== 'GET') {
  23. return goNext();
  24. }
  25. let filename = getFilenameFromUrl(context.options.publicPath, context.compiler, req.url);
  26. if (filename === false) {
  27. return goNext();
  28. }
  29. return new Promise(((resolve) => {
  30. handleRequest(context, filename, processRequest, req);
  31. function processRequest() {
  32. try {
  33. let stat = context.fs.statSync(filename);
  34. if (!stat.isFile()) {
  35. if (stat.isDirectory()) {
  36. let { index } = context.options;
  37. if (index === undefined || index === true) {
  38. index = 'index.html';
  39. } else if (!index) {
  40. throw new DevMiddlewareError('next');
  41. }
  42. filename = urlJoin(filename, index);
  43. stat = context.fs.statSync(filename);
  44. if (!stat.isFile()) {
  45. throw new DevMiddlewareError('next');
  46. }
  47. } else {
  48. throw new DevMiddlewareError('next');
  49. }
  50. }
  51. } catch (e) {
  52. return resolve(goNext());
  53. }
  54. // server content
  55. let content = context.fs.readFileSync(filename);
  56. content = handleRangeHeaders(content, req, res);
  57. let contentType = mime.getType(filename);
  58. // do not add charset to WebAssembly files, otherwise compileStreaming will fail in the client
  59. if (!/\.wasm$/.test(filename)) {
  60. contentType += '; charset=UTF-8';
  61. }
  62. res.setHeader('Content-Type', contentType);
  63. res.setHeader('Content-Length', content.length);
  64. const { headers } = context.options;
  65. if (headers) {
  66. for (const name in headers) {
  67. if ({}.hasOwnProperty.call(headers, name)) {
  68. res.setHeader(name, context.options.headers[name]);
  69. }
  70. }
  71. }
  72. // Express automatically sets the statusCode to 200, but not all servers do (Koa).
  73. res.statusCode = res.statusCode || 200;
  74. if (res.send) res.send(content);
  75. else res.end(content);
  76. resolve();
  77. }
  78. }));
  79. };
  80. };