@atlaspack/reporter-dev-server 2.14.22 → 2.14.24

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 CHANGED
@@ -1,5 +1,23 @@
1
1
  # @atlaspack/reporter-dev-server
2
2
 
3
+ ## 2.14.24
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies []:
8
+ - @atlaspack/utils@2.18.1
9
+ - @atlaspack/plugin@2.14.24
10
+ - @atlaspack/types@2.15.14
11
+
12
+ ## 2.14.23
13
+
14
+ ### Patch Changes
15
+
16
+ - Updated dependencies [[`23d561e`](https://github.com/atlassian-labs/atlaspack/commit/23d561e51e68b0c38fd1ff4e4fb173e5e7b01cf2)]:
17
+ - @atlaspack/utils@2.18.0
18
+ - @atlaspack/types@2.15.13
19
+ - @atlaspack/plugin@2.14.23
20
+
3
21
  ## 2.14.22
4
22
 
5
23
  ### Patch Changes
package/lib/Server.js CHANGED
@@ -88,16 +88,6 @@ function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e;
88
88
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
89
89
  // @ts-expect-error TS2307
90
90
 
91
- // @ts-expect-error TS7016
92
-
93
- // @ts-expect-error TS7016
94
-
95
- // @ts-expect-error TS7016
96
-
97
- // @ts-expect-error TS7016
98
-
99
- // @ts-expect-error TS7016
100
-
101
91
  function setHeaders(res) {
102
92
  res.setHeader('Access-Control-Allow-Origin', '*');
103
93
  res.setHeader('Access-Control-Allow-Methods', 'GET, HEAD, PUT, PATCH, POST, DELETE');
@@ -425,13 +415,10 @@ class Server {
425
415
  }
426
416
  };
427
417
  const app = (0, _connect().default)();
428
- // @ts-expect-error TS7006
429
418
  app.use((req, res, next) => {
430
419
  setHeaders(res);
431
420
  next();
432
421
  });
433
-
434
- // @ts-expect-error TS7006
435
422
  app.use((req, res, next) => {
436
423
  if (req.url === '/__parcel_healthcheck') {
437
424
  res.statusCode = 200;
@@ -0,0 +1 @@
1
+ "use strict";
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.StaticServerDataProvider = void 0;
7
+ function _path() {
8
+ const data = _interopRequireDefault(require("path"));
9
+ _path = function () {
10
+ return data;
11
+ };
12
+ return data;
13
+ }
14
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
15
+ /**
16
+ * An implementation of ServerDataProvider provides data from a direct `bundleGraph`
17
+ * and `requestBundle` function.
18
+ */
19
+ class StaticServerDataProvider {
20
+ bundleGraph = null;
21
+ requestBundleFn = null;
22
+ constructor(distDir) {
23
+ this.distDir = distDir;
24
+ }
25
+ getHTMLBundleFilePaths() {
26
+ var _this$bundleGraph;
27
+ return ((_this$bundleGraph = this.bundleGraph) === null || _this$bundleGraph === void 0 ? void 0 : _this$bundleGraph.getBundles().filter(b => _path().default.posix.extname(b.name) === '.html').map(b => _path().default.relative(this.distDir, b.filePath))) ?? [];
28
+ }
29
+ async requestBundle(requestedPath) {
30
+ var _this$bundleGraph2;
31
+ const bundle = (_this$bundleGraph2 = this.bundleGraph) === null || _this$bundleGraph2 === void 0 ? void 0 : _this$bundleGraph2.getBundles().find(b => {
32
+ const relativePath = _path().default.relative(this.distDir, b.filePath);
33
+ return relativePath === requestedPath;
34
+ });
35
+ if (!bundle) {
36
+ return 'not-found';
37
+ }
38
+ if (!this.requestBundleFn) {
39
+ return 'not-found';
40
+ }
41
+ await this.requestBundleFn(bundle);
42
+ return 'requested';
43
+ }
44
+
45
+ /**
46
+ * Update the provider with the latest bundle graph and request function.
47
+ *
48
+ * This should be called after every successful build so that subsequent requests operate on fresh data.
49
+ *
50
+ * @param bundleGraph The most recent bundle graph representing the output of a build.
51
+ * @param requestBundleFn Function that will be called to (re)build a specific bundle on demand.
52
+ */
53
+ update(bundleGraph, requestBundleFn) {
54
+ this.bundleGraph = bundleGraph;
55
+ this.requestBundleFn = requestBundleFn;
56
+ }
57
+ }
58
+ exports.StaticServerDataProvider = StaticServerDataProvider;
@@ -0,0 +1 @@
1
+ "use strict";
@@ -0,0 +1,33 @@
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
+ * Attempt to (re)build the bundle that corresponds to the given request path.
20
+ *
21
+ * If a bundle matching `requestedPath` exists and a request handler has been
22
+ * provided, the implementation should trigger a rebuild and resolve the
23
+ * promise with "requested". Otherwise the promise must resolve with
24
+ * "not-found".
25
+ *
26
+ * @param requestedPath Path (relative to the distribution directory) that
27
+ * identifies the bundle file requested by the browser.
28
+ * @returns A promise that resolves to:
29
+ * - "requested" when the build has been successfully triggered, or
30
+ * - "not-found" when the bundle cannot be handled by the provider.
31
+ */
32
+ requestBundle(requestedPath: string): Promise<'requested' | 'not-found'>;
33
+ }
@@ -0,0 +1,23 @@
1
+ import type { BundleGraph, PackagedBundle, BuildSuccessEvent } from '@atlaspack/types';
2
+ import { ServerDataProvider } from './ServerDataProvider';
3
+ /**
4
+ * An implementation of ServerDataProvider provides data from a direct `bundleGraph`
5
+ * and `requestBundle` function.
6
+ */
7
+ export declare class StaticServerDataProvider implements ServerDataProvider {
8
+ private distDir;
9
+ private bundleGraph;
10
+ private requestBundleFn;
11
+ constructor(distDir: string);
12
+ getHTMLBundleFilePaths(): string[];
13
+ requestBundle(requestedPath: string): Promise<'requested' | 'not-found'>;
14
+ /**
15
+ * Update the provider with the latest bundle graph and request function.
16
+ *
17
+ * This should be called after every successful build so that subsequent requests operate on fresh data.
18
+ *
19
+ * @param bundleGraph The most recent bundle graph representing the output of a build.
20
+ * @param requestBundleFn Function that will be called to (re)build a specific bundle on demand.
21
+ */
22
+ update(bundleGraph: BundleGraph<PackagedBundle>, requestBundleFn: (bundle: PackagedBundle) => Promise<BuildSuccessEvent>): void;
23
+ }
@@ -0,0 +1,34 @@
1
+ import type { ServerOptions, PluginLogger, HMROptions, HTTPSOptions, FilePath, PackageManager } from '@atlaspack/types';
2
+ import type { FileSystem } from '@atlaspack/fs';
3
+ import type { HTTPServer } from '@atlaspack/utils';
4
+ import { IncomingMessage, ServerResponse } from 'http';
5
+ interface HTTPRequest extends IncomingMessage {
6
+ originalUrl?: string;
7
+ }
8
+ export type Request = HTTPRequest;
9
+ export type Response = ServerResponse;
10
+ export type DevServerOptions = ServerOptions & {
11
+ projectRoot: string;
12
+ publicUrl: string;
13
+ cacheDir: string;
14
+ inputFS: FileSystem;
15
+ outputFS: FileSystem;
16
+ logger: PluginLogger;
17
+ hmrOptions?: HMROptions | null | undefined;
18
+ packageManager: PackageManager;
19
+ };
20
+ export type ServerError = Error & {
21
+ code: string;
22
+ };
23
+ export type HMRServerOptions = {
24
+ devServer?: HTTPServer;
25
+ addMiddleware?: (handler: (req: Request, res: Response) => boolean) => void;
26
+ port: number;
27
+ host?: string | null | undefined;
28
+ logger: PluginLogger;
29
+ https?: HTTPSOptions | boolean;
30
+ cacheDir: FilePath;
31
+ inputFS: FileSystem;
32
+ outputFS: FileSystem;
33
+ };
34
+ export {};
package/lib/types.js ADDED
@@ -0,0 +1 @@
1
+ "use strict";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlaspack/reporter-dev-server",
3
- "version": "2.14.22",
3
+ "version": "2.14.24",
4
4
  "description": "Blazing fast, zero configuration web application bundler",
5
5
  "license": "(MIT OR Apache-2.0)",
6
6
  "type": "commonjs",
@@ -13,7 +13,7 @@
13
13
  },
14
14
  "main": "./lib/ServerReporter.js",
15
15
  "source": "./src/ServerReporter.ts",
16
- "types": "./lib/ServerReporter.d.ts",
16
+ "types": "./lib/types/ServerReporter.d.ts",
17
17
  "engines": {
18
18
  "node": ">= 16.0.0"
19
19
  },
@@ -26,9 +26,9 @@
26
26
  }
27
27
  },
28
28
  "dependencies": {
29
- "@atlaspack/plugin": "2.14.22",
30
- "@atlaspack/utils": "2.17.4",
31
- "@atlaspack/types": "2.15.12",
29
+ "@atlaspack/plugin": "2.14.24",
30
+ "@atlaspack/utils": "2.18.1",
31
+ "@atlaspack/types": "2.15.14",
32
32
  "connect": "^3.7.0",
33
33
  "ejs": "^3.1.6",
34
34
  "fresh": "^0.5.2",
@@ -40,9 +40,14 @@
40
40
  "ws": "^7.0.0"
41
41
  },
42
42
  "devDependencies": {
43
- "@atlaspack/babel-preset": "2.14.2"
43
+ "@atlaspack/babel-preset": "2.14.2",
44
+ "@types/connect": "^3.4.38",
45
+ "@types/ejs": "^3.1.5",
46
+ "@types/fresh": "^0.5.3",
47
+ "@types/serve-handler": "^6.1.4"
44
48
  },
45
49
  "scripts": {
46
- "check-ts": "tsc --emitDeclarationOnly --rootDir src"
50
+ "check-ts": "tsc --emitDeclarationOnly --rootDir src",
51
+ "build:lib": "gulp build --gulpfile ../../../gulpfile.js --cwd ."
47
52
  }
48
- }
53
+ }
package/src/Server.ts CHANGED
@@ -24,17 +24,12 @@ import {
24
24
  } from '@atlaspack/utils';
