Files
shiny/srcts

TypeScript build tools

All files will be described as if the working directory is the root folder of rstudio/shiny, not relative to this README.md file.

First-time setup

Shiny's TypeScript build tools use Node.js, along with yarn v2 to manage the JavaScript packages.

Installation of Node.js differs across platforms, see the official Node.js website for instructions on downloading and installing. We presume that you have Node.js installed on your machine before continuing.

Install yarn using the official instructions.

You can test that Node.js and yarn are installed properly by running the following commands:

node --version
yarn --version

Once both are installed, run the following in the root repo directory to install the packages :

# Sitting in `rstudio/shiny` repo
yarn install

Yarn v2

This repo uses Yarn v2. If you have the latest yarn installed from brew (v1.x), Yarn will pick up on the fact that this repo is a Yarn v2 (berry) repo.

For compatibility with esbuild, the ./node_modules is still maintained.

Updating Node

To avoid finding and determining which is the best node version to use, use a package called n to help facilitate installing the latest stable version of node.

npx is a command that allows you to run a package and command even if the package is not installed. It is distributed with the latest releases of node.

# Update to the latest stable node version
npx n stable

# View installed versions
npx n ls

Adding packages

If in the future you want to upgrade or add a package, run:

yarn add --dev [packagename]

This will automatically add the package to the dependencies in package.json, and it will also update the yarn.lock to reflect that change. If someone other than yourself does this, simply run yarn to update your local packages to match the new package.json.

Upgrading packages

Periodically, it's good to upgrade the packages to a recent version. There's two ways of doing this, depending on your intention:

  1. Use yarn up to upgrade all dependencies to their latest version based on the version range specified in the package.json file (the yarn.lock file will be recreated as well. Yarn packages use semantic versioning, i.e. each version is writen with a maximum of 3 dot-separated numbers such that: major.minor.patch. For example in the version 3.1.4, 3 is the major version number, 1 is the minor version number and 4 is the patch version number. Here are the most used operators (these appear before the version number):
  • ~ is for upgrades that keep the minor version the same (assuming that was specified);

  • ^ is for upgrades that keep the major version the same (more or less -- more specifically, it allow changes that do not modify the first non-zero digit in the version, either the 3 in 3.1.4 or the 4 in 0.4.2.). This is the default operator added to the package.json when you run yarn add [package-name].

  1. Use yarn up [package] to upgrade a single named package to the version specified by the latest tag (potentially upgrading the package across major versions).

  2. To see all outdated packages, run yarn outdated

Configure TypeScript

The JavaScript community likes to build many small, effective packages that do minimal work. The unfortunate side effect is needing a config file for everything.

Config files

All config files are located in the root folder to avoid opening two separate VS Code projects.

  • .browserslistrc
    • Used with browserslist and core-js to determine which polyfills should be incorporated.
  • .eslintrc.yml
    • Used with eslint and prettier to determine how the TypeScript files should be formatted and which lint failures should cause warnings, errors, or be ignored.
  • .madgerc
    • Package used to determine if circular dependencies are found. type only imports are ignored as they are not included in the final bundle.
  • .prettierrc.yml
    • Used by prettier to know how to adjust code when a file is saved in VSCode or within eslint's linting process.
  • yarnrc.yml
    • Notifies yarn to use yarn v2, install ./node_modules folder for esbuild, and any CLI plugins.
  • babel.config.json
    • Used within babel transpilation of TypeScript -> JavaScript -> polyfilled JavaScript.
    • Noteable options set:
      • "useBuiltIns": "usage" - core-js polyfills are only added as they are used.
      • "corejs": "3.9" - This number should match the installed core-js number.
      • "ignore":["node_modules/core-js"] - The core-js library is directly ignored to avoid being processed by babel.
  • jest.config.js
  • package.json
    • Contains useful scripts that can be run by yarn via yarn run SCRIPTNAME.
    • The scripts described below are inteded for developer use. All other scripts are means to an end.
      • yarn run watch - Watch srcts/src for changes and rebuild the JavaScript files.
      • yarn run build - Build shiny.js and shiny.min.js in inst/www/shared. Both files will have a corresponding sourcemap
      • yarn run lint - Fix all TypeScript lints using eslint and prettier
      • yarn run test - Run all TypeScript tests
  • tsconfig.json -
    • TypeScript config file
    • Notable options set:
      • target: ES5 - Compile to es5, so babel has an easier job.
      • preserveConstEnums: false - Do no preserve enum values into the final code. (If true, produces bloat / unused code)
      • isolatedModules: true & esModuleInterop: true - Requested by esbuild. This allows for esbuild to safely compile the files in parallel

Bundle TypeScript

esbuild is a build tool that (for Shiny's purposes) compiles the TypeScript into a single JavaScript file.

To run all build tasks, run:

yarn build

It's also useful to have esbuild watch for updated files and immediately re-build shiny.js as necessary during development. This is done with:

yarn watch

Both JavaScript files will produce a sourcemap (**.js.map) that the browser will understand. This will help you debug Shiny's JavaScript code within the browser and point back to the original TypeScript files.

GitHub Actions

On push to the master branch or push to a Pull Request to the master branch, a GitHub Action will be run to make sure the bundled JavaScript code is up to date. If the source code does not compile to the exact same file, it will be committed an pushed back to the outdated branch. (This makes it so the full build tools are not necessary for small tweaks and comments. 🎉)

Updating dependencies

@types/jquery

As of v3.5.5, @types/jquery produces a globally available constant of $ and jQuery. This is problematic as TypeScript is there to enforce that all variables are accounted for. Declaring that these two variables exist globally removes the requirement to import $ (or jQuery). This is bad for Shiny as the $ would not be enforced to the "within package" $.

To overcome this, a patch is used to remove the globally defined $ (and Symbol) variable declarations. Yarn v2 has a patch protocol that allows a local patch to be applied to the publically available @types/jquery package upon installation.

If in the future where the variables are not globally declared anymore, the patch may be removed and @types/jquery can be imported directly.

A global module plugin is used by esbuild to swap out a real jquery module to just return window.jQuery. This allows for tests and core code to behave the same way.

core-js

To update the version of core-js:

  • Check if there is a newer version available by running yarn outdated core-js. (If there's no output, then you have the latest version.)
  • Run yarn add --dev core-js --exact.

External libraries

Shiny already has a handful of html dependencies that should NOT be bundled within shiny.js. To update the dependencies below, see the directions in in tools/README.md.

  • jquery / @types/jquery
  • bootstrap / @types/bootstrap
    • Bootstrap is not being updated anymore. Only bootstrap 3.4 will be utilized within shiny.js. To use the latest bootstrap, see rstudio/bslib
  • bootstrap-datepicker / @types/bootstrap-datepicker
  • ion-rangeslider / @types/ion-rangeslider
  • selectize / @types/selectize