Skip to main content
AI in Production 2026 is now open for talk proposals.
Share insights that help teams build, scale, and maintain stronger AI systems.
items
Menu
  • About
    • Overview 
    • Join Us  
    • Community 
    • Contact 
  • Training
    • Overview 
    • Course Catalogue 
    • Public Courses 
  • Posit
    • Overview 
    • License Resale 
    • Managed Services 
    • Health Check 
  • Data Science
    • Overview 
    • Visualisation & Dashboards 
    • Open-source Data Science 
    • Data Science as a Service 
    • Gallery 
  • Engineering
    • Overview 
    • Cloud Solutions 
    • Enterprise Applications 
  • Our Work
    • Blog 
    • Case Studies 
    • R Package Validation 
    • diffify  

Developing React Applications in RStudio Workbench

Author: Sebastian Mellor

Published: June 30, 2022

tags: r, react, workbench

Introduction

RStudio Workbench provides a development environment for R, Python, and many other languages. When developing a performant web application you may progress from Shiny towards tools like Plumber. This allows you to continue development of the true application code, modelling, data processing in the language you already know, R, while providing an interface to those processes suitable for embedding in larger web-based applications.

As a Shiny developer, one popular front-end library you might already be familiar with is React. React is used in many popular {htmlwidgets} such as {reactable} and anything built with {reactR}.

React is a “A JavaScript library for building user interfaces”. It provides the coupling between your data, application state, and the HTML-based user interface. An optional extension of JavaScript called JSX allows efficient definition of React based user interface components. Another optional extension of JavaScript called TypeScript enables strict typing of your code, potentially improving the quality.

This short article covers some technical hurdles to make use of the standard Create React App workflow, this is compatible with Typescript, Redux, and other extensions.

Do you require help building a Shiny app? Would you like someone to take over the maintenance burden? If so, check out our Shiny and Dash services.

Initial Setup

We are using RStudio Workbench for our development, and VS Code Sessions within Workbench as our IDE. Some extensions will be installed by default, a few of our enabled extensions include:

  • Error Lens, for better inline error notifications
  • Git Graph, for reviewing git history
  • GitLens, for additional inline information about git history
  • RStudio Workbench, for detection of running servers

Start a new VS Code Session in RStudio Workbench

The last extension is the most important and is installed when following the RStudio Workbench installation guide.

We will assume a recent version of Node.js is installed, check with nodejs --version. We are using version 16.13.2. Open a VS Code Session in RStudio Workbench and create a new project:

npx create-react-app my-app --template typescript

The issues

Following the getting started instructions, we will enter the new project and start the development server:

cd my-app
npm start

If port 3000 is already in use, you will be prompted to use another port, allow this. Now we will use the RStudio Workbench extension to find our development server, in our case, 0.0.0.0:3001:

RStudio Workbench sidebar with running servers

When you open one of these links you will find a blank page instead of the usual spinning React logo. Inspecting the Console will identify several issues. These all stem from the URL provided by the RStudio Workbench extension. We can easily resolve all of these problems.

Initial React App errors when running behind a proxy

Issue 1 - Incorrect application root

The example template (public/index.html) uses a variable PUBLIC_URL to enable development within different environments. The favicon has an href of %PUBLIC_URL%/favicon.ico.

Our application is now privately available at https://rstudio.jumpingrivers.cloud/workbench/s/ecb2d3c9ab5a71bf18071/p/fc2c1fd4/ for us to use and test while developing it. Click on a server in the RStudio Workbench extension to open your own link.

Create a file called .env.development in the root of your project with the following contents:

PUBLIC_URL=/workbench/s/ecb2d3c9ab5a71bf18071/p/fc2c1fd4

If npm start is still running, stop it now and restart it. Refresh your application now as well. The session and process IDs will usually remain the same so you will have another blank page, but fewer console errors.

Issue 2 - Incorrect routes in Express dev server

The files you are expecting are now missing because the development server uses the new PUBLIC_URL to serve content, but RStudio Workbench is removing the subdirectories when it maps back to 0.0.0.0:3000.

We can set up a proxy to server content on both “/workbench/s/ecb2d3c9ab5a71bf18071/p/fc2c1fd4” and “/”. Create a file “./src/setupProxy.js” with the following content:

module.exports = function (app) {
  app.use((req, _, next) => {
    if (!req.url.startsWith(process.env.PUBLIC_URL))
      req.url = process.env.PUBLIC_URL + req.url;
    next();
  });
};

When you now restart the dev server npm start and refresh the browser you will finally see a spinning React logo.

Default Create React App initial view

Two errors in the console remain.

Issue 3 - Invalid manifest

By definition, a web application manifest will not be requested with any authentication cookies. This is a very easy fix.

In “public/index.html” add crossorigin="use-credentials", e.g.

    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />

becomes:

<link rel="manifest" href="%PUBLIC_URL%/manifest.json" crossorigin="use-credentials" />

Refresh your application to see the changes immediately. In some cases you may require authentication in produciton, but if not then you should only enable it in development mode. We can use the already included HtmlWebpackPlugin to conditionally include our changes:

<% if (process.env.NODE_ENV === 'development') { %>
    <!-- enable authentication in dev mode only -->
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" crossorigin="use-credentials" />
<% } else { %>
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<% } %>

