Skip to content

Commit 6ce3204

Browse files
pinin4fjordsclaude
andcommitted
Flag Dockerfile workarounds as TEMPORARY and trim verbosity
The Dockerfiles in this repo are meant to be readable as teaching material. Shorten the renderValue-patch and CMD comments to match the density of the other branches' Dockerfiles, and prefix each fix with TEMPORARY: linking the upstream shinyngs PR that will obsolete them. Also drop redundant library(DT) and library(plotly) from CMD — the sed patch is the primary fix for the widget race; the htmlwidget resource paths are registered lazily by Shiny when an output is rendered, no library() call required. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent ce39662 commit 6ce3204

2 files changed

Lines changed: 50 additions & 30 deletions

File tree

.seqera/Dockerfile

Lines changed: 17 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -41,21 +41,20 @@ RUN rm -rf /opt/conda/pkgs/*.lock && \
4141
&& micromamba clean --all --yes \
4242
&& rm -rf /opt/conda/pkgs/*.lock
4343

44-
# ---------------------------------------------------------------
45-
# Workaround: htmlwidgets 1.6.4's Shiny binding calls the synchronous
46-
# Shiny.renderDependencies(data.deps) before bindingDef.renderValue, so
47-
# the widget plugin <script> tag is appended but not awaited. Locally
48-
# that's a <1ms race; behind the Seqera Studios iframe/connect-client
49-
# relay it consistently loses, so e.g. $().DataTable is undefined when
50-
# the DT binding tries to initialise the table. Patch to use the
51-
# async variant and await it.
44+
# TEMPORARY: async-patch htmlwidgets 1.6.4 shinyBinding.renderValue so
45+
# widget plugins load before the binding runs. Drop once
46+
# https://github.com/pinin4fjords/shinyngs/pull/92 ships via bioconda.
5247
RUN f=/opt/conda/envs/shinyngs/lib/R/library/htmlwidgets/www/htmlwidgets.js \
53-
&& grep -q 'shinyBinding.renderValue = function(el, data)' "$f" \
54-
&& sed -i \
55-
-e 's|shinyBinding\.renderValue = function(el, data) {|shinyBinding.renderValue = async function(el, data) {|' \
56-
-e 's|Shiny\.renderDependencies(data\.deps);|await (Shiny.renderDependenciesAsync ? Shiny.renderDependenciesAsync(data.deps) : Shiny.renderDependencies(data.deps));|' \
57-
"$f" \
58-
&& grep -n 'await (Shiny.renderDependenciesAsync' "$f"
48+
&& if grep -q 'await (Shiny.renderDependenciesAsync' "$f"; then \
49+
echo "htmlwidgets.js already patched, skipping"; \
50+
elif grep -q 'shinyBinding\.renderValue = function(el, data)' "$f"; then \
51+
sed -i \
52+
-e 's|shinyBinding\.renderValue = function(el, data) {|shinyBinding.renderValue = async function(el, data) {|' \
53+
-e 's|Shiny\.renderDependencies(data\.deps);|await (Shiny.renderDependenciesAsync ? Shiny.renderDependenciesAsync(data.deps) : Shiny.renderDependencies(data.deps));|' \
54+
"$f"; \
55+
else \
56+
echo "ERROR: htmlwidgets.js renderValue pattern not found" >&2; exit 1; \
57+
fi
5958

6059
# Add connect-client version label for Platform capability tracking
6160
ARG CONNECT_CLIENT_VERSION
@@ -74,10 +73,7 @@ COPY app.R data.rds /app/
7473
# ---------------------------------------------------------------
7574
ENTRYPOINT ["/usr/bin/connect-client", "--entrypoint"]
7675

77-
# The port is set by the CONNECT_TOOL_PORT environment variable.
78-
# shinyngs must be attached before app.R is sourced (app.R calls
79-
# prepareApp() without namespacing it). DT, shinyBS, plotly, shinyjs
80-
# are also attached so their Shiny resource paths register with httpuv,
81-
# otherwise widget JS/CSS (e.g. jquery.dataTables.min.js, sbs/shinyBS.css)
82-
# 404 and tables/plots fail to render.
83-
CMD ["micromamba", "run", "-n", "shinyngs", "R", "-e", "library(shinyngs); library(DT); library(shinyBS); library(plotly); library(shinyjs); shiny::runApp('/app', host='0.0.0.0', port=as.integer(Sys.getenv('CONNECT_TOOL_PORT')))"]
76+
# Port is set by CONNECT_TOOL_PORT. library() calls are required:
77+
# shinyngs attaches prepareApp() for app.R; shinyBS/shinyjs register
78+
# their addResourcePath hooks (else sbs/shinyBS.css etc. 404).
79+
CMD ["micromamba", "run", "-n", "shinyngs", "R", "-e", "library(shinyngs); library(shinyBS); library(shinyjs); library(markdown); shiny::runApp('/app', host='0.0.0.0', port=as.integer(Sys.getenv('CONNECT_TOOL_PORT')))"]

README.md

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,16 @@ a standalone Shiny application in Seqera Platform.
1919
5. Select your compute environment
2020
6. Click **Add** then **Start**
2121

22+
### Alternative: Use Pre-built Image
23+
24+
```
25+
ghcr.io/seqeralabs/custom-studios-examples/shinyngs:latest
26+
```
27+
28+
Published automatically by `.github/workflows/build.yml` on every push to this
29+
branch. `:latest` tracks the branch head; individual builds are also tagged
30+
with the short commit SHA.
31+
2232
### Alternative: Build with Wave CLI
2333

2434
```bash
@@ -40,25 +50,39 @@ docker run --rm --platform=linux/amd64 \
4050
--entrypoint micromamba \
4151
shinyngs-studio \
4252
run -n shinyngs R -e \
43-
"shiny::runApp('/app', host='0.0.0.0', port=as.integer(Sys.getenv('CONNECT_TOOL_PORT')))"
53+
"library(shinyngs); library(shinyBS); library(shinyjs); library(markdown); shiny::runApp('/app', host='0.0.0.0', port=as.integer(Sys.getenv('CONNECT_TOOL_PORT')))"
4454
```
4555

4656
Then open http://localhost:3838.
4757

4858
## What's in the image
4959

50-
- `r-shinyngs` from Bioconda, installed into a micromamba env named `shinyngs`
60+
- `r-shinyngs` and `r-markdown` from Bioconda/conda-forge, installed into a
61+
micromamba env named `shinyngs`
5162
- `connect-client` 0.12 for Studios session bootstrapping
52-
- A baked-in RNA-seq demo app generated at build time from the bundled
53-
`SRP254919` test dataset via `shinyngs`'s `make_app_from_files.R`, producing
54-
`/app/app.R` and `/app/data.rds`
63+
- A pre-built shinyngs app for the `SRP254919` RNA-seq test dataset
64+
(`/app/app.R` + `/app/data.rds`, produced upstream with
65+
`shinyngs::make_app_from_files.R`)
66+
67+
## Temporary workarounds
68+
69+
The Dockerfile carries two small fixes flagged as `TEMPORARY:` that make
70+
standalone Shiny apps render correctly behind the Studios iframe +
71+
connect-client relay (attaching `shinyBS`/`shinyjs` so their resource paths
72+
register, and patching `htmlwidgets.js` to await plugin scripts before the
73+
widget binding runs). Both go away once
74+
[pinin4fjords/shinyngs#92](https://github.com/pinin4fjords/shinyngs/pull/92)
75+
ships via bioconda; the sed step is idempotent and will skip automatically
76+
when upstream is already async.
5577

5678
## Customising the data
5779

58-
To swap in your own dataset, replace the files under `.seqera/` with your own
59-
expression matrix, sample metadata, feature metadata, contrasts, and
60-
differential-results TSVs, then rebuild. See `shinyngs`'s
61-
`make_app_from_files.R --help` for input schema.
80+
The app is built from five TSVs/CSVs fed to `shinyngs::make_app_from_files.R`
81+
(expression matrix, sample metadata, feature metadata, contrasts,
82+
differential-results). To swap in your own dataset, regenerate `app.R` +
83+
`data.rds` on any machine with `r-shinyngs` installed and replace the files
84+
under `.seqera/`, then rebuild. See `make_app_from_files.R --help` for the
85+
full input schema.
6286

6387
## References
6488

0 commit comments

Comments
 (0)