@atlaspack/reporter-dev-server 2.14.5-canary.49 → 2.14.5-canary.490
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +496 -0
- package/dist/HMRServer.js +220 -0
- package/dist/Server.js +408 -0
- package/dist/ServerDataProvider.js +2 -0
- package/dist/ServerReporter.js +135 -0
- package/dist/StaticServerDataProvider.js +51 -0
- package/dist/serverErrors.js +16 -0
- package/dist/types.js +2 -0
- package/lib/HMRServer.js +270 -0
- package/lib/Server.js +466 -0
- package/lib/ServerDataProvider.js +1 -0
- package/lib/ServerReporter.js +137 -17455
- package/lib/StaticServerDataProvider.js +58 -0
- package/lib/launch-editor.d.js +1 -0
- package/lib/serverErrors.js +20 -0
- package/lib/types/HMRServer.d.ts +54 -0
- package/lib/types/Server.d.ts +45 -0
- package/lib/types/ServerDataProvider.d.ts +33 -0
- package/lib/types/ServerReporter.d.ts +3 -0
- package/lib/types/StaticServerDataProvider.d.ts +23 -0
- package/lib/types/serverErrors.d.ts +4 -0
- package/lib/types/types.d.ts +34 -0
- package/lib/types.js +1 -0
- package/package.json +19 -11
- package/src/{HMRServer.js → HMRServer.ts} +61 -35
- package/src/{Server.js → Server.ts} +52 -38
- package/src/ServerDataProvider.ts +34 -0
- package/src/{ServerReporter.js → ServerReporter.ts} +3 -5
- package/src/StaticServerDataProvider.ts +72 -0
- package/src/launch-editor.d.ts +4 -0
- package/src/{serverErrors.js → serverErrors.ts} +6 -5
- package/src/types.ts +46 -0
- package/{src/templates → templates}/404.html +1 -1
- package/{src/templates → templates}/500.html +1 -1
- package/test/StaticServerDataProvider.test.ts +131 -0
- package/tsconfig.json +18 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/lib/ServerReporter.js.map +0 -1
- package/src/types.js.flow +0 -56
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
// @
|
|
2
|
-
|
|
1
|
+
// @ts-expect-error TS2307
|
|
3
2
|
import type {DevServerOptions, Request, Response} from './types.js.flow';
|
|
4
3
|
import type {
|
|
5
4
|
BuildSuccessEvent,
|
|
@@ -51,15 +50,19 @@ const SLASH_REGEX = /\//g;
|
|
|
51
50
|
export const SOURCES_ENDPOINT = '/__parcel_source_root';
|
|
52
51
|
const EDITOR_ENDPOINT = '/__parcel_launch_editor';
|
|
53
52
|
const TEMPLATE_404 = fs.readFileSync(
|
|
54
|
-
path.join(__dirname, 'templates/404.html'),
|
|
53
|
+
path.join(__dirname, '..', 'templates/404.html'),
|
|
55
54
|
'utf8',
|
|
56
55
|
);
|
|
57
56
|
|
|
58
57
|
const TEMPLATE_500 = fs.readFileSync(
|
|
59
|
-
path.join(__dirname, 'templates/500.html'),
|
|
58
|
+
path.join(__dirname, '..', 'templates/500.html'),
|
|
60
59
|
'utf8',
|
|
61
60
|
);
|
|
62
|
-
type NextFunction = (
|
|
61
|
+
type NextFunction = (
|
|
62
|
+
req: Request,
|
|
63
|
+
res: Response,
|
|
64
|
+
next?: (arg1?: any) => any,
|
|
65
|
+
) => any;
|
|
63
66
|
|
|
64
67
|
export default class Server {
|
|
65
68
|
pending: boolean;
|
|
@@ -68,21 +71,24 @@ export default class Server {
|
|
|
68
71
|
options: DevServerOptions;
|
|
69
72
|
rootPath: string;
|
|
70
73
|
bundleGraph: BundleGraph<PackagedBundle> | null;
|
|
71
|
-
requestBundle:
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
74
|
+
requestBundle:
|
|
75
|
+
| ((bundle: PackagedBundle) => Promise<BuildSuccessEvent>)
|
|
76
|
+
| null
|
|
77
|
+
| undefined;
|
|
78
|
+
errors: Array<{
|
|
79
|
+
message: string;
|
|
80
|
+
stack: string | null | undefined;
|
|
81
|
+
frames: Array<FormattedCodeFrame>;
|
|
82
|
+
hints: Array<string>;
|
|
83
|
+
documentation: string;
|
|
84
|
+
}> | null;
|
|
85
|
+
stopServer: (() => Promise<void>) | null | undefined;
|
|
80
86
|
|
|
81
87
|
constructor(options: DevServerOptions) {
|
|
82
88
|
this.options = options;
|
|
83
89
|
try {
|
|
84
90
|
this.rootPath = new URL(options.publicUrl).pathname;
|
|
85
|
-
} catch (e) {
|
|
91
|
+
} catch (e: any) {
|
|
86
92
|
this.rootPath = options.publicUrl;
|
|
87
93
|
}
|
|
88
94
|
this.pending = true;
|
|
@@ -135,7 +141,7 @@ export default class Server {
|
|
|
135
141
|
);
|
|
136
142
|
}
|
|
137
143
|
|
|
138
|
-
respond(req: Request, res: Response):
|
|
144
|
+
respond(req: Request, res: Response): unknown {
|
|
139
145
|
if (this.middleware.some((handler) => handler(req, res))) return;
|
|
140
146
|
let {pathname, search} = url.parse(req.originalUrl || req.url);
|
|
141
147
|
if (pathname == null) {
|
|
@@ -281,7 +287,7 @@ export default class Server {
|
|
|
281
287
|
invariant(this.requestBundle != null);
|
|
282
288
|
try {
|
|
283
289
|
await this.requestBundle(bundle);
|
|
284
|
-
} catch (err) {
|
|
290
|
+
} catch (err: any) {
|
|
285
291
|
this.send500(req, res);
|
|
286
292
|
return;
|
|
287
293
|
}
|
|
@@ -296,7 +302,7 @@ export default class Server {
|
|
|
296
302
|
req: Request,
|
|
297
303
|
res: Response,
|
|
298
304
|
next: NextFunction,
|
|
299
|
-
): Promise<
|
|
305
|
+
): Promise<undefined> | Promise<unknown> {
|
|
300
306
|
return this.serve(
|
|
301
307
|
this.options.outputFS,
|
|
302
308
|
this.options.distDir,
|
|
@@ -312,7 +318,7 @@ export default class Server {
|
|
|
312
318
|
req: Request,
|
|
313
319
|
res: Response,
|
|
314
320
|
next: NextFunction,
|
|
315
|
-
): Promise<
|
|
321
|
+
): Promise<unknown> {
|
|
316
322
|
if (req.method !== 'GET' && req.method !== 'HEAD') {
|
|
317
323
|
// method not allowed
|
|
318
324
|
res.statusCode = 405;
|
|
@@ -325,7 +331,7 @@ export default class Server {
|
|
|
325
331
|
try {
|
|
326
332
|
var filePath = url.parse(req.url).pathname || '';
|
|
327
333
|
filePath = decodeURIComponent(filePath);
|
|
328
|
-
} catch (err) {
|
|
334
|
+
} catch (err: any) {
|
|
329
335
|
return this.sendError(res, 400);
|
|
330
336
|
}
|
|
331
337
|
|
|
@@ -343,7 +349,7 @@ export default class Server {
|
|
|
343
349
|
|
|
344
350
|
try {
|
|
345
351
|
var stat = await fs.stat(filePath);
|
|
346
|
-
} catch (err) {
|
|
352
|
+
} catch (err: any) {
|
|
347
353
|
if (err.code === 'ENOENT') {
|
|
348
354
|
return next(req, res);
|
|
349
355
|
}
|
|
@@ -370,9 +376,13 @@ export default class Server {
|
|
|
370
376
|
cleanUrls: false,
|
|
371
377
|
},
|
|
372
378
|
{
|
|
379
|
+
// @ts-expect-error TS7006
|
|
373
380
|
lstat: (path) => fs.stat(path),
|
|
381
|
+
// @ts-expect-error TS7006
|
|
374
382
|
realpath: (path) => fs.realpath(path),
|
|
383
|
+
// @ts-expect-error TS7006
|
|
375
384
|
createReadStream: (path, options) => fs.createReadStream(path, options),
|
|
385
|
+
// @ts-expect-error TS7006
|
|
376
386
|
readdir: (path) => fs.readdir(path),
|
|
377
387
|
},
|
|
378
388
|
);
|
|
@@ -388,7 +398,7 @@ export default class Server {
|
|
|
388
398
|
res.end(TEMPLATE_404);
|
|
389
399
|
}
|
|
390
400
|
|
|
391
|
-
send500(req: Request, res: Response):
|
|
401
|
+
send500(req: Request, res: Response): undefined | Response {
|
|
392
402
|
res.setHeader('Content-Type', 'text/html; charset=utf-8');
|
|
393
403
|
res.writeHead(500);
|
|
394
404
|
|
|
@@ -452,6 +462,7 @@ export default class Server {
|
|
|
452
462
|
}
|
|
453
463
|
for (const [context, options] of Object.entries(cfg)) {
|
|
454
464
|
// each key is interpreted as context, and value as middleware options
|
|
465
|
+
// @ts-expect-error TS2345
|
|
455
466
|
app.use(createProxyMiddleware(context, options));
|
|
456
467
|
}
|
|
457
468
|
} else {
|
|
@@ -459,10 +470,7 @@ export default class Server {
|
|
|
459
470
|
configFilePath,
|
|
460
471
|
fileInRoot,
|
|
461
472
|
);
|
|
462
|
-
if (
|
|
463
|
-
// $FlowFixMe
|
|
464
|
-
Object.prototype.toString.call(cfg) === '[object Module]'
|
|
465
|
-
) {
|
|
473
|
+
if (Object.prototype.toString.call(cfg) === '[object Module]') {
|
|
466
474
|
cfg = cfg.default;
|
|
467
475
|
}
|
|
468
476
|
|
|
@@ -520,20 +528,26 @@ export default class Server {
|
|
|
520
528
|
this.stopServer = stop;
|
|
521
529
|
|
|
522
530
|
server.listen(this.options.port, this.options.host);
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
531
|
+
// @ts-expect-error TS2322
|
|
532
|
+
return new Promise(
|
|
533
|
+
(
|
|
534
|
+
resolve: (result: Promise<Server> | Server) => void,
|
|
535
|
+
reject: (error?: any) => void,
|
|
536
|
+
) => {
|
|
537
|
+
server.once('error', (err) => {
|
|
538
|
+
this.options.logger.error({
|
|
539
|
+
// @ts-expect-error TS2345
|
|
527
540
|
message: serverErrors(err, this.options.port),
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
});
|
|
541
|
+
} as Diagnostic);
|
|
542
|
+
reject(err);
|
|
543
|
+
});
|
|
532
544
|
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
545
|
+
server.once('listening', () => {
|
|
546
|
+
// @ts-expect-error TS2345
|
|
547
|
+
resolve(server);
|
|
548
|
+
});
|
|
549
|
+
},
|
|
550
|
+
);
|
|
537
551
|
}
|
|
538
552
|
|
|
539
553
|
async stop(): Promise<void> {
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API the dev-server requires from the main application.
|
|
3
|
+
*
|
|
4
|
+
* This interface is used to provide data to the dev-server from the main application.
|
|
5
|
+
* It is used to get the list of HTML bundles and to request a bundle to be rebuilt.
|
|
6
|
+
*/
|
|
7
|
+
export interface ServerDataProvider {
|
|
8
|
+
/**
|
|
9
|
+
* Return relative file paths for every HTML bundle in the current build output.
|
|
10
|
+
*
|
|
11
|
+
* The returned paths are relative to the distribution directory on disk and
|
|
12
|
+
* can therefore be used as HTTP request targets by the dev-server.
|
|
13
|
+
*
|
|
14
|
+
* @returns List of `.html` bundle paths. If no bundle graph is available yet,
|
|
15
|
+
* an empty array should be returned.
|
|
16
|
+
*/
|
|
17
|
+
getHTMLBundleFilePaths(): string[];
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Attempt to (re)build the bundle that corresponds to the given request path.
|
|
21
|
+
*
|
|
22
|
+
* If a bundle matching `requestedPath` exists and a request handler has been
|
|
23
|
+
* provided, the implementation should trigger a rebuild and resolve the
|
|
24
|
+
* promise with "requested". Otherwise the promise must resolve with
|
|
25
|
+
* "not-found".
|
|
26
|
+
*
|
|
27
|
+
* @param requestedPath Path (relative to the distribution directory) that
|
|
28
|
+
* identifies the bundle file requested by the browser.
|
|
29
|
+
* @returns A promise that resolves to:
|
|
30
|
+
* - "requested" when the build has been successfully triggered, or
|
|
31
|
+
* - "not-found" when the bundle cannot be handled by the provider.
|
|
32
|
+
*/
|
|
33
|
+
requestBundle(requestedPath: string): Promise<'requested' | 'not-found'>;
|
|
34
|
+
}
|
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
// @flow
|
|
2
|
-
|
|
3
1
|
import {Reporter} from '@atlaspack/plugin';
|
|
4
2
|
import HMRServer from './HMRServer';
|
|
5
3
|
import Server from './Server';
|
|
6
4
|
|
|
7
5
|
let servers: Map<number, Server> = new Map();
|
|
8
6
|
let hmrServers: Map<number, HMRServer> = new Map();
|
|
9
|
-
export default
|
|
7
|
+
export default new Reporter({
|
|
10
8
|
async report({event, options, logger}) {
|
|
11
9
|
let {serveOptions, hmrOptions} = options;
|
|
12
10
|
let server = serveOptions ? servers.get(serveOptions.port) : undefined;
|
|
@@ -47,6 +45,7 @@ export default (new Reporter({
|
|
|
47
45
|
port: serveOptions.port,
|
|
48
46
|
host: hmrOptions.host,
|
|
49
47
|
devServer,
|
|
48
|
+
// @ts-expect-error TS7006
|
|
50
49
|
addMiddleware: (handler) => {
|
|
51
50
|
server?.middleware.push(handler);
|
|
52
51
|
},
|
|
@@ -93,7 +92,6 @@ export default (new Reporter({
|
|
|
93
92
|
}
|
|
94
93
|
if (hmrOptions && hmrServer) {
|
|
95
94
|
await hmrServer.stop();
|
|
96
|
-
// $FlowFixMe[prop-missing]
|
|
97
95
|
hmrServers.delete(hmrServer.wss.options.port);
|
|
98
96
|
}
|
|
99
97
|
break;
|
|
@@ -140,4 +138,4 @@ export default (new Reporter({
|
|
|
140
138
|
break;
|
|
141
139
|
}
|
|
142
140
|
},
|
|
143
|
-
})
|
|
141
|
+
}) as Reporter;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
BundleGraph,
|
|
3
|
+
PackagedBundle,
|
|
4
|
+
BuildSuccessEvent,
|
|
5
|
+
} from '@atlaspack/types';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
|
|
8
|
+
import {ServerDataProvider} from './ServerDataProvider';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* An implementation of ServerDataProvider provides data from a direct `bundleGraph`
|
|
12
|
+
* and `requestBundle` function.
|
|
13
|
+
*/
|
|
14
|
+
export class StaticServerDataProvider implements ServerDataProvider {
|
|
15
|
+
private distDir: string;
|
|
16
|
+
|
|
17
|
+
private bundleGraph: BundleGraph<PackagedBundle> | null = null;
|
|
18
|
+
|
|
19
|
+
private requestBundleFn:
|
|
20
|
+
| ((bundle: PackagedBundle) => Promise<BuildSuccessEvent>)
|
|
21
|
+
| null = null;
|
|
22
|
+
|
|
23
|
+
constructor(distDir: string) {
|
|
24
|
+
this.distDir = distDir;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
getHTMLBundleFilePaths(): string[] {
|
|
28
|
+
return (
|
|
29
|
+
this.bundleGraph
|
|
30
|
+
?.getBundles()
|
|
31
|
+
.filter((b) => path.posix.extname(b.name) === '.html')
|
|
32
|
+
.map((b) => path.relative(this.distDir, b.filePath)) ?? []
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async requestBundle(
|
|
37
|
+
requestedPath: string,
|
|
38
|
+
): Promise<'requested' | 'not-found'> {
|
|
39
|
+
const bundle = this.bundleGraph?.getBundles().find((b) => {
|
|
40
|
+
const relativePath = path.relative(this.distDir, b.filePath);
|
|
41
|
+
return relativePath === requestedPath;
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
if (!bundle) {
|
|
45
|
+
return 'not-found';
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (!this.requestBundleFn) {
|
|
49
|
+
return 'not-found';
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
await this.requestBundleFn(bundle);
|
|
53
|
+
|
|
54
|
+
return 'requested';
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Update the provider with the latest bundle graph and request function.
|
|
59
|
+
*
|
|
60
|
+
* This should be called after every successful build so that subsequent requests operate on fresh data.
|
|
61
|
+
*
|
|
62
|
+
* @param bundleGraph The most recent bundle graph representing the output of a build.
|
|
63
|
+
* @param requestBundleFn Function that will be called to (re)build a specific bundle on demand.
|
|
64
|
+
*/
|
|
65
|
+
update(
|
|
66
|
+
bundleGraph: BundleGraph<PackagedBundle>,
|
|
67
|
+
requestBundleFn: (bundle: PackagedBundle) => Promise<BuildSuccessEvent>,
|
|
68
|
+
) {
|
|
69
|
+
this.bundleGraph = bundleGraph;
|
|
70
|
+
this.requestBundleFn = requestBundleFn;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -1,19 +1,20 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|};
|
|
1
|
+
export type ServerError = Error & {
|
|
2
|
+
code: string;
|
|
3
|
+
};
|
|
5
4
|
|
|
6
5
|
const serverErrorList = {
|
|
7
6
|
EACCES: "You don't have access to bind the server to port {port}.",
|
|
8
7
|
EADDRINUSE: 'There is already a process listening on port {port}.',
|
|
9
|
-
};
|
|
8
|
+
} as const;
|
|
10
9
|
|
|
11
10
|
export default function serverErrors(err: ServerError, port: number): string {
|
|
12
11
|
let desc = `Error: ${
|
|
13
12
|
err.code
|
|
14
13
|
} occurred while setting up server on port ${port.toString()}.`;
|
|
15
14
|
|
|
15
|
+
// @ts-expect-error TS7053
|
|
16
16
|
if (serverErrorList[err.code]) {
|
|
17
|
+
// @ts-expect-error TS7053
|
|
17
18
|
desc = serverErrorList[err.code].replace(/{port}/g, port);
|
|
18
19
|
}
|
|
19
20
|
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ServerOptions,
|
|
3
|
+
PluginLogger,
|
|
4
|
+
HMROptions,
|
|
5
|
+
HTTPSOptions,
|
|
6
|
+
FilePath,
|
|
7
|
+
PackageManager,
|
|
8
|
+
} from '@atlaspack/types';
|
|
9
|
+
import type {FileSystem} from '@atlaspack/fs';
|
|
10
|
+
import type {HTTPServer} from '@atlaspack/utils';
|
|
11
|
+
import {IncomingMessage, ServerResponse} from 'http';
|
|
12
|
+
|
|
13
|
+
interface HTTPRequest extends IncomingMessage {
|
|
14
|
+
originalUrl?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export type Request = HTTPRequest;
|
|
18
|
+
export type Response = ServerResponse;
|
|
19
|
+
|
|
20
|
+
export type DevServerOptions = ServerOptions & {
|
|
21
|
+
projectRoot: string;
|
|
22
|
+
publicUrl: string;
|
|
23
|
+
cacheDir: string;
|
|
24
|
+
inputFS: FileSystem;
|
|
25
|
+
outputFS: FileSystem;
|
|
26
|
+
logger: PluginLogger;
|
|
27
|
+
hmrOptions?: HMROptions | null | undefined;
|
|
28
|
+
packageManager: PackageManager;
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// TODO: Figure out if there is a node.js type that could be imported with a complete ServerError
|
|
32
|
+
export type ServerError = Error & {
|
|
33
|
+
code: string;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export type HMRServerOptions = {
|
|
37
|
+
devServer?: HTTPServer;
|
|
38
|
+
addMiddleware?: (handler: (req: Request, res: Response) => boolean) => void;
|
|
39
|
+
port: number;
|
|
40
|
+
host?: string | null | undefined;
|
|
41
|
+
logger: PluginLogger;
|
|
42
|
+
https?: HTTPSOptions | boolean;
|
|
43
|
+
cacheDir: FilePath;
|
|
44
|
+
inputFS: FileSystem;
|
|
45
|
+
outputFS: FileSystem;
|
|
46
|
+
};
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import assert from 'assert';
|
|
2
|
+
import sinon from 'sinon';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
|
|
5
|
+
import {StaticServerDataProvider} from '../src/StaticServerDataProvider';
|
|
6
|
+
|
|
7
|
+
type MockBundle = {
|
|
8
|
+
name: string;
|
|
9
|
+
filePath: string;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
describe('StaticServerDataProvider', () => {
|
|
13
|
+
describe('getHTMLBundleFilePaths', () => {
|
|
14
|
+
it('returns an empty array when no bundleGraph is set', () => {
|
|
15
|
+
const provider = new StaticServerDataProvider('/dist');
|
|
16
|
+
assert.deepStrictEqual(provider.getHTMLBundleFilePaths(), []);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('filters only .html bundles and returns relative paths', () => {
|
|
20
|
+
const distDir = path.resolve('/project/dist');
|
|
21
|
+
const provider = new StaticServerDataProvider(distDir);
|
|
22
|
+
|
|
23
|
+
const bundles: MockBundle[] = [
|
|
24
|
+
{
|
|
25
|
+
name: 'index.html',
|
|
26
|
+
filePath: path.join(distDir, 'index.html'),
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
name: 'app.js',
|
|
30
|
+
filePath: path.join(distDir, 'app.js'),
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
name: 'about/index.html',
|
|
34
|
+
filePath: path.join(distDir, 'about', 'index.html'),
|
|
35
|
+
},
|
|
36
|
+
];
|
|
37
|
+
|
|
38
|
+
const bundleGraphMock = {
|
|
39
|
+
getBundles: () => bundles,
|
|
40
|
+
} as any;
|
|
41
|
+
|
|
42
|
+
// We don't care about requestBundleFn for this test, provide a noop.
|
|
43
|
+
provider.update(bundleGraphMock, () => Promise.resolve({} as any));
|
|
44
|
+
|
|
45
|
+
const htmlPaths = provider.getHTMLBundleFilePaths().sort();
|
|
46
|
+
assert.deepStrictEqual(htmlPaths, ['about/index.html', 'index.html']);
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
describe('requestBundle', () => {
|
|
51
|
+
it('returns "not-found" when no bundleGraph is set', async () => {
|
|
52
|
+
const provider = new StaticServerDataProvider('/dist');
|
|
53
|
+
const result = await provider.requestBundle('index.html');
|
|
54
|
+
assert.strictEqual(result, 'not-found');
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('returns "not-found" when the bundle is not present in the graph', async () => {
|
|
58
|
+
const distDir = '/dist';
|
|
59
|
+
const bundles: MockBundle[] = [
|
|
60
|
+
{name: 'index.html', filePath: path.join(distDir, 'index.html')},
|
|
61
|
+
];
|
|
62
|
+
const bundleGraphMock = {
|
|
63
|
+
getBundles: () => bundles,
|
|
64
|
+
} as any;
|
|
65
|
+
|
|
66
|
+
const provider = new StaticServerDataProvider(distDir);
|
|
67
|
+
provider.update(bundleGraphMock, () => Promise.resolve({} as any));
|
|
68
|
+
|
|
69
|
+
const result = await provider.requestBundle('missing.html');
|
|
70
|
+
assert.strictEqual(result, 'not-found');
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('returns "not-found" when requestBundleFn is not set', async () => {
|
|
74
|
+
const distDir = '/dist';
|
|
75
|
+
const bundles: MockBundle[] = [
|
|
76
|
+
{name: 'index.html', filePath: path.join(distDir, 'index.html')},
|
|
77
|
+
];
|
|
78
|
+
const provider = new StaticServerDataProvider(distDir);
|
|
79
|
+
// Directly assign bundleGraph without a requestBundleFn
|
|
80
|
+
(provider as any).bundleGraph = {getBundles: () => bundles} as any;
|
|
81
|
+
|
|
82
|
+
const result = await provider.requestBundle('index.html');
|
|
83
|
+
assert.strictEqual(result, 'not-found');
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('calls requestBundleFn and returns "requested" for a matching bundle', async () => {
|
|
87
|
+
const distDir = '/dist';
|
|
88
|
+
const bundles: MockBundle[] = [
|
|
89
|
+
{name: 'index.html', filePath: path.join(distDir, 'index.html')},
|
|
90
|
+
];
|
|
91
|
+
const bundleGraphMock = {
|
|
92
|
+
getBundles: () => bundles,
|
|
93
|
+
} as any;
|
|
94
|
+
|
|
95
|
+
const requestBundleFn = sinon.stub().resolves();
|
|
96
|
+
|
|
97
|
+
const provider = new StaticServerDataProvider(distDir);
|
|
98
|
+
provider.update(bundleGraphMock, requestBundleFn);
|
|
99
|
+
|
|
100
|
+
const result = await provider.requestBundle('index.html');
|
|
101
|
+
|
|
102
|
+
assert.strictEqual(result, 'requested');
|
|
103
|
+
sinon.assert.calledOnce(requestBundleFn);
|
|
104
|
+
sinon.assert.calledWithExactly(requestBundleFn, bundles[0]);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('handles nested bundle paths correctly', async () => {
|
|
108
|
+
const distDir = '/dist';
|
|
109
|
+
const bundles: MockBundle[] = [
|
|
110
|
+
{
|
|
111
|
+
name: 'nested/index.html',
|
|
112
|
+
filePath: path.join(distDir, 'nested', 'index.html'),
|
|
113
|
+
},
|
|
114
|
+
];
|
|
115
|
+
const bundleGraphMock = {
|
|
116
|
+
getBundles: () => bundles,
|
|
117
|
+
} as any;
|
|
118
|
+
|
|
119
|
+
const requestBundleFn = sinon.stub().resolves();
|
|
120
|
+
|
|
121
|
+
const provider = new StaticServerDataProvider(distDir);
|
|
122
|
+
provider.update(bundleGraphMock, requestBundleFn);
|
|
123
|
+
|
|
124
|
+
const result = await provider.requestBundle('nested/index.html');
|
|
125
|
+
|
|
126
|
+
assert.strictEqual(result, 'requested');
|
|
127
|
+
sinon.assert.calledOnce(requestBundleFn);
|
|
128
|
+
sinon.assert.calledWithExactly(requestBundleFn, bundles[0]);
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
});
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../../tsconfig.base.json",
|
|
3
|
+
"include": ["src"],
|
|
4
|
+
"compilerOptions": {
|
|
5
|
+
"composite": true
|
|
6
|
+
},
|
|
7
|
+
"references": [
|
|
8
|
+
{
|
|
9
|
+
"path": "../../core/plugin/tsconfig.json"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"path": "../../core/types/tsconfig.json"
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"path": "../../core/utils/tsconfig.json"
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
}
|