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.

Automatically re-rendering when inline markdown changes

See original GitHub issue

Hey there!

This is a feature request to add automatic partial re-rendering when the inline markdown changes.

Below is a basic and slightly naive proof of concept in the form of an extension to ZeroMd, just to provide some working code. Here’s the gist of it:

  • Using a MutationObserver to detect changes in the inline markdown’s <script>;
  • When a change occurs, re-render only the markdown body
    • Why not use the existing render()? Because it clears the element’s DOM and rebuilds the CSS, which causes an unwanted flash between the old content and the new content.
class ZeroMdExample extends ZeroMd {
  connectedCallback()
  {
    super.connectedCallback();
  
    const script = this.querySelector("script[type='text/markdown']");
  
    if (script) {
      const observer = new MutationObserver(() => this.updateFromInlineContent());
      observer.observe(script, { characterData: true, attributes: true, childList: true, subtree: true });
    }
  }
  
  async updateFromInlineContent (opts = {}) {
    await this.waitForReady();
    const md = await this.buildMd(opts);
    this.shadowRoot.querySelector(".markdown-body").replaceWith(md);
  }
}

There are plenty of optimizations and improvements to be made, of course, but this is a quick suggestion of how it could be handled.

If this seems like a viable way to implement the feature, or if you have any feedback, just let me know - I would gladly get to work on a PR for this.

Cheers!

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:8 (8 by maintainers)

github_iconTop GitHub Comments

1reaction
zerodevxcommented, May 17, 2021

Hi @EmilePerron, thanks so much for reaching out - I think it’s a great feature and I’d love a PR! 😁

On first pass, this may not be a trivial feature to implement. Some thoughts come to mind:

  1. Probably both <script> and style <template> tags should be observed for changes.

  2. I guess mutation callbacks must be debounced so multiple calls will only trigger a re-render once. (I didn’t read in detail on MutationObserver specs though, maybe it’s native?)

  3. Perhaps the render() function can be re-factored to support conditional DOM stamping (or re-building)? Something like if render() is called twice in a row, checks are added so that the second call shouldn’t actually re-stamp i.e. render() will only render changes.

There are probably other optimisations and gotchas too, so let’s keep this thread open for discussion! Also do let me know if there’s anything I can help with. Thanks so much for you time once again. 👍

0reactions
zerodevxcommented, Jun 25, 2021

Hi @EmilePerron

My apologies for the wait. I (finally) reviewed PR #51 and it generally looks very good.

I have included simple test cases for both styles and content changes, which are both passing at the moment.

Thanks for adding the tests. They look very good!

Insertion and removal of <template> and <script type="text/markdown"> tags in the component are detected with a MutationObserver and trigger a partial re-rendering of styles and/or content (via the new refreshStyle() and/or refreshContent())

Updates to <template> and <script type="text/markdown"> elements in the component also trigger partial re-rendering of the appropriate part of the component, using the same methods.

I still feel there’s an opportunity to refactor the render() method to render changes instead, which removes the need for refreshStyle() and refreshContent() - and IMO simplifies the codebase as well.

When a partial re-rendering occurs, the zero-md-rendered event is fired just like in the render() method. However, it includes a partial flag and a part indicator in the event.detail (ex.: this.fire(‘zero-md-rendered’, { partial: true, part: ‘body’ }))

Thanks for the recommendation. I’ll document this API change.

This feature is inactive when the component is in manual-render mode.

Good catch!

More tests could likely be added to ensure there’s no regression in relation with other features (ex.: no-shadow, manual-render, more complex manipulations, etc.).

Coverage seems OK so far; we can add as and when bug reports surface. 😄

You’ll likely want to review the code style - I tried to match yours as closely as I could (and lint checks all pass), but I tend to be very verbose and space heavy, so it might not be up to your standards 😬

Thanks for doing this! I don’t personally have big opinions on this - as long as it passes standardjs linting it’s an OK.

I’ll probably merge this upstream in a bit - I’ll also see if there’re opportunities to simplify, if not today then soon. Thanks so much!

Read more comments on GitHub >

github_iconTop Results From Across the Web

Automatically re-render markdown when renderer settings ...
My workaround was to append the markdown with a zero-width space character, then use a setTimeout to remove it. It would be nicer,...
Read more >
How to Safely Render Markdown From a React Component
Step-by-step guide on how to safely render Markdown within your React Component using react-markdown.
Read more >
A Story of a React Re-Rendering Bug - Engineering Blog
We know, by default, one React component will only be re-rendered if its state gets changed, either caused by props change, or triggered...
Read more >
A (Mostly) Complete Guide to React Rendering Behavior
In normal rendering, React does not care whether "props changed" - it will render child components unconditionally just because the parent ...
Read more >
17.3 Render R Markdown with rmarkdown::render() - Bookdown
This means you can programmatically render an R Markdown document in any R script. For example, you could render a series of reports...
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