Skip to content

Commit

Permalink
feat(runtime): add preview.pathname
Browse files Browse the repository at this point in the history
  • Loading branch information
AriPerkkio committed Aug 9, 2024
1 parent bd0ca1a commit adefbd5
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 25 deletions.
20 changes: 17 additions & 3 deletions docs/tutorialkit.dev/src/content/docs/reference/configuration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -91,18 +91,32 @@ Configure whether or not the editor should be rendered. If an object is provided
##### `previews`
Configure which ports should be used for the previews allowing you to align the behavior with your demo application's dev server setup. If not specified, the lowest port will be used.

You can optionally provide these as an array of tuples where the first element is the port number and the second is the title of the preview, or as an object.
<PropertyTable inherited type={'Preview[]'} />

The `Preview` type has the following shape:

```ts
type Preview = string
type Preview =
| number
| string
| [port: number, title: string]
| { port: number, title: string }
| [port: number, title: string, pathname: string]
| { port: number, title: string, pathname?: string }

```

Example value:

```yaml
previews:
- 3000 # Preview is on :3000/
- "3001/docs" # Preview is on :3001/docs/
- [3002, "Dev Server"] # Preview is on :3002/. Displayed title is "Dev Server".
- [3003, "Dev Server", "/docs"] # Preview is on :3003/docs/. Displayed title is "Dev Server".
- { port: 3004, title: "Dev Server" } # Preview is on :3004/. Displayed title is "Dev Server".
- { port: 3005, title: "Dev Server", pathname: "/docs" } # Preview is on :3005/docs/. Displayed title is "Dev Server".
```
##### `mainCommand`
The main command to be executed. This command will run after the `prepareCommands`.
<PropertyTable inherited type="Command" />
Expand Down
25 changes: 13 additions & 12 deletions packages/runtime/src/store/previews.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { PreviewInfo } from '../webcontainer/preview-info.js';
import type { WebContainer } from '@webcontainer/api';