Note that if you are running your production application behind a protected endpoint, such as when using RStudio Connect, you may remove the conditional statement and include credentials in all cases.

Issue 4 - WebSocket connections

Finally, you may have noticed that auto-reload is not enabled and there are network errors every ~5 seconds.

We can fix this by intercepting all WebSocket connections made from our web page. Add a script tag to the head of “public/index.html”. As with the authenticated manifest, we can embed this script only when in development mode.

<% if (process.env.NODE_ENV === 'development') { %>
<script>
  const WebSocketProxy = new Proxy(window.WebSocket, {
    construct(target, args) {
      console.log("Proxying WebSocket connection", ...args);
      let newUrl = "wss://" + window.location.host + "%PUBLIC_URL%/ws";
      const ws = new target(newUrl);
      
      // Configurable hooks
      ws.hooks = {
        beforeSend: () => null,
        beforeReceive: () => null
      };
  
      // Intercept send
      const sendProxy = new Proxy(ws.send, {
        apply(target, thisArg, args) {
          if (ws.hooks.beforeSend(args) === false) {
            return;
          }
          return target.apply(thisArg, args);
        }
      });
      ws.send = sendProxy;
  
      // Intercept events
      const addEventListenerProxy = new Proxy(ws.addEventListener, {
        apply(target, thisArg, args) {
          if (args[0] === "message" && ws.hooks.beforeReceive(args) === false) {
            return;
          }
          return target.apply(thisArg, args);
        }
      });
      ws.addEventListener = addEventListenerProxy;
  
      Object.defineProperty(ws, "onmessage", {
        set(func) {
          const onmessage = function onMessageProxy(event) {
            if (ws.hooks.beforeReceive(event) === false) {
              return;
            }
            func.call(this, event);
          };
          return addEventListenerProxy.apply(this, [
            "message",
            onmessage,
            false
          ]);
        }
      });
  
      // Save reference
      window._websockets = window._websockets || [];
      window._websockets.push(ws);
      
      return ws;
    }
  });
  
  window.WebSocket = WebSocketProxy;
</script>
<% } %>

Refresh your applications and wait to confirm that there are no WebSocket connection errors any more.

References

  • Intercept WebSockets: https://gist.github.com/Checksum/27867c20fa371014cf2a93eafb7e0204
  • Change PUBLIC_URL: https://stackoverflow.com/a/58508562
  • React development proxies: https://create-react-app.dev/docs/proxying-api-requests-in-development/
  • Authenticated manifest.json: https://stackoverflow.com/a/57184506
  • Conditional index.html: https://betterprogramming.pub/how-to-conditionally-change-index-html-in-react-de090b51fed3

Jumping Rivers Logo

Recent Posts

  • Start 2026 Ahead of the Curve: Boost Your Career with Jumping Rivers Training 
  • Should I Use Figma Design for Dashboard Prototyping? 
  • Announcing AI in Production 2026: A New Conference for AI and ML Practitioners 
  • Elevate Your Skills and Boost Your Career – Free Jumping Rivers Webinar on 20th November! 
  • Get Involved in the Data Science Community at our Free Meetups 
  • Polars and Pandas - Working with the Data-Frame 
  • Highlights from Shiny in Production (2025) 
  • Elevate Your Data Skills with Jumping Rivers Training 
  • Creating a Python Package with Poetry for Beginners Part2 
  • What's new for Python in 2025? 

Top Tags

  • R (236) 
  • Rbloggers (182) 
  • Pybloggers (89) 
  • Python (89) 
  • Shiny (63) 
  • Events (26) 
  • Training (23) 
  • Machine Learning (22) 
  • Conferences (20) 
  • Tidyverse (17) 
  • Statistics (14) 
  • Packages (13) 

Authors

  • Amieroh Abrahams 
  • Tim Brock 
  • Theo Roe 
  • Colin Gillespie 
  • Aida Gjoka 
  • Gigi Kenneth 
  • Osheen MacOscar 
  • Sebastian Mellor 
  • Keith Newman 
  • Pedro Silva 
  • Shane Halloran 
  • Russ Hyde 
  • Myles Mitchell 

Keep Updated

Like data science? R? Python? Stan? Then you’ll love the Jumping Rivers newsletter. The perks of being part of the Jumping Rivers family are:

  • Be the first to know about our latest courses and conferences.
  • Get discounts on the latest courses.
  • Read news on the latest techniques with the Jumping Rivers blog.

We keep your data secure and will never share your details. By subscribing, you agree to our privacy policy.

Follow Us

  • GitHub
  • Bluesky
  • LinkedIn
  • YouTube
  • Eventbrite

Find Us

The Catalyst Newcastle Helix Newcastle, NE4 5TG
Get directions

Contact Us

  • hello@jumpingrivers.com
  • + 44(0) 191 432 4340

Newsletter

Sign up

Events

  • North East Data Scientists Meetup
  • Leeds Data Science Meetup
  • Shiny in Production
British Assessment Bureau, UKAS Certified logo for ISO 9001 - Quality management British Assessment Bureau, UKAS Certified logo for ISO 27001 - Information security management Cyber Essentials Certified Plus badge
  • Privacy Notice
  • |
  • Booking Terms

©2016 - present. Jumping Rivers Ltd