Integrating Vapor and React, Part 2: Rendering React Bundle via a Script


This is part 2 of the Vapor and React series. In this tutorial we will show how to render the react front end in a leaf file server-side, as well as perform some cleanup to our code.

What does "Rendering React Bundle via a Script " mean?

Right now, our application works like so:

1) To see our user interface, we go to http://localhost:3000, and then 2) Our front end calls our backend (http://localhost:8080), gets the data, and returns it to our front end 3) We display the data using this.setState() react side

For some applications--this relationship between front/backend is just fine and works perfectly. However, there is 1 big, big drawback to doing it this way:

  • Search Engines and social media web scrapers (Facebook and Twitter, for example) do not run javascript. In order to dynamically set the page title and meta tags, we cannot wait on our react side to do an API call and get the info from the server--they must be set when the page initially loads. This means, if you want to share your articles on Facebook/Twitter, and have it rank in SEO, then you will have to render those on the server.

So, what does this mean for us?

In this tutorial, we will fundamentally change the way data flows in our application. We will no longer do http://localhost:3000 --> make API call to http://localhost:8080 --> return data and display in react

Now, we will do the following:
  • Go to http://localhost:8080, and render an HTML document
  • In our html, load our react bundle via a script tag
  • the react bundle will make all necessary API request and load the UI as normal

So, let's get started!

First -- Tighten Security in Cors.json

Let's make our app a bit more secure. In cors.json, change the entire contents of the file to read:

    { "allowedOrigin": "http://localhost:3000",
    "allowedMethods": ["GET"],
    "allowedHeaders": [

This does 2 things:

  • It changes the allowedOrigin to only be http://localhost:3000. This protects us from cross-domain attacks, except those coming from our own server
  • It changes the allowedMethods to accept only GET requests. If you want to allow more types of request, you can include them as you like.

Restart the server with these changes, and everything should work exactly as before.

Add Leaf to the Vapor Project

In order to render our react front end on via a script on the server, we will need a way to serve up Leaf files in our app.

In order to add the LeafProvider, add the following to the dependencies array in Package.swift:

    .package(url: "", .upToNextMajor(from: "1.1.0"))

And, then to the targets array, add LeafProvider. It should now look like:

    targets: [
        .target(name: "App", dependencies: ["Vapor", "FluentProvider", "LeafProvider"],
                exclude: [
        .target(name: "Run", dependencies: ["App"]),
        .testTarget(name: "AppTests", dependencies: ["App", "Testing"])

At this point, your entire Package.swift file should look exactly as it does here.

Then, add "view": "leaf" to your droplet.json file.

Next, at your root project directory, right click and go down to "Create Group", and then name the group "Resources". Under this group, create a new sub-group, "Views." These groups (with Yellow colored folders) will be changed to blue colored folders when we regenerate our Xcode project. To create these groups, click as in the image below:

Finally, close your Xcode project, and run $ vapor update and $ vapor xcode to update your dependencies and regenerate your Xcode project with Leaf.

Creating the Leaf File

In Config+Setup.swift, add import LeafProvider as an import statement, and then add:

    try addProvider(LeafProvider.Provider.self)
to your setupProviders() method.

Under the Views folder, create a new file, hello.leaf. Add the following as the entire contents of the file:

     <!DOCTYPE html>
      <html lang="en">
        <title>Your Site Title Here

Then, in Routes.swift, add the following route:

    get("/") { req in
            return try self.view.make("hello")

Run your server, and navigate to http://localhost:8080/, and you should see:


Great! It's using our Leaf file.

So, what does any of this have to do with the react side?

Currently, when we navigate to localhost:8080, we are simply rendering a hard-coded "Hello." What we want to do, is render our javascript bundle from React. To do so, just replace the Hello with the following:

    <div id="root"></div>
    <script src="http://localhost:3000/static/js/bundle.js" ></script>

The above is all that should be in the body tag.

  • Note: The id in
    must correspond to the div id=xxx in your index.html in your react project. "Root" should be the default ( it is at the time of this post writing, but may change in the future)

Now, restart your server, and navigate to http://localhost:8080, and you should see:

Hello World

This should be the exact same as if you went to http://localhost:3000, because we are simply loading the bundle and inserting it into the DOM.

Great job, we have successfully rendered our react as a script server side! In the next tutorial, we will go a bit deeper and discuss social sharing, adding more routes, and meta tags.

Enjoy this article? Consider supporting VaporForums by following us on Twitter! Get the latest Vapor articles, tutorials, and news.