export class PreviewsStore {
private _availablePreviews = new Map<number, PreviewInfo>();
private _availablePreviews: PreviewInfo[] = [];
private _previewsLayout: PreviewInfo[] = [];

/**
Expand All @@ -21,18 +21,21 @@ export class PreviewsStore {
const webcontainer = await webcontainerPromise;

webcontainer.on('port', (port, type, url) => {
let previewInfo = this._availablePreviews.get(port);
const previewInfos = this._availablePreviews.filter((preview) => preview.port === port);

if (!previewInfo) {
previewInfo = new PreviewInfo(port, type === 'open');
this._availablePreviews.set(port, previewInfo);
if (previewInfos.length === 0) {
const info = new PreviewInfo(port, type === 'open');
previewInfos.push(info);
this._availablePreviews.push(info);
}

previewInfo.ready = type === 'open';
previewInfo.baseUrl = url;
previewInfos.forEach((info) => {
info.ready = type === 'open';
info.baseUrl = url;
});

if (this._previewsLayout.length === 0) {
this.previews.set([previewInfo]);
this.previews.set(previewInfos);
} else {
this._previewsLayout = [...this._previewsLayout];
this.previews.set(this._previewsLayout);
Expand All @@ -58,14 +61,12 @@ export class PreviewsStore {
const previewInfos = previews.map((preview) => {
const info = new PreviewInfo(preview);

let previewInfo = this._availablePreviews.get(info.port);
let previewInfo = this._availablePreviews.find((availablePreview) => PreviewInfo.equals(info, availablePreview));

if (!previewInfo) {
previewInfo = info;

this._availablePreviews.set(previewInfo.port, previewInfo);
} else {
previewInfo.title = info.title;
this._availablePreviews.push(previewInfo);
}

return previewInfo;
Expand Down
39 changes: 33 additions & 6 deletions packages/runtime/src/webcontainer/preview-info.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,52 @@ import { describe, it, expect } from 'vitest';
import { PreviewInfo } from './preview-info.js';

describe('PreviewInfo', () => {
it('should accept a port', () => {
it('should accept a number for port', () => {
const previewInfo = new PreviewInfo(3000);

expect(previewInfo.port).toBe(3000);
expect(previewInfo.title).toBe(undefined);
expect(previewInfo.pathname).toBe(undefined);
});

it('should accept a string for port and pathname', () => {
const previewInfo = new PreviewInfo('3000/some/nested/path');

expect(previewInfo.port).toBe(3000);
expect(previewInfo.pathname).toBe('some/nested/path');
expect(previewInfo.title).toBe(undefined);
});

it('should accept a tuple of [port, title]', () => {
const previewInfo = new PreviewInfo([3000, 'Local server']);

expect(previewInfo.port).toBe(3000);
expect(previewInfo.title).toBe('Local server');
expect(previewInfo.pathname).toBe(undefined);
});

it('should accept a tuple of [port, title, pathname]', () => {
const previewInfo = new PreviewInfo([3000, 'Local server', '/docs']);

expect(previewInfo.port).toBe(3000);
expect(previewInfo.title).toBe('Local server');
expect(previewInfo.pathname).toBe('/docs');
});

it('should accept an object with { port, title }', () => {
const previewInfo = new PreviewInfo({ port: 3000, title: 'Local server' });

expect(previewInfo.port).toBe(3000);
expect(previewInfo.title).toBe('Local server');
expect(previewInfo.pathname).toBe(undefined);
});

it('should accept an object with { port, title, pathname }', () => {
const previewInfo = new PreviewInfo({ port: 3000, title: 'Local server', pathname: '/docs' });

expect(previewInfo.port).toBe(3000);
expect(previewInfo.title).toBe('Local server');
expect(previewInfo.pathname).toBe('/docs');
});

it('should not be ready by default', () => {
Expand All @@ -41,9 +69,8 @@ describe('PreviewInfo', () => {
});

it('should have a url with a custom pathname and baseUrl', () => {
const previewInfo = new PreviewInfo(3000);
const previewInfo = new PreviewInfo('3000/foo');
previewInfo.baseUrl = 'https://example.com';
previewInfo.pathname = '/foo';

expect(previewInfo.url).toBe('https://example.com/foo');
});
Expand Down Expand Up @@ -71,10 +98,10 @@ describe('PreviewInfo', () => {

it('should not be equal to another preview info with a different pathname', () => {
const a = new PreviewInfo(3000);
const b = new PreviewInfo(3000);

a.pathname = '/foo';
const b = new PreviewInfo('3000/b');
const c = new PreviewInfo('3000/c');

expect(PreviewInfo.equals(a, b)).toBe(false);
expect(PreviewInfo.equals(b, c)).toBe(false);
});
});
6 changes: 6 additions & 0 deletions packages/runtime/src/webcontainer/preview-info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,18 @@ export class PreviewInfo {
constructor(preview: Exclude<PreviewSchema, boolean>[0], ready?: boolean) {
if (typeof preview === 'number') {
this.port = preview;
} else if (typeof preview === 'string') {
const [port, ...rest] = preview.split('/');
this.port = parseInt(port);
this.pathname = rest.join('/');
} else if (Array.isArray(preview)) {
this.port = preview[0];
this.title = preview[1];
this.pathname = preview[2];
} else {
this.port = preview.port;
this.title = preview.title;
this.pathname = preview.pathname;
}

this.ready = !!ready;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ title: Foo from part 1
slug: foo
focus: /src/index.html
previews:
- [8080, 'Main Page']
- { title: 'Main Page', port: 8080, pathname: '/src'}
- [1, 'Test Runner']
- [2, 'Bar']
- '2/some/custom/pathname'
- '2/another/pathname'
terminal:
panels: 'terminal'
editPageLink: 'https://tutorialkit.dev'
Expand Down
2 changes: 1 addition & 1 deletion packages/template/src/templates/default/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ createServer((_req, res) => {
`);
}).listen(1);

createServer((_req, res) => res.end('Server 2')).listen(2);
createServer((req, res) => res.end(`Server 2\n${req.method} ${req.url}`)).listen(2);

servor({
root: 'src/',
Expand Down
7 changes: 6 additions & 1 deletion packages/types/src/schemas/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,17 @@ export const previewSchema = z.union([
// a single number, the port for the preview
z.number(),

// a tuple, the port followed by a title
// a string, the port and pathname
z.string(),

// a tuple, the port followed by a title and optional pathname
z.tuple([z.number(), z.string()]),
z.tuple([z.number(), z.string(), z.string()]),

z.strictObject({
port: z.number().describe('Port number of the preview.'),
title: z.string().describe('Title of the preview.'),
pathname: z.string().optional().describe('Pathname of the preview URL.'),
}),
])
.array(),
Expand Down

0 comments on commit adefbd5

Please sign in to comment.