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

Discuss Sandpack support #80

Closed
mpeterdev opened this issue Dec 19, 2022 · 2 comments
Closed

Discuss Sandpack support #80

mpeterdev opened this issue Dec 19, 2022 · 2 comments

Comments

@mpeterdev
Copy link

After becoming familiar with the NEAR social Viewer implementation during Pagoda's hackathon last week, I started wondering whether Sandpack, the online bundler used and maintained by CodeSandbox, would be effective for rendering widgets.

I put together a POC for consideration at https://github.com/mpeterdev/near-social-sandpack-poc

I realize this is a highly impactful proposal since it would include migrating away from the current custom VM and breaking changes to widget code. I hope its benefits are tempting enough to merit discussion.

Copying the README here for reference:

Near Social - Sandpacked

Live: near-social-sandpacked.vercel.app

POC of using Sandpack, the online bundler used and maintained by CodeSandbox, for the NEAR Social Viewer

Why

Sandpack is built to compile and run modern React in the browser with support for TypeScript, hooks, async/await, etc. Using Sandpack in place of the custom built VM could improve widget DevX while simultaneously lightening the maintenance and development workload of the Viewer project.

How it works

  1. Root widget code is fetched via near-api-js
  2. Widget code is parsed to AST with @swc/wasm-web
  3. Other widgets identified by import statements are fetched and parsed recursively e.g.
    import PokeActivity from '/social-widgets/michaelpeter.near/PokeActivity';
  4. Root widget is loaded into /App.tsx (Sandpack default view) and all other widgets are loaded into their own
    files i.e. /social-widgets/<owner>/<widget>.tsx

Benefits

  • lightens maintenance and development of Viewer
  • robust React support
  • TypeScript support
  • trivial to add npm packages and other dependencies to widget-land
  • security OOTB

Drawbacks

  • initial page load is slower
  • full widget tree is fetched and parsed before any widgets are rendered
  • requires hosting a bundler

Notes

  • monaco is not the default editor but it can be added
  • Viewer app can receive messages from Sandpack iFrame to execute tasks not capable within iFrame (i.e. NEAR Wallet Selector interactions)
  • all imported widget tabs are shown in editor for demonstration, but they can be individually hidden

What would this change

  • widget code would be a full component file, providing the widget as its default export i.e.

    export default function Profile(){...}
  • other widgets would be imported and used by name in tsx/jsx

    import PokeActivity from '/social-widgets/michaelpeter.near/PokeActivity';
    
    return <PokeActivity />;
  • actions not available in iFrame would be handled by sending messages back to Viewer code, but this could be abstracted away by a library
    e.g. opening a link in current tab

    // Widget code
    window.top.postMessage(
      { action: 'link', target: 'https://www.google.com' },
      '*'
    );
    // Viewer code
    window.onmessage = function (e) {
      if (e.data?.action === 'link' && typeof e.data?.target === 'string') {
        window.location.href = e.data.target;
      }
    };
@evgenykuzyakov
Copy link
Contributor

I like it a lot, and I think there should be a version NearSocial that uses this. It does indeed can use social DB, and we may even reuse some existing widgets.

In the past, I've also explored using iframes for security, but choose not to. As you mentioned there are benefits of the full JS/TS VM compatibility, higher performance and external libraries. But you also lose the cross-widget security due to the fact that whole DOM and all methods are available. Any import has to be carefully selected and ideally version locked. Loading everything at once can be sped up by using local cache, so it's not a total blocker.

Also with the current approach we can publish the VM and the Widget component. So you can embed Widgets to any react app externally and they would be native to your app, meaning you can pass properties back and worth. For example, how search component is embedded into the editor: #79

@mpeterdev
Copy link
Author

@evgenykuzyakov ah I see, that makes sense and I can certainly see the attack vectors without widget isolation.

Having multiple viewer experiences is interesting. I would hesitate to fragment the widget ecosystem, especially at such an early stage. We might find, however, that there are developers who want to build on Near Social but would prioritize the capabilities of an iFrame solution over the ability to use third-party widgets.

Thinking out loud, assuming we found that there were developers with that set of priorities:
You could even bundle the two rendering methods into one frontend and use metadata on the root widget to determine whether to load w/ Sandpack or the custom VM.

@mpeterdev mpeterdev closed this as not planned Won't fix, can't repro, duplicate, stale Feb 16, 2023
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

No branches or pull requests

2 participants