|
|
'use strict';
const path = require('path'); const { parse } = require('url'); const querystring = require('querystring');
const parseRange = require('range-parser');
const HASH_REGEXP = /[0-9a-f]{10,}/;
// support for multi-compiler configuration
// see: https://github.com/webpack/webpack-dev-server/issues/641
function getPaths(publicPath, compiler, url) { const compilers = compiler && compiler.compilers; if (Array.isArray(compilers)) { let compilerPublicPath;
// the path portion of compilerPublicPath
let compilerPublicPathBase;
for (let i = 0; i < compilers.length; i++) { compilerPublicPath = compilers[i].options && compilers[i].options.output && compilers[i].options.output.publicPath;
if (compilerPublicPath) { compilerPublicPathBase = compilerPublicPath.indexOf('/') === 0 ? compilerPublicPath // eslint-disable-next-line
: // handle the case where compilerPublicPath is a URL with hostname
parse(compilerPublicPath).pathname;
// check the url vs the path part of the compilerPublicPath
if (url.indexOf(compilerPublicPathBase) === 0) { return { publicPath: compilerPublicPath, outputPath: compilers[i].outputPath, }; } } } } return { publicPath, outputPath: compiler.outputPath, }; }
// eslint-disable-next-line consistent-return
function ready(context, fn, req) { if (context.state) { return fn(context.webpackStats); }
context.log.info(`wait until bundle finished: ${req.url || fn.name}`); context.callbacks.push(fn); }
module.exports = { getFilenameFromUrl(pubPath, compiler, url) { const { outputPath, publicPath } = getPaths(pubPath, compiler, url); // localPrefix is the folder our bundle should be in
const localPrefix = parse(publicPath || '/', false, true); const urlObject = parse(url); let filename;
const hostNameIsTheSame = localPrefix.hostname === urlObject.hostname;
// publicPath has the hostname that is not the same as request url's, should fail
if ( localPrefix.hostname !== null && urlObject.hostname !== null && !hostNameIsTheSame ) { return false; }
// publicPath is not in url, so it should fail
if (publicPath && hostNameIsTheSame && url.indexOf(publicPath) !== 0) { return false; }
// strip localPrefix from the start of url
if (urlObject.pathname.indexOf(localPrefix.pathname) === 0) { filename = urlObject.pathname.substr(localPrefix.pathname.length); }
if ( !urlObject.hostname && localPrefix.hostname && url.indexOf(localPrefix.path) !== 0 ) { return false; }
let uri = outputPath;
/* istanbul ignore if */ if (process.platform === 'win32') { // Path Handling for Microsoft Windows
if (filename) { uri = path.posix.join(outputPath || '', querystring.unescape(filename));
if (!path.win32.isAbsolute(uri)) { uri = `/${uri}`; } }
return uri; }
// Path Handling for all other operating systems
if (filename) { uri = path.posix.join(outputPath || '', filename);
if (!path.posix.isAbsolute(uri)) { uri = `/${uri}`; } }
// if no matches, use outputPath as filename
return querystring.unescape(uri); },
handleRangeHeaders(content, req, res) { // assumes express API. For other servers, need to add logic to access
// alternative header APIs
res.setHeader('Accept-Ranges', 'bytes');
if (req.headers.range) { const ranges = parseRange(content.length, req.headers.range);
// unsatisfiable
if (ranges === -1) { res.setHeader('Content-Range', `bytes */${content.length}`); // eslint-disable-next-line no-param-reassign
res.statusCode = 416; }
// valid (syntactically invalid/multiple ranges are treated as a
// regular response)
if (ranges !== -2 && ranges.length === 1) { const { length } = content;
// Content-Range
// eslint-disable-next-line no-param-reassign
res.statusCode = 206; res.setHeader( 'Content-Range', `bytes ${ranges[0].start}-${ranges[0].end}/${length}` );
// eslint-disable-next-line no-param-reassign
content = content.slice(ranges[0].start, ranges[0].end + 1); } }
return content; },
handleRequest(context, filename, processRequest, req) { // in lazy mode, rebuild on bundle request
if ( context.options.lazy && (!context.options.filename || context.options.filename.test(filename)) ) { context.rebuild(); }
if (HASH_REGEXP.test(filename)) { try { if (context.fs.statSync(filename).isFile()) { processRequest(); return; } } catch (e) { // eslint-disable-line
} }
ready(context, processRequest, req); },
noop: () => {},
ready, };
|