question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. ItĀ collects links to all the places you might be looking at while hunting down a tough bug.

And, if youā€™re still stuck at the end, weā€™re happy to hop on a call to see how we can help out.

[labs/ssr] do we need special ssr only async decorators?

See original GitHub issue

Description

I for example quite often inlining svgs when generating html

const headerTemplate =() => html`
  <button id="mobile-menu-trigger" data-action="trigger-mobile-menu">
    <span class="sr-only">Show Menu</span>
     ${readFile(new URL('../assets/burger-menu.svg', import.meta.url), 'utf8').then(res => res.toString())}
  </button>
`;

expected output

<button id="mobile-menu-trigger" data-action="trigger-mobile-menu">
  <span class="sr-only">Show Menu</span>
  <svg>...</svg>
</button>

actual output

<button id="mobile-menu-trigger" data-action="trigger-mobile-menu">
  <span class="sr-only">Show Menu</span>
  [object Promise]
</button>

now there are 2 issues

  • itā€™s async which does render as [object Promise]
  • Using the until wonā€™t help as in ssr there is only one render
  • it uses fs to access a file on the filesystem which you obviously canā€™t do in the browser

some (crazy) ideas

  • have a special ssr directive that only executes in ssr but is ā€œstaticā€ on the client side?
  • have a special ssr async directive that ā€œblocksā€ the rendering until itā€™s resolved so you get the value you want in a single pass?

what do you think?

Additional info

a simplified version

function* generator(i) {
  yield i;
  yield i + 10;
}

const template = ({ title, lang }) => html`
  <p>${title}</p>
  ${new Promise((res) => { setTimeout(res('resolved-promise'), 10)})}
  ${generator(1)}
`;

expected

<p>hello</p>
resolved-promise
1

actual

<p>hello</p>
[object Promise]
[object Generator]

Issue Analytics

  • State:open
  • Created 2 years ago
  • Reactions:1
  • Comments:10 (8 by maintainers)

github_iconTop GitHub Comments

2reactions
daKmoRcommented, Mar 26, 2022

hmmm I just ran into this again šŸ˜…

not loading any server side code statically totally makes sense šŸ‘

In this case I can not work around itā€¦ as the async server code depends on a property of the element šŸ˜­

export class OpenGraphOverview extends LitElement {
  static properties = {
    urls: { type: String },
    inputDir: { type: String, attribute: 'input-dir' },
  };

  render() {
    const iframeUrl = this.url.endsWith('/')
      ? `${this.url}index.opengraph.html`
      : this.url.replace(/\.html$/, '.opengraph.html');
      
    return html`
      <div>
          <a href="vscode://${hydrateAbleUrlToSourceFilePath(url, this.inputDir)}">
            <server-icon icon="solid/laptop-code"></server-icon>
          </a>
          <iframe src="${iframeUrl}" loading="lazy" width="1200" height="628"></iframe>
      </div>
    `;      
}

const isSsr = window && window.navigator ? false : true;

async function serverUrlToSourceFilePath(url, inputDir) {
  const { urlToSourceFilePath } = await import('@rocket/engine');
  // urlToSourceFilePath is a function that searched the file system for potential matches
  // e.g. it's async & needs access to the file system
  return serverUntil(urlToSourceFilePath(url, inputDir));
}

const hydrateAbleUrlToSourceFilePath = isSsr ? serverUrlToSourceFilePath : () => noChange;

on the server side I can then render it like this

export default () => html`
  <opengraph-overview
    urls="${JSON.stringify(urls)}"
    input-dir=${new URL('./', import.meta.url).href}
  ></opengraph-overview>
`;

which result in this

<opengraph-overview 
  urls="[&quot;/&quot;,&quot;/docs/&quot;,&quot;/docs/setup/&quot;]" 
  input-dir="file:///html/rocket/site/pages/">
  <!--lit-node 1-->
</opengraph-overview>

which I guess could then be hydrated šŸ¤”

Soooo I think this will need a few steps to make it work šŸ˜…

1. some way to execute an async code via ssr

As a first step having a serverUntil makes sense. What would it take to make it happen? Iā€™m that is the most important part as this will need to be backed into lit-ssr. and there are you could use.

Impact: No user code workarounds possible => this is actually blocking me right now

2. Best practices for how to make hydratable server functions

Show and explain how static imports to server needing function break hydration. So if you want to hydrate you need to use a dynamic import for server functions.

Impact: You can already do this yourself right now - so not blocking.

3. Streamline

Once we have it working we can look into improving the developer experience. Some potential options

  • until behaves like serverUntil while using ssr and later does nothing?
  • automatic wrapper helpers to dynamically load server functions
  • ā€¦

Impact: Itā€™s a nice to have for now.

0reactions
steveworkmancommented, May 27, 2022

Can we work around any of this by making use of the Task labs package? Extend this to have an SSR state beyond the regular states would give a nice interface to manage server-side async functions

Read more comments on GitHub >

github_iconTop Results From Across the Web

Authoring components for Lit SSR - Lit.dev
When authoring components, perform imperative DOM operations from lifecycle methods that are called only on the client, and not on the server. For...
Read more >
Recipe for universal decorator that accepts async function #150
I wonder if there's an elegant way to make a universal decorator that accepts both sync and async function... or classes and async...
Read more >
How do you write decorators for both async and sync functions ...
Write two functions: async and a sync one with exact body but a different return call and conditionally return one. Write a functional...
Read more >
Decorating Async JavaScript Functions - Innolitics
In this article, we explore how to extend async JavaScript functions using a functional design patternā€”the decorator.
Read more >
Python Decorators Manual - Denis Kovalev
Class-based async decorator with optional arguments ... To understand how decorators work first we need to look into closures.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found