Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(runtime): add preview.pathname #233

Merged
merged 5 commits into from
Aug 12, 2024

Conversation

AriPerkkio
Copy link
Member

Adds support for defining pathname for previews. Example from Vite Plugin Tutorial where I'd like to show two previews for same server:

---
type: lesson
title: Extra - Source map support
focus: /vite.config.ts
previews:
  - { port: 5173, title: "Vite" }
  - { port: 5173, title: "Inspect", pathname: "/__inspect/" }
---

This will also be useful for remult tutorial: https://learn.remult.dev/1-basics/5-live-query/2-realtime-updates - mentioned here #226

Copy link

stackblitz bot commented Aug 9, 2024

Review PR in StackBlitz Codeflow Run & review this pull request in StackBlitz Codeflow.

@AriPerkkio AriPerkkio marked this pull request as ready for review August 9, 2024 15:14
Copy link
Member

@Nemikolh Nemikolh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the config change!

I would prefer if we had _availablePreviews set to Map<number, PortInfo> instead which it should have been from the beginning. The idea behind _availablePreviews was to track information about the active ports from a webcontainer perspective.

However, when I had written the code I thought that most use case would probably have a single preview per port which is an over-simplification.

The correct approach is to use a different class in _availablePreviews other than PreviewInfo and make sure all PreviewInfo instances point to that instance.

So that means:

class PortInfo {
   constructor(
     public readonly port: number,
     public origin: string;
     public ready: boolean
  ) {}
}

Then we modify PreviewInfo to something like:

export class PreviewInfo {
-  port: number;
-  ready: boolean;
-  baseUrl?: string;
+  readonly portInfo: PortInfo; // initialized in constructor
+
+  get port() { return this.portInfo.port; }
+  get baseUrl() { return this.portInfo.origin; }

Finally when setPreviews is called we check if a PortInfo is present in the Map. If it isn't then we create one, and in webcontainer.on('port') we update that instance instead.

We could also consider have the ready and origin fields in PortInfo be atoms which I think could make sense, however given that in the current code we signal changes on previews by setting the previews atom on PreviewsStore to a new array instance, we don't really need those to be atom I think.

packages/runtime/src/store/previews.ts Outdated Show resolved Hide resolved
packages/runtime/src/store/previews.ts Show resolved Hide resolved
packages/runtime/src/store/previews.ts Show resolved Hide resolved
@AriPerkkio
Copy link
Member Author

I would prefer if we had _availablePreviews set to Map<number, PortInfo>

export class PreviewInfo {
+  readonly portInfo: PortInfo; // initialized in constructor

I think we need to either make it Map<number, PortInfo[]> or public portInfo, so that we can mark multiple PortInfo's ready at once.

If it was public field that allows overwriting, we would do it here:

    const previewInfos = previews.map((preview) => {
      const info = new PreviewInfo(preview);
      const portInfo = this._availablePreviews.get(info.port);

      if (!portInfo) {
        this._availablePreviews.set(info.port, info.portInfo);
      } else {
        info.portInfo = portInfo; // <-- All previews sharing same port should point to same portInfo
      }

      return info;
    });

Or if we would track multiple PortInfo[] in the map, we could then mark all of them ready on webcontainer's port event.

@Nemikolh
Copy link
Member

I think we need to either make it Map<number, PortInfo[]> or public portInfo, so that we can mark multiple PortInfo's ready at once.

I don't think I'm following that reasoning. A single instance of PreviewInfo uses a single port.

In your code snippet:

   const previewInfos = previews.map((preview) => {
     const info = new PreviewInfo(preview);
     const portInfo = this._availablePreviews.get(info.port);

     if (!portInfo) {
       this._availablePreviews.set(info.port, info.portInfo);
     } else {
       info.portInfo = portInfo; // <-- All previews sharing same port should point to same portInfo
     }

     return info;
   });

The logic should be changed to:

    const previewInfos = previews.map((preview) => {
      const port = PreviewInfo.parsePort(preview);
      let portInfo = this._availablePreviews.get(port);

      if (!portInfo) {
        portInfo = new PortInfo(port);
        this._availablePreviews.set(port, portInfo);
      }

      return new PreviewInfo(preview, portInfo);
    });

@AriPerkkio
Copy link
Member Author

The logic should be changed to:

This looks good, I've applied these changes!

This allows us to have multiple PreviewInfo's referencing a single PortInfo, so that on webcontainer's port event we can mark multiple PreviewInfo's ready at once. This is what #233 (comment) was essentially about. 👍

Copy link
Member

@Nemikolh Nemikolh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks really good! 🤩

Really good job on this! 🎉

@Nemikolh Nemikolh merged commit 9bf2156 into stackblitz:main Aug 12, 2024
9 checks passed
@AriPerkkio AriPerkkio deleted the feat/preview-pathname branch August 12, 2024 13:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Adding urls to the previews definition
2 participants