Microservices UI Frontend with Java and ReactJS Server Side Rendering

后端 未结 2 1391
悲哀的现实
悲哀的现实 2021-02-09 15:10

My current design is to have clients connect to my (Java) Web API Gateway using a browser, the Web API Gateway will call each (Java) microservice to get their JSON data and retu

相关标签:
2条回答
  • 2021-02-09 15:34

    So, a React component needs two things: the JavaScript source code and the data.

    The JavaScript source code can be provided by a CDN.

    The data must be provided by the Microservices.

    If you don't want server side rendering, then the skeleton index.html file along with the JS files are provided by a CDN.

    If you need server side rendering (for SEO purposes, for example) then the API gateway (or another Web server) will render the components using NodeJS by requesting their source code from the CDN and their data from the microservices then return the full HTML to the browser.

    On the client side, React will continue to load other data from the right microservice as JSON using the API gateway.

    0 讨论(0)
  • 2021-02-09 15:46

    Problem

    How to aggregate ReactJS UI components during server side rendering on the Web API gateway.

    Solution

    Use a templating framework like Mustache to inject the rendered HTML output of each ReactJS component server side, then serve this HTML back to the client.

    Github repo https://github.com/damorton/dropwizardheroku-webgateway

    Server Side

    The solution I implemented on the Web API gateway first requested the JSON data from the microservice, then rendered the ReactJS component while injecting the JSON data from the microservice as Props. Once I had the fully rendered ReactJS component with data as a HTML string I used Mustache templating to inject the fully rendered ReactJS component HTML into the Mustache template, then returned this to the client.

    WebGatewayResource.java

    @GET
    @Produces(MediaType.TEXT_HTML)
    public IndexView index() throws IOException {
    
        // Get events json data from Events microservice
        ApiResponse events = getEventsJsonData();
    
        // Render the Events component and pass in props
        @SuppressWarnings("unchecked")
        List<Object> eventsProps = (List<Object>) events.getList();
        String eventsComponent = this.nashornController.renderReactJsComponent(kEventsUiComponentRenderServerFunction, eventsProps);
    
        IndexView index = new IndexView(eventsComponent);
        return index;
    }
    

    Note: Dropwizard performs alot of magic around Mustache templating so all that was needed was to create an index.mustache file and reference this when constructing the IndexView class. Returning this View to the client tells Dropwizard to render the view and return the HTML.

    index.mustache

    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8" />
    <title>Dropwizard Heroku Event Service</title>
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/react/15.5.4/react.min.js"></script>
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/react/15.5.4/react-dom.min.js"></script>
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/react/15.5.4/react-dom-server.min.js"></script>
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.24.0/babel.min.js"></script>
    <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.16.1/axios.min.js"></script>
    </head>
    <body>
      <h1>Events</h1>
      <div id="events">{{{eventsComponent}}}</div>
      <script type="text/javascript" src="assets/js/bundle.js"></script>
      <script type="text/javascript" src="assets/js/client.js"></script>
    </body>
    </html>
    

    Client side

    On the client side, to fix an issue with the client and server side rendered HTML being different due to the props for the ReactJS components not being available when the component was mounted initially, a javascript function is called when the page loads to request the JSON data from the gateway.

    client.js

    var loadEventsFromServer = function(eventsUrl) {
        axios.get(eventsUrl).then(function(res) {
            var data = res.data.list;       
            renderClientEvents(data);
        });
    };
    
    loadEventsFromServer('https://domain.webapigateway.com/events');
    

    ReactJS

    The client side HTML is not re-rendered when the component is mounted, React is aware of the already existing HTML from the server side render and only adds the event listeners for each component when it mounts. This allows React to update its components individually, and also takes advantage of server side rendering.

    0 讨论(0)
提交回复
热议问题