Title: | A Framework for Enterprise Shiny Applications |
---|---|
Description: | A framework that supports creating and extending enterprise Shiny applications using best practices. |
Authors: | Kamil Żyła [aut, cre], Jakub Nowicki [aut], Leszek Siemiński [aut], Marek Rogala [aut], Recle Vibal [aut], Tymoteusz Makowski [aut], Rodrigo Basa [aut], Eduardo Almeida [ctb], Appsilon Sp. z o.o. [cph] |
Maintainer: | Kamil Żyła <[email protected]> |
License: | LGPL-3 |
Version: | 1.10.1 |
Built: | 2024-11-20 06:55:41 UTC |
Source: | CRAN |
The entrypoint for a Rhino application.
Your app.R
should contain nothing but a call to rhino::app()
.
app()
app()
This function is a wrapper around shiny::shinyApp()
.
It reads rhino.yml
and performs some configuration steps (logger, static files, box modules).
You can run a Rhino application in typical fashion using shiny::runApp()
.
Rhino will load the app/main.R
file as a box module (box::use(app/main)
).
It should export two functions which take a single id
argument -
the ui
and server
of your top-level Shiny module.
An object representing the app (can be passed to shiny::runApp()
).
It is possible to specify a different way to load your application
using the legacy_entrypoint
option in rhino.yml
:
app_dir
: Rhino will run the app using shiny::shinyAppDir("app")
.
source
: Rhino will source("app/main.R")
.
This file should define the top-level ui
and server
objects to be passed to shinyApp()
.
box_top_level
: Rhino will load app/main.R
as a box module (as it does by default),
but the exported ui
and server
objects will be considered as top-level.
The legacy_entrypoint
setting is useful when migrating an existing Shiny application to Rhino.
It is recommended to transform your application step by step:
With app_dir
you should be able to run your application right away
(just put the files in the app
directory).
With source
setting your application structure must be brought closer to Rhino,
but you can still use library()
and source()
functions.
With box_top_level
you can be confident that the whole app is properly modularized,
as box modules can only load other box modules (library()
and source()
won't work).
The last step is to remove the legacy_entrypoint
setting completely.
Compared to box_top_level
you'll need to make your top-level ui
and server
into a Shiny module
(functions taking a single id
argument).
## Not run: # Your `app.R` should contain nothing but this single call: rhino::app() ## End(Not run)
## Not run: # Your `app.R` should contain nothing but this single call: rhino::app() ## End(Not run)
Builds the app/js/index.js
file into app/static/js/app.min.js
.
The code is transformed and bundled
using Babel and webpack,
so the latest JavaScript features can be used
(including ECMAScript 2015 aka ES6 and newer standards).
Requires Node.js to be available on the system.
build_js(watch = FALSE)
build_js(watch = FALSE)
watch |
Keep the process running and rebuilding JS whenever source files change. |
Functions/objects defined in the global scope do not automatically become window
properties,
so the following JS code:
function sayHello() { alert('Hello!'); }
won't work as expected if used in R like this:
tags$button("Hello!", onclick = 'sayHello()');
Instead you should explicitly export functions:
export function sayHello() { alert('Hello!'); }
and access them via the global App
object:
tags$button("Hello!", onclick = "App.sayHello()")
None. This function is called for side effects.
if (interactive()) { # Build the `app/js/index.js` file into `app/static/js/app.min.js`. build_js() }
if (interactive()) { # Build the `app/js/index.js` file into `app/static/js/app.min.js`. build_js() }
Builds the app/styles/main.scss
file into app/static/css/app.min.css
.
build_sass(watch = FALSE)
build_sass(watch = FALSE)
watch |
Keep the process running and rebuilding Sass whenever source files change.
Only supported for |
The build method can be configured using the sass
option in rhino.yml
:
node
: Use Dart Sass
(requires Node.js to be available on the system).
r
: Use the {sass}
R package.
It is recommended to use Dart Sass which is the primary,
actively developed implementation of Sass.
On systems without Node.js you can use the {sass}
R package as a fallback.
It is not advised however, as it uses the deprecated
LibSass implementation.
None. This function is called for side effects.
if (interactive()) { # Build the `app/styles/main.scss` file into `app/static/css/app.min.css`. build_sass() }
if (interactive()) { # Build the `app/styles/main.scss` file into `app/static/css/app.min.css`. build_sass() }
Install, remove or update the R package dependencies of your Rhino project.
pkg_install(packages) pkg_remove(packages)
pkg_install(packages) pkg_remove(packages)
packages |
Character vector of package names. |
Use pkg_install()
to install or update a package to the latest version.
Use pkg_remove()
to remove a package.
These functions will install or remove packages from the local {renv}
library,
and update the dependencies.R
and renv.lock
files accordingly, all in one step.
The underlying {renv}
functions can still be called directly for advanced use cases.
See the Explanation: Renv configuration
to learn about the details of the setup used by Rhino.
None. This functions are called for side effects.
## Not run: # Install dplyr rhino::pkg_install("dplyr") # Update shiny to the latest version rhino::pkg_install("shiny") # Install a specific version of shiny rhino::pkg_install("[email protected]") # Install shiny.i18n package from GitHub rhino::pkg_install("Appsilon/shiny.i18n") # Install Biobase package from Bioconductor rhino::pkg_install("bioc::Biobase") # Install shiny from local source rhino::pkg_install("~/path/to/shiny") # Remove dplyr rhino::pkg_remove("dplyr") ## End(Not run)
## Not run: # Install dplyr rhino::pkg_install("dplyr") # Update shiny to the latest version rhino::pkg_install("shiny") # Install a specific version of shiny rhino::pkg_install("[email protected]") # Install shiny.i18n package from GitHub rhino::pkg_install("Appsilon/shiny.i18n") # Install Biobase package from Bioconductor rhino::pkg_install("bioc::Biobase") # Install shiny from local source rhino::pkg_install("~/path/to/shiny") # Remove dplyr rhino::pkg_remove("dplyr") ## End(Not run)
Prints information which can be useful for diagnosing issues with Rhino.
diagnostics()
diagnostics()
None. This function is called for side effects.
if (interactive()) { # Print diagnostic information. diagnostics() }
if (interactive()) { # Print diagnostic information. diagnostics() }
Runs prettier on JavaScript files in app/js
directory.
Requires Node.js installed.
format_js(fix = TRUE)
format_js(fix = TRUE)
fix |
If |
You can prevent prettier from formatting a given chunk of your code by adding a special comment:
// prettier-ignore
Read more about ignoring code.
None. This function is called for side effects.
Uses the {styler}
and {box.linters}
packages to automatically format R sources. As with
styler
, carefully examine the results after running this function.
format_r(paths, exclude_files = NULL)
format_r(paths, exclude_files = NULL)
paths |
Character vector of files and directories to format. |
exclude_files |
Character vector with regular expressions of files that should be excluded from styling. |
The code is formatted according to the styler::tidyverse_style
guide with one adjustment:
spacing around math operators is not modified to avoid conflicts with box::use()
statements.
If available, box::use()
calls are reformatted by styling functions provided by
{box.linters}
. These include:
Separating box::use()
calls for packages and local modules
Alphabetically sorting packages, modules, and functions.
Adding trailing commas
box.linters::style_*
functions require the treesitter
and treesitter.r
packages. These, in
turn, require R >= 4.3.0. format_r()
will continue to operate without these but will not
perform box::use()
call styling.
For more information on box::use()
call styling please refer to the {box.linters}
styling
functions
documentation.
None. This function is called for side effects.
if (interactive()) { # Format a single file. format_r("app/main.R") # Format all files in a directory. format_r("app/view") }
if (interactive()) { # Format a single file. format_r("app/main.R") # Format all files in a directory. format_r("app/view") }
Runs prettier on Sass (.scss) files in app/styles
directory.
Requires Node.js installed.
format_sass(fix = TRUE)
format_sass(fix = TRUE)
fix |
If |
You can prevent prettier from formatting a given chunk of your code by adding a special comment:
// prettier-ignore
Read more about ignoring code.
None. This function is called for side effects.
Generates the file structure of a Rhino application. Can be used to start a fresh project or to migrate an existing Shiny application created without Rhino.
init( dir = ".", github_actions_ci = TRUE, rhino_version = "rhino", force = FALSE )
init( dir = ".", github_actions_ci = TRUE, rhino_version = "rhino", force = FALSE )
dir |
Name of the directory to create application in. |
github_actions_ci |
Should the GitHub Actions CI be added? |
rhino_version |
When using an existing |
force |
Boolean; force initialization? By default, Rhino will refuse to initialize a project in the home directory. |
The recommended steps for migrating an existing Shiny application to Rhino:
Put all app files in the app
directory,
so that it can be run with shiny::shinyAppDir("app")
(assuming all dependencies are installed).
If you have a list of dependencies in form of library()
calls,
put them in the dependencies.R
file.
If this file does not exist, Rhino will generate it based on renv::dependencies("app")
.
If your project uses {renv}
, put renv.lock
and renv
directory in the project root.
Rhino will try to only add the necessary dependencies to your lockfile.
Run rhino::init()
in the project root.
None. This function is called for side effects.
Runs ESLint on the JavaScript sources in the app/js
directory.
Requires Node.js to be available on the system.
lint_js(fix = FALSE)
lint_js(fix = FALSE)
fix |
Automatically fix problems. |
If your JS code uses global objects defined by other JS libraries or R packages,
you'll need to let the linter know or it will complain about undefined objects.
For example, the {leaflet}
package defines a global object L
.
To access it without raising linter errors, add /* global L */
comment in your JS code.
You don't need to define Shiny
and $
as these global variables are defined by default.
If you find a particular ESLint error inapplicable to your code, you can disable a specific rule for the next line of code with a comment like:
// eslint-disable-next-line no-restricted-syntax
See the ESLint documentation for full details.
None. This function is called for side effects.
if (interactive()) { # Lint the JavaScript sources in the `app/js` directory. lint_js() }
if (interactive()) { # Lint the JavaScript sources in the `app/js` directory. lint_js() }
Uses the {lintr}
package to check all R sources in the app
and tests/testthat
directories
for style errors.
lint_r(paths = NULL)
lint_r(paths = NULL)
paths |
Character vector of directories and files to lint.
When |
The linter rules can be adjusted
in the .lintr
file.
You can set the maximum number of accepted style errors
with the legacy_max_lint_r_errors
option in rhino.yml
.
This can be useful when inheriting legacy code with multiple styling issues.
The box.linters::namespaced_function_calls()
linter requires the {treesitter}
and
{treesitter.r}
packages. These require R >= 4.3.0. lint_r()
will continue to run and skip
namespaced_function_calls()
if its dependencies are not available.
None. This function is called for side effects.
Runs Stylelint on the Sass sources in the app/styles
directory.
Requires Node.js to be available on the system.
lint_sass(fix = FALSE)
lint_sass(fix = FALSE)
fix |
Automatically fix problems. |
None. This function is called for side effects.
if (interactive()) { # Lint the Sass sources in the `app/styles` directory. lint_sass() }
if (interactive()) { # Lint the Sass sources in the `app/styles` directory. lint_sass() }
Convenient way to log messages at a desired severity level.
log
log
An object of class list
of length 7.
The log
object is a list of logging functions, in order of decreasing severity:
fatal
error
warn
success
info
debug
trace
Rhino configures logging based on settings read from the config.yml
file
in the root of your project:
rhino_log_level
: The minimum severity of messages to be logged.
rhino_log_file
: The file to save logs to. If NA
, standard error stream will be used.
The default config.yml
file uses !expr Sys.getenv()
so that log level and file can also be configured
by setting the RHINO_LOG_LEVEL
and RHINO_LOG_FILE
environment variables.
The functions re-exported by the log
object are aliases for {logger}
functions.
You can also import the package and use it directly to utilize its full capabilities.
## Not run: box::use(rhino[log]) # Messages can be formatted using glue syntax. name <- "Rhino" log$warn("Hello {name}!") log$info("{1:3} + {1:3} = {2 * (1:3)}") ## End(Not run)
## Not run: box::use(rhino[log]) # Messages can be formatted using glue syntax. name <- "Rhino" log$warn("Hello {name}!") log$info("{1:3} + {1:3} = {2 * (1:3)}") ## End(Not run)
Declare the React components defined in your app.
react_component(name)
react_component(name)
name |
The name of the component. |
There are three steps to add a React component to your Rhino application:
Define the component using JSX and register it with Rhino.registerReactComponents()
.
Declare the component in R with rhino::react_component()
.
Use the component in your application.
Please refer to the Tutorial: Use React in Rhino to learn about the details.
A function representing the component.
# Declare the component. TextBox <- react_component("TextBox") # Use the component. ui <- TextBox("Hello!", font_size = 20)
# Declare the component. TextBox <- react_component("TextBox") # Use the component. ui <- TextBox("Hello!", font_size = 20)
A dataset containing population of 5 species of rhinos.
rhinos
rhinos
A data frame with 58 rows and 3 variables:
year
rhinos population
rhinos species
Uses Cypress to run end-to-end tests
defined in the tests/cypress
directory.
Requires Node.js to be available on the system.
test_e2e(interactive = FALSE)
test_e2e(interactive = FALSE)
interactive |
Should Cypress be run in the interactive mode? |
Check out: Tutorial: Write end-to-end tests with Cypress to learn how to write end-to-end tests for your Rhino app.
If you want to write end-to-end tests with {shinytest2}
, see our
How-to: Use shinytest2
guide.
None. This function is called for side effects.
if (interactive()) { # Run the end-to-end tests in the `tests/cypress` directory. test_e2e() }
if (interactive()) { # Run the end-to-end tests in the `tests/cypress` directory. test_e2e() }
Uses the {testhat}
package to run all unit tests in tests/testthat
directory.
test_r()
test_r()
None. This function is called for side effects.
if (interactive()) { # Run all unit tests in the `tests/testthat` directory. test_r() }
if (interactive()) { # Run all unit tests in the `tests/testthat` directory. test_r() }