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.
npxis 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:
- Use
yarn upto upgrade all dependencies to their latest version based on the version range specified in the package.json file (theyarn.lockfile 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 version3.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 runyarn add [package-name].
-
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). -
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
browserslistandcore-jsto determine which polyfills should be incorporated.
- Used with
.eslintrc.yml- Used with
eslintandprettierto determine how the TypeScript files should be formatted and which lint failures should cause warnings, errors, or be ignored.
- Used with
.madgerc- Package used to determine if circular dependencies are found.
typeonly imports are ignored as they are not included in the final bundle.
- Package used to determine if circular dependencies are found.
.prettierrc.yml- Used by
prettierto know how to adjust code when a file is saved in VSCode or withineslint's linting process.
- Used by
yarnrc.yml- Notifies
yarnto useyarnv2, install./node_modulesfolder foresbuild, and any CLI plugins.
- Notifies
babel.config.json- Used within
babeltranspilation of TypeScript -> JavaScript -> polyfilled JavaScript. - Noteable options set:
"useBuiltIns": "usage"-core-jspolyfills are only added as they are used."corejs": "3.9"- This number should match the installedcore-jsnumber."ignore":["node_modules/core-js"]- Thecore-jslibrary is directly ignored to avoid being processed bybabel.
- Used within
jest.config.js- Used to configure
jesttesting
- Used to configure
package.json- Contains useful scripts that can be run by
yarnviayarn run SCRIPTNAME. - The scripts described below are inteded for developer use. All other scripts are means to an end.
yarn run watch- Watchsrcts/srcfor changes and rebuild the JavaScript files.yarn run build- Buildshiny.jsandshiny.min.jsininst/www/shared. Both files will have a corresponding sourcemapyarn run lint- Fix all TypeScript lints usingeslintandprettieryarn run test- Run all TypeScript tests
- Contains useful scripts that can be run by
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 byesbuild. This allows foresbuildto 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/jquerybootstrap/@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 is not being updated anymore. Only bootstrap 3.4 will be utilized within shiny.js. To use the latest bootstrap, see
bootstrap-datepicker/@types/bootstrap-datepickerion-rangeslider/@types/ion-rangesliderselectize/@types/selectize