middleware.js 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. /*
  2. MIT License http://www.opensource.org/licenses/mit-license.php
  3. Author Tobias Koppers @sokra
  4. */
  5. var mime = require("mime");
  6. var getFilenameFromUrl = require("./lib/GetFilenameFromUrl");
  7. var Shared = require("./lib/Shared");
  8. var pathJoin = require("./lib/PathJoin");
  9. // constructor for the middleware
  10. module.exports = function(compiler, options) {
  11. var context = {
  12. state: false,
  13. webpackStats: undefined,
  14. callbacks: [],
  15. options: options,
  16. compiler: compiler,
  17. watching: undefined,
  18. forceRebuild: false
  19. };
  20. var shared = Shared(context);
  21. // The middleware function
  22. function webpackDevMiddleware(req, res, next) {
  23. function goNext() {
  24. if(!context.options.serverSideRender) return next();
  25. return new Promise(function(resolve) {
  26. shared.ready(function() {
  27. res.locals.webpackStats = context.webpackStats;
  28. resolve(next());
  29. }, req);
  30. });
  31. }
  32. if(req.method !== "GET") {
  33. return goNext();
  34. }
  35. var filename = getFilenameFromUrl(context.options.publicPath, context.compiler, req.url);
  36. if(filename === false) return goNext();
  37. return new Promise(function(resolve) {
  38. shared.handleRequest(filename, processRequest, req);
  39. function processRequest() {
  40. try {
  41. var stat = context.fs.statSync(filename);
  42. if(!stat.isFile()) {
  43. if(stat.isDirectory()) {
  44. var index = context.options.index;
  45. if(index === undefined || index === true) {
  46. index = "index.html";
  47. } else if(!index) {
  48. throw "next";
  49. }
  50. filename = pathJoin(filename, index);
  51. stat = context.fs.statSync(filename);
  52. if(!stat.isFile()) throw "next";
  53. } else {
  54. throw "next";
  55. }
  56. }
  57. } catch(e) {
  58. return resolve(goNext());
  59. }
  60. // server content
  61. var content = context.fs.readFileSync(filename);
  62. content = shared.handleRangeHeaders(content, req, res);
  63. var contentType = mime.lookup(filename);
  64. // do not add charset to WebAssembly files, otherwise compileStreaming will fail in the client
  65. if(!/\.wasm$/.test(filename)) {
  66. contentType += "; charset=UTF-8";
  67. }
  68. res.setHeader("Content-Type", contentType);
  69. res.setHeader("Content-Length", content.length);
  70. if(context.options.headers) {
  71. for(var name in context.options.headers) {
  72. res.setHeader(name, context.options.headers[name]);
  73. }
  74. }
  75. // Express automatically sets the statusCode to 200, but not all servers do (Koa).
  76. res.statusCode = res.statusCode || 200;
  77. if(res.send) res.send(content);
  78. else res.end(content);
  79. resolve();
  80. }
  81. });
  82. }
  83. webpackDevMiddleware.getFilenameFromUrl = getFilenameFromUrl.bind(this, context.options.publicPath, context.compiler);
  84. webpackDevMiddleware.waitUntilValid = shared.waitUntilValid;
  85. webpackDevMiddleware.invalidate = shared.invalidate;
  86. webpackDevMiddleware.close = shared.close;
  87. webpackDevMiddleware.fileSystem = context.fs;
  88. return webpackDevMiddleware;
  89. };