| 'use strict'; |
| |
| const path = require('path'); |
| |
| const mime = require('mime'); |
| |
| const DevMiddlewareError = require('./DevMiddlewareError'); |
| const { |
| getFilenameFromUrl, |
| handleRangeHeaders, |
| handleRequest, |
| ready, |
| } = require('./util'); |
| |
| // Do not add a charset to the Content-Type header of these file types |
| // otherwise the client will fail to render them correctly. |
| const NonCharsetFileTypes = /\.(wasm|usdz)$/; |
| |
| module.exports = function wrapper(context) { |
| return function middleware(req, res, next) { |
| // fixes #282. credit @cexoso. in certain edge situations res.locals is |
| // undefined. |
| // eslint-disable-next-line no-param-reassign |
| res.locals = res.locals || {}; |
| |
| function goNext() { |
| if (!context.options.serverSideRender) { |
| return next(); |
| } |
| |
| return new Promise((resolve) => { |
| ready( |
| context, |
| () => { |
| // eslint-disable-next-line no-param-reassign |
| res.locals.webpackStats = context.webpackStats; |
| // eslint-disable-next-line no-param-reassign |
| res.locals.fs = context.fs; |
| |
| resolve(next()); |
| }, |
| req |
| ); |
| }); |
| } |
| |
| const acceptedMethods = context.options.methods || ['GET', 'HEAD']; |
| |
| if (acceptedMethods.indexOf(req.method) === -1) { |
| return goNext(); |
| } |
| |
| let filename = getFilenameFromUrl( |
| context.options.publicPath, |
| context.compiler, |
| req.url |
| ); |
| |
| if (filename === false) { |
| return goNext(); |
| } |
| |
| return new Promise((resolve) => { |
| handleRequest(context, filename, processRequest, req); |
| // eslint-disable-next-line consistent-return |
| function processRequest() { |
| try { |
| let stat = context.fs.statSync(filename); |
| |
| if (!stat.isFile()) { |
| if (stat.isDirectory()) { |
| let { index } = context.options; |
| |
| // eslint-disable-next-line no-undefined |
| if (index === undefined || index === true) { |
| index = 'index.html'; |
| } else if (!index) { |
| throw new DevMiddlewareError('next'); |
| } |
| |
| filename = path.posix.join(filename, index); |
| stat = context.fs.statSync(filename); |
| |
| if (!stat.isFile()) { |
| throw new DevMiddlewareError('next'); |
| } |
| } else { |
| throw new DevMiddlewareError('next'); |
| } |
| } |
| } catch (e) { |
| return resolve(goNext()); |
| } |
| |
| // server content |
| let content = context.fs.readFileSync(filename); |
| |
| content = handleRangeHeaders(content, req, res); |
| |
| let contentType = mime.getType(filename) || ''; |
| |
| if (!NonCharsetFileTypes.test(filename)) { |
| contentType += '; charset=UTF-8'; |
| } |
| |
| if (!res.getHeader || !res.getHeader('Content-Type')) { |
| res.setHeader('Content-Type', contentType); |
| } |
| |
| res.setHeader('Content-Length', content.length); |
| |
| const { headers } = context.options; |
| |
| if (headers) { |
| for (const name in headers) { |
| if ({}.hasOwnProperty.call(headers, name)) { |
| res.setHeader(name, context.options.headers[name]); |
| } |
| } |
| } |
| |
| // Express automatically sets the statusCode to 200, but not all servers do (Koa). |
| // eslint-disable-next-line no-param-reassign |
| res.statusCode = res.statusCode || 200; |
| |
| if (res.send) { |
| res.send(content); |
| } else { |
| res.end(content); |
| } |
| |
| resolve(); |
| } |
| }); |
| }; |
| }; |