[SOLVED] <script> isn't executed if created by react-basic-hooks

I was trying to insert a component via <script> tag but that wasn’t working. Upon reducing to the minimal testcase I found weird behavior: when a <script> tag is created from react-basic-hooks it’s never executed. From my findings on JS-related posts, inserting a <script> always executes it, so this is very weird.

Here’s a minimal example:

  1. Create index.html as
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <link rel="stylesheet" href="styles.css">
    </head>
    <body>
      <div id="root"></div>
      <script src="index.js"></script>
    </body>
    </html>
    
  2. Put this code to src/Main.purs
    module Main where
    
    import Prelude
    
    import Data.Maybe (Maybe(..))
    import Effect (Effect)
    import Effect.Exception (throw)
    import React.Basic.DOM as R
    import React.Basic.DOM.Client (createRoot, renderRoot)
    import React.Basic.Hooks (Component, component)
    import Web.DOM.NonElementParentNode (getElementById)
    import Web.HTML (window)
    import Web.HTML.HTMLDocument (toNonElementParentNode)
    import Web.HTML.Window (document)
    
    main :: Effect Unit
    main = do
      doc <- document =<< window
      root <- getElementById "root" $ toNonElementParentNode doc
      case root of
        Nothing -> throw "Could not find root."
        Just container -> do
          reactRoot <- createRoot container
          app <- myComponent
          renderRoot reactRoot (app {})
    
    myComponent :: Component {}
    myComponent =
      component "Test" \_ -> React.do
        pure $ R.script {children: [R.text "alert(1)"]}
    
  3. Build it with spago bundle-app
  4. Open index.html in a browser

Expected

An alert should pop up

Actual

No popups appear

1 Like

Actually, I just realized this doesn’t look like expected behavior and most likely a bug, so it’s best to be reported to the react-basic-hook project directly. So I created an issue there.

As found by Pete Murphy on the linked issue, it turns out to be upstream JS React bug. There is a workaround though through re-declaring script manually with botched letter case.

Solution for the example code:

module Main where

import Prelude

import Data.Maybe (Maybe(..))
import Effect (Effect)
import Effect.Exception (throw)
import Effect.Unsafe (unsafePerformEffect)
import React.Basic (JSX, element)
import React.Basic.DOM as R
import React.Basic.DOM.Client (createRoot, renderRoot)
import React.Basic.Hooks (Component, component)
import Unsafe.Coerce (unsafeCoerce)
import Web.DOM.NonElementParentNode (getElementById)
import Web.HTML (window)
import Web.HTML.HTMLDocument (toNonElementParentNode)
import Web.HTML.Window (document)

-- Creates <script> tag, but works around JS React bug that <script> doesn't get
-- executed https://github.com/facebook/react/issues/19865
rScriptEval :: forall attrs. Record attrs -> JSX
rScriptEval = element (unsafeCoerce (unsafePerformEffect (R.unsafeCreateDOMComponent "sCript")))

main :: Effect Unit
main = do
  doc <- document =<< window
  root <- getElementById "root" $ toNonElementParentNode doc
  case root of
    Nothing -> throw "Could not find root."
    Just container -> do
      reactRoot <- createRoot container
      app <- myComponent
      renderRoot reactRoot (app {})

myComponent :: Component {}
myComponent =
  component "Test" \_ -> React.do
    pure $ rScriptEval {children: [R.text "alert(1)"]}

2 Likes