25
25
  import serverErrors from './serverErrors';
26
26
  import fs from 'fs';
27
- // @ts-expect-error TS7016
28
27
  import ejs from 'ejs';
29
- // @ts-expect-error TS7016
30
28
  import connect from 'connect';
31
- // @ts-expect-error TS7016
32
29
  import serveHandler from 'serve-handler';
33
30
  import {createProxyMiddleware} from 'http-proxy-middleware';
34
31
  import {URL, URLSearchParams} from 'url';
35
- // @ts-expect-error TS7016
36
32
  import launchEditor from 'launch-editor';
37
- // @ts-expect-error TS7016
38
33
  import fresh from 'fresh';
39
34
 
40
35
  export function setHeaders(res: Response) {
@@ -504,13 +499,11 @@ export default class Server {
504
499
  };
505
500
 
506
501
  const app = connect();
507
- // @ts-expect-error TS7006
508
502
  app.use((req, res, next) => {
509
503
  setHeaders(res);
510
504
  next();
511
505
  });
512
506
 
513
- // @ts-expect-error TS7006
514
507
  app.use((req, res, next) => {
515
508
  if (req.url === '/__parcel_healthcheck') {
516
509
  res.statusCode = 200;
@@ -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
+ }
@@ -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
+ }
@@ -0,0 +1,4 @@
1
+ declare module 'launch-editor' {
2
+ function launchEditor(filePath: string): void;
3
+ export default launchEditor;
4
+ }
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
+ });
File without changes
File without changes