Deploy a multiple quarto documents in a single project to posit connect

I am trying to figure out how I can share a _quarto.yml across several qmds and deploy those qmds separately in Connect. So if I had this file structure:

.
├── _quarto.yml
├── data
│   └── small.csv
├── qmd-connect.Rproj
├── qmd1
│   └── qmd1.qmd
└── qmd2
    └── qmd2.qmd

which is replicated here: GitHub - boshek/qmd-connect

Here if say I run quarto render locally at the top level of the project, it behaves just like I would expect. Both qmds get rendered using the shared _quarto.yml.

What, however, I am trying to do is to have qmd1.qmd and qmd2.qmd exist as separate objects in Connect as git-backed content but still be able to realize the benefit of a quarto project -- namely that _quarto.yml file. If try to create a manifest file like this for qmd1.qmd:

rsconnect::writeManifest(
  appDir = "qmd1",
  appPrimaryDoc = "qmd1.qmd", 
  quarto = quarto::quarto_path()
)

The manifest does not find data/small.csv nor does it find the _quarto.yml.

If I try to create the manifest like this:

rsconnect::writeManifest(
  appDir = ".",
  appPrimaryDoc = "qmd1/qmd1.qmd", 
  quarto = quarto::quarto_path()
)

it creates a manifest file that incorporates the _quarto.yml file but create it at the top of the directory which means I then can't create a manifest file for qmd2.qmd. Some of this can be solved by packaging code as suggested here but not everything as I don't quite see how one can create a shared _quarto.yml like that.

Can anyone recommend any strategies to fully realize quarto projects and shared ymls (which are great!) across multiple pieces of content in connect?

1 Like

Hi boshek,

Thanks for your question, and for your example. The short answer is that what you want to do isn't possible in Connect right now, but your example is an interesting use case and we'll take note of it. I'll explain in more detail below and describe what will work.

The tl;dr is that it isn't possible to deploy a monolithic Quarto project and have small parts of it poke out as individual content items in Connect; Connect's content items are self-contained.

In addition, Connect makes a few simplifying assumptions about the structure of content items that are deployed:

  • A content item deployed to Connect is a self-contained directory tree containing a set of files (as uploaded to Connect at deploy time). This isn't necessarily all the items in a directory; it could be a subset.
  • The primary render target must be at the top level of the content item's directory tree, i.e. not in a subdirectory.

In addition, for git-backed deployments:

  • One manifest.json can exist in a directory, so multiple content items from different subsets of files in the same directory can't become multiple content items from a git-backed deployment.

We describe these restrictions in the User Guide section on Structuring Content and Git Backed Content.

There are some workarounds described in the Structuring Content section that I don't think apply to your use case, unfortunately. For instance, workarounds using symlinks are incompatible with git-backed deployments (and wouldn't work for the relative paths in _quarto.yml anyway.

There are two ways I'd approach this if I were you.

If the different .qmd files need different access controls, or need to be available separately in Connect's content list, I'd use separate Quarto projects in subfolders. To access shared resources such as data.csv, I'd probably deploy the file as a pin using the pins package — that way, content can access it in the same manner locally and on the Connect server.

If all that matters is that all of the resulting documents exist at a URL somewhere on Connect, you can add an index.qmd file at the top level (it can be entirely blank). rsconnect will properly detect that the directory is a Quarto project and the whole thing can be deployed to Connect. The subdocuments will render and will be available at subpaths underneath the content item.

You can either access them by adding relative links to the index.qmd file, or by opening the content in "open solo" mode (the button highlighted below in the dashboard) and appending the relative path of the leaf document to the URL in the browser.

For example, if the dashboard URL for a document is: myorg.org is available for purchase - Sedo.com, clicking that button will navigate you to myorg.org is available for purchase - Sedo.com, and the individual rendered docs will be available at myorg.org is available for purchase - Sedo.com

I hope that at least clarifies what's going on. We'll take note of this use case when we're thinking about enhancing our Quarto and git-backed content improvements in the future.

Toph

2 Likes

Thanks @toph! The pins package could be really useful. Great suggestion. That will work great for small data like in this example. And shared R code and data can also be handled by packaging too. I think I've resolved that portion of this. Even a scss file could be handled with this pretty well i think. But I am struggling to see how this applies to _quarto.yml files.

Is there currently a way to pin _quarto.yml file that can them be accessed by individual qmds? Since it is the header, it is the first thing that is run so I don't see how to download that _quarto.yml from pins before starting to render the qmd. Is there some workaround that I am missing?

Again thanks for the response.

Ahh yes. RE: scss file, IIUC correctly pins::pin_read can't read raw files so I have to do something like this in a chunk (rather than in the header):

library(pins)
board <- board_connect()
scss_path <- pin_download(board, "test_scss")
fs::file_move(scss_path, ".")

If that's the case then I have to port around this above bit of code between documents specific to an scss.