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

Offline support #9

Open
juba opened this issue Jun 12, 2020 · 5 comments
Open

Offline support #9

juba opened this issue Jun 12, 2020 · 5 comments
Labels
enhancement New feature or request

Comments

@juba
Copy link
Owner

juba commented Jun 12, 2020

See if there could be a way to provide offline support (ie functional widget in rmarkdown or shiny without an active Internet connection).

@juba juba added the enhancement New feature or request label Jun 12, 2020
@timelyportfolio
Copy link
Collaborator

timelyportfolio commented Jun 14, 2020

@juba Do you mean that if a user has a local stored copy of an observablehq notebook that they could use the local copy instead of an online download? Observablehq allows for download that produces a zip file that we could potentially plug in instead either with bare text/<script> tag or through a file attachment. Also, this notebook offers a ui to help a user get exactly what they want.

Or, we could set up an htmlDependency on the R side to handle local or offline with src.

It seems like we would need a mechanism here to choose local instead of online.

I'm not sure yet if this might be helpful, but htmlwidget simplification ramnathv/htmlwidgets#305 might aid in this feature.

@timelyportfolio
Copy link
Collaborator

After a little experimentation, offline will be possible unless we can get http server in R to serve .js as text/javascript. Here is the code for reference.

library(robservable)
library(htmltools)

# get temp directory
tmpd <- tempdir()
# create directory for notebook
nb <- file.path(tmpd, "notebook")
dir.create(nb)
# download notebook locally in our newly created directory
path_file <- file.path(nb,"notebook.js")
download.file(
  "https://api.observablehq.com/@jashkenas/inputs.js?v=3",
  path_file
)
# see contents of our new notebook directory
list.files(nb)

# does not work because server not configured to serve module
# Failed to load module script: The server responded with a non-JavaScript MIME type of "text/plain". Strict MIME type checking is enforced for module scripts per HTML spec.
browsable(tagList(
  htmlDependency(
    name = "notebook",
    version = "0.0.0",
    src = list(file = nb),
    all_files = TRUE
  ),
  tags$script(
"
(async () => {
  let nb = await import('./lib/notebook-0.0.0/notebook.js');
  let notebook = nb.default;
})()
"
  )
))

# also does not work because of mime type
browsable(tagList(
  htmlDependency(
    name = "notebook",
    version = "0.0.0",
    src = list(file = nb),
    all_files = TRUE
  ),
  tags$script(
    type = "module",
    "import {define} from './lib/notebook-0.0.0/notebook.js'"
  )
))

# also does not work because of mime type
browsable(tagList(
  htmlDependency(
    name = "notebook",
    version = "0.0.0",
    src = list(file = nb),
    script = "notebook.js"
  ),
  tags$script(
    type = "module",
    "import {define} from './lib/notebook-0.0.0/notebook.js'"
  )
))

# works in that no error but no way to import that I know of with script type="module"
browsable(
  tagList(
    tags$script(
      type="module",
      HTML(paste(readLines(path_file), collapse="\n"))
    )
  )
)

@timelyportfolio
Copy link
Collaborator

timelyportfolio commented Jun 14, 2020

This is a less than ideal way to make this work, but if we only expect one notebook then perhaps we could replace export default and then define becomes available on window/global.

library(robservable)
library(htmltools)

# get temp directory
tmpd <- tempdir()
# create directory for notebook
nb <- file.path(tmpd, "notebook")
dir.create(nb)
# download notebook locally in our newly created directory
path_file <- file.path(nb,"notebook.js")
download.file(
  "https://api.observablehq.com/@jashkenas/inputs.js?v=3",
  path_file
)

# since mime type seems to be blocking with module
#  try to replace export default
#  but this means we will likely face namespace issues
path_file2 <- file.path(nb,"notebook_no_export.js")
cat(
  paste(
    # replace export default
    gsub(
      x = readLines(path_file),
      pattern = "export default ",
      replacement = ""
    ), collapse="\n"
  ),
  file = path_file2
)
browsable(tagList(
  htmlDependency(
    name = "notebook",
    version = "0.0.0",
    src = list(file = nb),
    script = "notebook_no_export.js",
    all_files = TRUE
  ),
  tags$script(
    "console.log(define);"
  )
))

@juba
Copy link
Owner Author

juba commented Jun 16, 2020

Thanks for taking the time to experiment on this. You're right, the MIME type issue is a real problem here as modules are not expected to be loaded from local files. In my browser even downloading a notebook via Observable "Download code" features doesn't work outside of a local HTTP server.

Your workaround is quite clever if not ideal !

The only use case of an offline support I can think of is an rmarkdown document which would be completely self_contained, ie would work without an active Internet connection. But maybe it is a case not frequent enough to justify investing time in it or using workarounds right now ?

@juba
Copy link
Owner Author

juba commented Jun 16, 2020

Other workarounds could be :

  • Asking observable to distribute notebooks in another format in their API, in addition to ES6 modules
  • Using a bundler locally such as webpack to convert ES6 module into another format (but of course the bundler has to be installed locally)

In other words, none of these workarounds are ideal either...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants