Disqus component (WIP)

Hello!

Streamlit components offers a great opportunity to embed useful services in streamlit apps. One of them is disqus, a popular commenting system embedded in multiple blogs and web pages. IMO, having such service as a component would be of great value for the ecosystem.

So far, I’ve got a mostly working disqus. However, I haven’t found a way to dynamically resize the component’s iframe’s height. Setting the iframe’s height to “auto” didn’t help.

Here’s a preview:

Here's the python part
import streamlit as st

Disqus = st.declare_component(url="http://localhost:3001")

@Disqus
def create_instance(f, shortname, url, identifier, title):
    """Disqus."""
    return f(shortname=shortname, url=url, identifier=identifier, title=title, key="streamlit-disqus-thread")


st.register_component("disqus", Disqus)

st.disqus("streamlit-disqus-component", "http://localhost:8501", "test", "Streamlit test")

st.sidebar.title("Disqus test")
st.write("---")
st.write("# Next section")
st.write("Hello world")
And here the react part
import React, { useEffect } from "react"
import { DiscussionEmbed } from "disqus-react"
import {
  withStreamlitConnection,
  ComponentProps,
  Streamlit,
} from "./streamlit"

import "bootstrap/dist/css/bootstrap.min.css"
import "./streamlit.css"

const Disqus = (props: ComponentProps) => {
  useEffect(() => {
    Streamlit.setFrameHeight(500)
  })

  return (
    <DiscussionEmbed
      shortname={props.args.shortname}
      config={{
        url: props.args.url,
        identifier: props.args.identifier,
        title: props.args.title
      }}
    />
  )
}

export default withStreamlitConnection(Disqus)
3 Likes

I agree, having the ability to comment on an app could work really well in an educational/work environment, if the app represents an experiment or other analysis

2 Likes

Are you maintaining these components as Git repos anywhere?

For now it’s on private repos while components are on closed beta.

1 Like

Makes sense.

I’ve been investigating a little on that auto resize issue, and it seems that there is no obvious way to do it as far as I understood. If there is one, I’d be glad to hear it :smiley:

For testing purposes I'm using a MutationObserver to get notified when I should update the frame height.
import React, { useEffect, useRef } from "react"
import { DiscussionEmbed } from "disqus-react"
import {
  withStreamlitConnection,
  ComponentProps,
  Streamlit,
} from "./streamlit"

import "bootstrap/dist/css/bootstrap.min.css"
import "./streamlit.css"

function Disqus(props: ComponentProps) {
  const container = useRef<HTMLDivElement>(null)
  const observer = new MutationObserver(mutation => {
    Streamlit.setFrameHeight()  // Causes infinite reloads because of re-rendering
  })

  useEffect(() => {
    if (container.current) {
      observer.observe(container.current, {
        attributes: true,
        subtree: true
      })
    }
    return () => {
      observer.disconnect()
    }
  }, [])

  return (
    <div ref={container}>
      <DiscussionEmbed
        shortname={props.args.shortname}
        config={{
          url: props.args.url,
          identifier: props.args.identifier,
          title: props.args.title
        }}
      />
    </div>
  )
}

export default withStreamlitConnection(Disqus)

However, calling Streamlit.setFrameHeight() causes a re-render which makes Disqus reload constantly. The reason is that setState is called everytime a streamlit:setFrameHeight message is sent.

To support setting the height without having to reload the component each time, we could rely on a react reference to get the component’s DOM, and set its height.

This change would affect the ComponentInstance class in frontend/src/components/widgets/CustomComponent/ComponentInstance.tsx.

I’ll fill a github issue when I have time.

1 Like

Small update, I’ve created a GitHub issue and made the changes in a fork. With this fix, my Disqus component can update its height with no re-render issue.


2 Likes

Hey @synode - thanks for posting this, and apologies for the late response!

I just cherry-picked your fix, tweaked it slightly, and merged it into the streamlit components branch: https://github.com/streamlit/streamlit/pull/1602

This will go out in the next beta, later today or tomorrow.

Hey @tim,

That’s great news! Thanks for the update and the hard work!
I’ll update my components and finish the Disqus one as soon as I can.

1 Like

I’ve made some tests, and unfortunately Disqus doesn’t like to be in an iframe which doesn’t have allow-same-origin.

I saw that it was modified for security reason, but I don’t know if we could add it back in specific cases, maybe tag the component as unsafe and warn the user about it.

However, Disqus does load correctly with st.html as it has allow-same-origin, but I cannot change the height dynamically from there.

One solution would be to have a height="auto" parameter, but even that is not that simple as there’s no easy way to support auto resizing iframes. The way I implement it is inspired from those two links (from the same author):


Awww, shoot. Yeah, it was disabled for security reasons - and yeah, it causes issues. We’re going to come up with a solution for this before launch - it might be a halfway measure to begin with (e.g. tagging the component as unsafe, as you suggest). Ultimately, we may end up serving components from a different port as Streamlit itself (running two webservers inside the Streamlit library) in order to allow-same-origin without the security concern that comes from serving components on the same origin.

2 Likes

Hey @synode -

I have a bit of annoying Components API news that affects your Disqus component:

  • For the upcoming components open beta launch, we’re going to remove allow-same-origin from st.html (which means your Disqus workaround will no longer work :frowning:)
  • We’re not currently implementing a “allow users to opt in to unsafe components” workaround

There are several competing goals that led to this decision:

  • First, we want to make sure that Streamlit’s iframes are properly sandboxed. This means that we can’t use the allow-same-origin sandbox flag for any iframe content that is being served by the Streamlit webserver.
  • Currently, all st.html and st.declare_component iframes are served by Streamlit webserver, which means they cannot use the allow-same-origin flag.
  • There are a number of potential solutions to this issue (an “unsafe” flag, like you suggested; running a 2nd components-only webserver from within the Streamlit process; requiring that allow-same-origin components be served from a CDN or some other server; etc). We haven’t decided which of these - if any - we like.
  • We want to release the open beta soon - probably too soon to really evaluate all the allow-same-origin solutions and think about their impacts on the rest of Streamlit - and we don’t want to half-ass a solution that we later regret.

So, I have egg on my face for speaking too soon when I said “we’re going to come up with a solution to this before launch”! Apologies for that :frowning:

(And for anyone else reading this thread but not sure what it’s all about, the MDN iframe reference page has a decent explanation of the folly of the allow-same-origin + allow-scripts iframe sandbox tokens for iframe content that’s served from the same origin as its host page.)

Tim

2 Likes

@synode, so for now are there working methods to add Disqus?

I don’t know if there’s no other working method, but so far I haven’t investigated any.

Hey @Quoc_Tran - there is currently not a working method to add Disqus, but we’re looking into ways to enable it.

1 Like

Now component is GA. what is our future plan for Disqus?

I think a solution like @tim’s could work as iframe() still has the allow-same-origin flag. I’d consist in spawning a server in a different thread which would be exposed locally only. I’ll try to investigate that this week-end, but I can’t guarantee anything for now.

Unfortunately with this method, there’s no way to auto-update the height.

Yeah, I think @synode is right - you could even serve the Disqus content from a completely different machine (doesn’t have to be in the Streamlit process).

We’re evaluating ways to have height auto-updating work even outside of st.declare_component, but yeah this doesn’t exist yet, so you currently need to hardcode an iframe’s height inside your Python script.

I am able to add Facebook Comments Plugin ( or Disqus) component to my site: https://covid19.aipert.org . The trick as Synode suggests is putting these plugins to another html page and show it through iframe() in the streamlit app. I solve the height issue by using scrolling=True.

3 Likes