UNPKG

4.54 kBJavaScriptView Raw
1'use strict';
2
3const { parse } = require('url');
4const querystring = require('querystring');
5const MemoryFileSystem = require('memory-fs');
6const pathabs = require('path-is-absolute');
7const parseRange = require('range-parser');
8const urlJoin = require('url-join');
9
10const HASH_REGEXP = /[0-9a-f]{10,}/;
11
12// support for multi-compiler configuration
13// see: https://github.com/webpack/webpack-dev-server/issues/641
14function getPaths(publicPath, compiler, url) {
15 const compilers = compiler && compiler.compilers;
16 if (Array.isArray(compilers)) {
17 let compilerPublicPath;
18 for (let i = 0; i < compilers.length; i++) {
19 compilerPublicPath = compilers[i].options
20 && compilers[i].options.output
21 && compilers[i].options.output.publicPath;
22 if (url.indexOf(compilerPublicPath) === 0) {
23 return {
24 publicPath: compilerPublicPath,
25 outputPath: compilers[i].outputPath
26 };
27 }
28 }
29 }
30 return {
31 publicPath,
32 outputPath: compiler.outputPath
33 };
34}
35
36function ready(context, fn, req) {
37 if (context.state) {
38 return fn(context.webpackStats);
39 }
40
41 context.log.info(`wait until bundle finished: ${req.url || fn.name}`);
42 context.callbacks.push(fn);
43}
44
45module.exports = {
46 getFilenameFromUrl(pubPath, compiler, url) {
47 const { outputPath, publicPath } = getPaths(pubPath, compiler, url);
48 // localPrefix is the folder our bundle should be in
49 const localPrefix = parse(publicPath || '/', false, true);
50 const urlObject = parse(url);
51 let filename;
52
53 // publicPath has the hostname that is not the same as request url's, should fail
54 if (localPrefix.hostname !== null && urlObject.hostname !== null &&
55 localPrefix.hostname !== urlObject.hostname) {
56 return false;
57 }
58
59 // publicPath is not in url, so it should fail
60 if (publicPath && localPrefix.hostname === urlObject.hostname &&
61 url.indexOf(publicPath) !== 0) {
62 return false;
63 }
64
65 // strip localPrefix from the start of url
66 if (urlObject.pathname.indexOf(localPrefix.pathname) === 0) {
67 filename = urlObject.pathname.substr(localPrefix.pathname.length);
68 }
69
70 if (!urlObject.hostname && localPrefix.hostname &&
71 url.indexOf(localPrefix.path) !== 0) {
72 return false;
73 }
74
75 let uri = outputPath;
76
77 if (filename) {
78 uri = urlJoin((outputPath || '').replace(/\/$/, ''), filename);
79 }
80
81 // if no matches, use outputPath as filename
82 return querystring.unescape(uri);
83 },
84
85 handleRangeHeaders(content, req, res) {
86 // assumes express API. For other servers, need to add logic to access
87 // alternative header APIs
88 res.setHeader('Accept-Ranges', 'bytes');
89
90 if (req.headers.range) {
91 const ranges = parseRange(content.length, req.headers.range);
92
93 // unsatisfiable
94 if (ranges === -1) {
95 res.setHeader('Content-Range', `bytes */${content.length}`);
96 res.statusCode = 416;
97 }
98
99 // valid (syntactically invalid/multiple ranges are treated as a
100 // regular response)
101 if (ranges !== -2 && ranges.length === 1) {
102 const { length } = content;
103
104 // Content-Range
105 res.statusCode = 206;
106 res.setHeader(
107 'Content-Range',
108 `bytes ${ranges[0].start}-${ranges[0].end}/${length}`
109 );
110
111 content = content.slice(ranges[0].start, ranges[0].end + 1);
112 }
113 }
114
115 return content;
116 },
117
118 handleRequest(context, filename, processRequest, req) {
119 // in lazy mode, rebuild on bundle request
120 if (context.options.lazy && (!context.options.filename || context.options.filename.test(filename))) {
121 context.rebuild();
122 }
123
124 if (HASH_REGEXP.test(filename)) {
125 try {
126 if (context.fs.statSync(filename).isFile()) {
127 processRequest();
128 return;
129 }
130 } catch (e) {
131 // eslint-disable-line
132 }
133 }
134
135 ready(context, processRequest, req);
136 },
137
138 noop: () => {},
139
140 ready,
141
142 setFs(context, compiler) {
143 if (typeof compiler.outputPath === 'string' && !pathabs.posix(compiler.outputPath) && !pathabs.win32(compiler.outputPath)) {
144 throw new Error('`output.path` needs to be an absolute path or `/`.');
145 }
146
147 let fs;
148 // store our files in memory
149 const isMemoryFs = !compiler.compilers && compiler.outputFileSystem instanceof MemoryFileSystem;
150
151 if (isMemoryFs) {
152 fs = compiler.outputFileSystem;
153 } else {
154 fs = new MemoryFileSystem();
155 compiler.outputFileSystem = fs;
156 }
157
158 context.fs = fs;
159 }
160};