React16 Server Side Rendering (SSR) CSS and Images Not Loading Issues

Before looking into React16 SSR css and images related issues first check go through a Step By Step guide for implementing React16 Server Side Rendering (SSR) with Material-ui library

React16 SSR css & public images not loading issue

Since in SSR applications we configure our own http server using expressjs or any other framework, we have to configure the path for public folder and css files folder path so that http server finds the file when request comes.

To fix css and public images not loading issue which is a very common issues in react ssr applications, we have to add following below lines in our server side script

<code>//note the relative path of build folder  may change as per your project structure check those ../.. as per your project.
app.use(express.static(path.join(__dirname, '../../build'))); 
app.use(express.static(path.join(__dirname, 'public')));</code>

if above two lines are not added in your server side script then you may face following common issues.

  1. Bootstrap/jquery css files are not getting included after running npm run build and running the app
  2. images referred from public folder will not be loaded

ComponentDidMount not getting called in React SSR application

Another very common problem in react ssr applications is once we enable server side rendering client side rendering will stop happening. Since client side rendering doesn’t happen componentDidMount will not be fired some times.

React run build generates lots of javascript files under build/static/js folder, if these files are not served by our server side script when browser requests those files then client side rendering fails. when we generate build using npm run build, react-scripts refers those static js files in index.html file. When page is loaded browser requests for those js files but our server side script fails to serve those files.

again to solve this issue the above two lines code is important especially,

<code>//note the relative path of build folder  may change as per your project structure check those ../.. as per your project.
app.use(express.static(path.join(__dirname, '../../build')));</code>

COVID-19 : corona virus epidemic, What one can do to stop it?

The world has hit badly by an invisible tiny virus who is shaking the entire scientific, medical community and challenging to save the lives. Corona virus is not that critical if every one takes some simple precautions but as usual we did mistakes, we neglected and hence paying for it and struggling to escape from it.

Coronavirus is spreading very fast, its an exponential way, person to person through different medium and hence an extreme precautions has to be taken to stop it

Social Distancing:

A simple technique can save our life and save your family, social distancing. Virus can spread through person to person when a infected person cough, spit, sneezes.

It will also spread through some surfaces when an infected person touch any metal surface, cardboard, plastic the virus can survive several hours on the surface and some one else touch the same surface it will transfer to his body.

Look at the below animated view which helps us to understand how social distancing helps us to stop coronavirus spread drastically

Is’t it a simple solution ? but we are failing follow.

“By our most conservative estimate, at least 59% of the infected individuals were out and about, without being tested and potentially infecting others,” says lead study author Prof. Wu Tangchun. Reference

What you should not do ?

Avoid

  1. Parties, functions
  2. Smoking
  3. Avoid taking tablets on your own for fever , cold or headache.
  4. touching your eyes, nose and mouth without washing it properly with soap and water or sanitisers

Social Warriors and NGOs working for Covid-19

There are lot of NGOs, social warriors working for coronavirus epidemic to stop it, lot of awareness programs running for COVID-19, lot of donations are being raised by many organisations to help the needy people in this lockdown situation almost everywhere in the world

Awareness Programs Run by SociallyGood Platform through some of the organisations

Awareness Campaign For Pandemic COVID-19

Awareness program by Sewa USA :

Coronavirus-(COVID-19) Awareness Program

Donate for Covid-19 epidemic

Donation Campaigns run by SociallyGood Platform through some of the organisations

Groceries to daily wage workers in view of outbreak of COVID-19

Support to Fight COVID-19

know more about COVID-19 through SociallyGood Platform

COVID-19 Campaigns on SociallyGood Platform

Let us stop Coronavirus by following the protocol

  1. Lockdown : Be at home, do not go out without the real need
  2. Social Distancing: Keep distance between people
  3. Be wise not panic
  4. Improve your health by doing simple physical work like yoga

COVID-19 Information Center on Facebook

Amazon AWS RDS Failed to Connect to MySQL at with user using MySql Workbench

When trying to connect to Amazon AWS RDS from local machine using MySql Workbench , if you face connection issue like error: Failed to Connect to MySQL at with user Kindly follow below steps

Follow setting up security group : Refer

Then set public access try by following these steps

To change the Publicly Accessible property of the Amazon RDS instance to Yes:

1.    Verify that your VPC has an internet gateway attached to it and that the inbound rules for the security group allow connections.

2.    Open the Amazon RDS console.

3.    Choose Databases from the navigation pane, and then select the DB instance.

4.    Choose Modify.

5.    Under Network & Security, choose Yes for Public accessibility.

6.    Choose Continue.

7.    Choose Modify DB Instance.

DB Import Error due to Triggers :

ERROR 1419 (HY000) at line 918: You do not have the SUPER privilege and binary logging is enabled (you might want to use the less safe log_bin_trust_function_creators variable)

To fix this issue follow steps

  1. Open the RDS web console.
  2. Open the “Parameter Groups” tab.
  3. Create a new Parameter Group. On the dialog, select the MySQL family compatible to your MySQL database version, give it a name and confirm. Select the just created Parameter Group and issue “Edit Parameters”.
  4. Look for the parameter ‘log_bin_trust_function_creators’ and set its value to ’1′.
  5. Save the changes.
  6. Open the “Instances” tab. Expand your MySQL instance and issue the “Instance Action” named “Modify”.
  7. Select the just created Parameter Group and enable “Apply Immediately”
  8. Click on “Continue” and confirm the changes.
  9. Wait for the “Modifying” operation to be completed.
  10. Again, open the “Instances” tab. Expand your MySQL instance and
  11. expand “Instance Action” tab and select “Reboot”.

Factory Design Pattern : A Creational Design Pattern

Factory design patterns provides an interface to create an object. Object creation is not just allocating some memory, in a complex systems the object creation will be a complex process. Setting certain defaults, following certain steps and initialisation of an object many more aspects will be taken care.

Let us take an example to understand it better, when we handle payment gateway transactions, a transaction object is not a simple object, it has much more complexities. It may be handling specific details for Master cards, Visa cards, or it may be related to income tax etc.

There are multiple ways of handling factory design patter, Factory Method pattern and Abstract Factory class are two different approaches.

Factory Method Pattern

Without a design pattern the code looks as fallow

<code>processPayment() {
  switch(paymentGateway) {
    case 'RazorPay': 
       transaction = new RazorPayTransaction();
    break;
    case 'Paypal': 
       transaction = new PaypalTransaction();
    break; 
    case 'Paypal': 
       transaction = new StripeTransaction();
    break; 
  }
}</code>

However the above code looks more cleaner when we apply design pattern the code looks as fallow

<code>createRazorPayTransaction() {
  transaction = new RazorPayTransaction();
  return transaction;
}
createPaypalTransaction() {
  transaction = new PaypalTransaction();
  return transaction;
}
createTransactionFactory(paymentGateway) {
  switch(paymentGateway) {
    case 'RazorPay': 
       createRazorPayTransaction();
    break;
    case 'Paypal': 
       createPaypalTransaction();
    break; 
    case 'Paypal': 
    break; 
  }
}
processPayment() {
  transaction = createTransactionFactory('RazorPay');
}</code>

the above code looks simple and we may not understand the significance of it with a small scale application. However the creational design pattern brings in lot of flexibility, like any complexity with respect to a particular payment gateway will be handled with respective creation method.

for example if I try to elaborate little about one particular method it may looks as below, and this shows how a particular method becomes complex while considering various cases.

<code>createPaypalTransaction() {
  transaction = new PaypalTransaction();
   if (cardType === 'Master') {
     if (country === 'India') {
        if (cardKind === 'Chip') {

        }
      }
    }
  return transaction;
}</code>

Abstract Factory Pattern

Abstract factory pattern simplifies and makes the pattern into more object oriented and enforces future extendability to follow certain strict guidelines by defining interfaces.

Taking an example of developing a super software to handle a robotic machines. There are various types of robotic machines like marine explorer, space explorer and terrain explorer. Its great to have abstract class which enforces and defines basic structure of the factory class. Let us see how does it look

<code>abstract class RoboticMachineFactory {
  createCrawlingRobot();
  createRunningRobot();
  createFlyingRobot();
}

class SpaceExplorerRobotFactory extends RoboticMachineFactory {
  createCrawlingRobot();
  createRunningRobot();
  createFlyingRobot();
}

class TerrainExplorerRobotFactory extends RoboticMachineFactory {
  createCrawlingRobot();
  createRunningRobot();
  createFlyingRobot();
}

class MarineExplorerRobotFactory extends RoboticMachineFactory {
  createCrawlingRobot();
}</code>

Read Classification of Design Patterns

Classification of design patterns : Creational Design Patterns

Before reading further , let us first understand what are design patterns read part 1 of this article

Creational Design Pattern

Object creation is a very common pattern we need to use almost for all complex objects. Object creation is not just allocating a memory and use it, we may need to consider lot of aspects while creating an object.

Creational design pattern solves this problem by following a sophisticated approach, typically creational design patterns will be used for initialising hardware configuration, database connections , Logger object.

Creational design patterns are important to use because they follow SOLID Principles closely. It allows long term flexibility, it allows more decoupling and easily testable.

Let us look into some of the important creational design patterns

Singleton Pattern

We have to identify a scenario where we may need to maintain only one object, even if you try to create an object, the program should not allow to create new object instead it has to return only one object.

Singleton pattern is meaningful where multiple objects doesn’t make any sense. Taking few scenarios here for example , DBConnectionHandler, MQManager for managing Queue connections, these are classical examples where having multiple objects has no meaning.

Example of Singleton Pattern in Javascript

<code>class MQManager {
  constructor() {
    this.amqpProducerConn = null;
    this.amqpConsumerConn = null;
    this.producerChannel = null;
    this.consumerChannel = null;
  }
  createProducerConnection(onConnectSuccess, onConnectFail) {
  }

  createConsumerConnection(onConnectSuccess, onConnectFail) {
  }
  createProducerChannel(connection) {}
  createConsumerChannel() {}
  enqueueJob(queueName, jobDetails) {}
  dequeueJob(queueName, consumerCallback) {}
  closeProducerConnectionOnErr(err) {}
  closeConsumerConnectionOnErr(err) {}
};
module.exports = (() => {
  let instance;
  function getInstance() {
    //TO RESTRICT CREATING SINGLE OBJECT 
    if (instance === undefined) {
      instance = new MQManager();
    }
    return instance;
  }
  // Public API definition
  return {
    getInstance
  };
})();</code>

The above class we can import as follows

<code>const MQManager = require('./mqManager').getInstance();</code>

Read More About Creational Design Pattern

Thanks to refactoring.guru for wonderful images - https://refactoring.guru/design-patterns/

Design Patterns – importance and Examples

What are design pattern?

design patterns are typical solutions to common problems a developer face repeatedly

Design Patterns Classification 

Creational Pattern

These patterns provides various objects creation mechanism. Which increase flexibility and reuse of existing code

Structural Pattern

These patterns explain how to assemble objects and classes into larger structure, while keeping these structures flexible and efficient

Behavioral Pattern

These patterns are concerned with algorithms and assignment or responsibilities between objects

Design patterns are the best practices adapted by experienced software developers, with a vast experience, we developers will find a best way to solve a problem which we face almost every day. The outcome of such solution we usually call it as design patterns

Let us look into some of the design patterns: Read Here

Thanks to refactoring.guru for wonderful images - https://refactoring.guru/design-patterns/

Server Side Rendering (SSR) in React 16 with create-react-app using Material Ui, Redux and Express Libraries

What is Server Side Rendering in React (SSR)?

Server side rendering is normally rendering the requested page at server side of client and sending back the whole html page from server.
i.e: Server-side rendering is all about handling the initial render whenever a request hits the server. For more on basics of SSR please read my first article

Let us see how to implement server side rendering in ReactJs

How to Enable Server Side Rendering using React and ExpressJS

Dependencies:

React: 16.7.0
Material Ui Library from Google: v3.9.3
redux: 4.0.1
redux-thunk: 4.0.1
express: 4.17.1
react-jss: 8.6.1
react-router-dom: 4.3.1
react-document-meta: 2.1.2
axios: 0.19.0
@babel/plugin-proposal-class-properties: 7.4.0
@babel/preset-env: 7.4.3
@babel/register: 7.4.4
babel-preset-es2015: 6.24.1

Step1: Create React Application
Create a react app using command create-react-app
Install the create-react-app globally on your machine with below command.

npm install -g create-react-app

Create a project by create-react-app as follows

create-react-app ssr-react-16


Step2: Install necessary npm packages for React server side rendering applicationInstall the following packages by running the following commands, if necessary please use the same version too.

npm install @material-ui/core
npm install  react-redux
npm install redux
npm install redux-thunk 
npm install express
npm install react-router-dom
npm install react-document-meta
npm install react-jss
npm install axios
npm install @babel/plugin-proposal-class-properties
npm install @babel/preset-env
npm install @babel/register
npm install babel-preset-es2015

Thats it now your app is ready with library setup

Step3: babel configs for react server side app
Create a file called .babelrc in root directory of the app and paste the below code.
Babel is a toolchain that is mainly used to convert ECMAScript 2015+ code into a backwards compatible version of JavaScript in current and older browsers or environments. For more you can read the babel doc.

{
  "presets": ["@babel/env", "@babel/preset-react"],
  "plugins": [
    "@babel/plugin-proposal-class-properties"
  ]
}

Step4:
Create a file called www under bin folder which is in root directory
In this file we will be creating a server for client and allocate a port (I am using 5000 here)
Copy the code below to file just created

const app = require('../src/client/src/ssr/clientServer');
const http = require('http');

const port = normalizePort(process.env.PORT || 5000);
app.set('port', port);

const server = http.createServer(app);
server.listen(port);

function normalizePort(val) {
  const port = parseInt(val, 10);
  if (isNaN(port)) {
    // named pipe
    return val;
  }
  if (port &gt;= 0) {
    // port number
    return port;
  }
  return false;
}

In the above code snippet, we are importing a file called clientServer.js that’s covered in the next step.

Step5: ReactJS server side script to initialise server part of client app.
Create a file clientServer.js
For better folder structure, I have organised as shown in the below screenshot where bin and src will falls under root directory. Paste the below code in clientServer file. clientServer is kind of server side script for our client application, it will initiate expressjs and configurations for server side script of client.

require("@babel/register")({
  presets: ["@babel/preset-env"]
});

const express = require('express');
const path = require('path');

const requestHandler = require('./requestHandler');
const app = express();

//static files nd build file reference
app.use(express.static(path.join(__dirname, '../../../../build')));
app.use(express.static(path.join(__dirname, 'public')));

app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'public'));

//for server side rendering
app.use(requestHandler);

// catch 404 and forward to error handler
app.use((req, res, next) =&gt; {
  const err = new Error('Notdff Found');
  err.status = 404;
  next(err);
});

module.exports = app;<b><i></i></b>


In the above code you can see a requestHandler file, which is very important file and will see there.

Step6: A request handler for ReactJS for server side rendering and invoking (calling) apis at server side
This step is very important for serving the requested page from server side.  All magic of serving the requested page is done in this script.  When client request for a page, it matches the path and determines whether is there any API call for this page and invokes api then updates HTML body for the respective response. Basically here its creating the react component at server side. Hence React component is fully ready with all the data for the first render itself. 
If there is no api call for a particular page, it just serves a just a static page 


Create a file requestHandler.js Copy the below code.

'use strict';
import React from 'react';
import { Provider } from 'react-redux';
import thunk from 'redux-thunk';
import { applyMiddleware, createStore } from 'redux';
import { renderToString } from 'react-dom/server';
import { SheetsRegistry } from 'jss';
import JssProvider from 'react-jss/lib/JssProvider';
import path from 'path'
import fs from 'fs'
import {
  MuiThemeProvider,
  createMuiTheme,
  createGenerateClassName,
} from '@material-ui/core/styles';
import green from '@material-ui/core/colors/green';
import red from '@material-ui/core/colors/red';
import { StaticRouter, matchPath } from 'react-router-dom';
import DocumentMeta from 'react-document-meta';
import reducers from '../reducers/index';
import routes from '../routes';
import routesConfigs from './routesConfig';

const middleware = applyMiddleware(thunk);

function renderView(req, res, state) {

  // Create a theme instance.
  const theme = createMuiTheme({
    palette: {
      primary: green,
      accent: red,
      type: 'light',
    },
  });

  // STEP-1 CREATE A REDUX STORE ON THE SERVER
  const store = createStore(reducers, state, middleware);
  const sheetsRegistry = new SheetsRegistry();
  // Create a sheetsManager instance.
  const sheetsManager = new Map();
  const generateClassName = createGenerateClassName();
  // STEP-2 GET INITIAL STATE FROM THE STORE
  const initialState = JSON.stringify(store.getState()).replace(/&lt;\/script/g, '&lt;\\/script').replace(/&lt;!--/g, '&lt;\\!--');
  // STEP-3 IMPLEMENT REACT-ROUTER ON THE SERVER TO INTERCEPT CLIENT REQUESTs AND DEFINE WHAT TO DO WITH THEM
  const context = {};
  const reactComponent = renderToString(
    &lt;JssProvider registry={sheetsRegistry} generateClassName={generateClassName}&gt;
      &lt;MuiThemeProvider theme={theme} sheetsManager={sheetsManager}&gt;
        &lt;Provider store={store}&gt;
          &lt;StaticRouter
            location={req.url}
            context={context}&gt;
            {routes}
          &lt;/StaticRouter&gt;
        &lt;/Provider&gt;
      &lt;/MuiThemeProvider&gt;
    &lt;/JssProvider&gt;
  );
  const css = sheetsRegistry.toString()
  const reactMetaComponent = DocumentMeta.renderToStaticMarkup();
  if (context.url) {
    // can use the `context.status` that
    // we added in RedirectWithStatus
    redirect(context.status, context.url);
  } else {
    //https://crypt.codemancers.com/posts/2016-09-16-react-server-side-rendering/
    //res.status(200).render('index', { reactComponent, reactMetaComponent, initialState });
    fs.readFile(path.resolve('build/index.html'), 'utf8', (err, data) =&gt; {
      if (err) {
        return res.status(500).send('An error occurred')
      }
      const replacedData = data.replace(
        '&lt;div id="root"&gt;&lt;/div&gt;',
        `&lt;div id="root"&gt;${reactComponent}&lt;/div&gt;
        &lt;style id="jss-server-side"&gt;${css}&lt;/style&gt;
        &lt;script&gt;
          window.INITIAL_STATE = ${initialState}
        &lt;/script&gt;`
      );
      const replacedMetaTagData = replacedData
        .replace(`&lt;meta id="reactMetaTags"/&gt;`,
          `${reactMetaComponent}`);
      res.send(replacedMetaTagData);
    })
  }
}

function handleRender(req, res) {
  const components = routesConfigs
    .filter(route =&gt; matchPath(req.path, route)) // filter matching paths
    .map(route =&gt; route.component); // check if components have data requirement
  let promiseObj = null;
  if (components.length &gt; 0 &amp;&amp; (components[0].fetchData instanceof Function)) {
    /* fetchData is the function defined in each component and make it like class 
       function and it will be called at server side
    */
    components[0]
      .fetchData(req.query)
      .then((response) =&gt; {
        renderView(req, res, response);
      })
      .catch((error) =&gt; {
        console.log('***--- handleRender error ', error);
        renderView(req, res, {});
      });
  } else {
    renderView(req, res, {});
  }
}

module.exports = handleRender;
  1. By default it will be executing a handleRender function in the above code. In the handleRender function, we read a routesConfig file which is just for keeping track of respective component for each route path.
    import LandingComponent from '../pages/landing/components/LandingComponent';
    import AboutComponent from '../pages/about/components/AboutComponent';
    export default [
      {
        path: "/",
        component: LandingComponent,
        exact: true,
      },
      {
        path: '/about',
        component: AboutComponent,
        exact: true,
      }
    ];
  2. routesConfigs will be used by requestHandler to find dynamically which component needs to be rendered for the request. It also checks for fetchData, if fetchData is defined by the component then requestHandler will invoke it which internally invokes api. Note here is all this is happening at server side not on the browser, component object is created in server and fetchData action will be invoked in server. You can see the brief description of fetchData and how to use this in the component in the next step.
  3. When renderView is called, every times it creates is own redux store and a material ui theme provider, thats why we follow this code(which is also mention in the above code snip). 
    const theme = createMuiTheme({
        palette: {
          primary: green,
          accent: red,
          type: 'light',
        },
      });
    
      // STEP-1 CREATE A REDUX STORE ON THE SERVER
      const store = createStore(reducers, state, middleware);
      const sheetsRegistry = new SheetsRegistry();
      // Create a sheetsManager instance.
      const sheetsManager = new Map();
      const generateClassName = createGenerateClassName();
  4. Next major step is reading a build/index.html file which you will get by running npm run build,
    Here we will be injecting the component created at server side into index.html.

    const replacedData = data.replace(
            '&lt;div id="root"&gt;&lt;/div&gt;',
            `&lt;div id="root"&gt;${reactComponent}&lt;/div&gt;
            &lt;style id="jss-server-side"&gt;${css}&lt;/style&gt;
            &lt;script&gt;
              window.INITIAL_STATE = ${initialState}
            &lt;/script&gt;`
     );

    where in index.html of public folder should compulsory has this tag

    &lt;div id="root"&gt;&lt;/div&gt;
  5. For facebook sharing, when you share the url a image and the title and description of the page has to be displayed, for that all those content has to be in the meta tag inside the head tag, hence we need to replaced meta tag with server generated meta tag code. 
    const replacedMetaTagData = replacedData
      .replace(`&lt;meta id="reactMetaTags"/&gt;`,
      `${reactMetaComponent}`);

    Where in index.html of public folder, meta tag with id is should be unchanged

    &lt;meta id="reactMetaTags"/&gt;
  6. Finally we will serve the requested page with updated meta tags and updated html for the first rendering cycle it self. 
    res.send(replacedMetaTagData);
    
    

    Step 7

  7. Every component should define an action which will be invoked from server side script, however in server side the request handler will be a generic script and we have to dynamically invoke an action at server side, to achieve that, each component has to define an action and assign action function pointer to fetchData, fetchData is a static class variable kept in component. Check the below code snippet , fetchData is defined at AboutComponent class level and a pointer to action is assigned to it.
    AboutComponent.fetchData = fetchAboutData;
    export default connect(mapStateToProps, null)(AboutComponent);
    
  8. You can refer to the fetchAboutData action in the aboutActions.js which will make the API call to some server, for testing iI am using the JSON placeholder get API which will get the list of posts as response, refer the code below 
    import axios from 'axios';
    export const fetchAboutData = (params) =&gt; {
      return new Promise((resolve, reject) =&gt; {
        const url = 'https://jsonplaceholder.typicode.com/posts';
        axios
          .get(url)
          .then(response =&gt; {
            resolve({
              about: {
                posts: response.data
              }
            });
          })
          .catch((error) =&gt; {
            console.log('Error while fetching posts from network', error);
            reject(null);
          });
      });
    }
  9. In the positive view, it goes to then block(success block) of the axios api call, you can observe that it’s not direct resolve, its resolving a reducer named about and that contain the posts as one of the key, this set up has to be same in both client side reducer as well in axios call in order to use it component (About Component), Observe the below codes, I have shown the code snips of axios call, aboutReducer to mapStateToProps in AboutComponent,
    In axios call 

    resolve({
        about: {
           posts: response.data
        }
    });

    In about reducer 

    const INITIAL_STATE = {
    posts: []
    };

    In about component

    const mapStateToProps = (state) =&gt; {
        return {
           posts:state.about.posts
        };
    }
  10. So in the render method, you can access the posts array like this.props.posts, in the return method of render function i have written one more function which will return the list of posts(only title) and it creates a html code
    getAllPosts = () =&gt; {
       const postView = this.props.posts.map(post =&gt;
       &lt;li&gt;{post.title}&lt;/li&gt;
     );
     return postView;
    }
  11. Once the html is ready, then its in the success block of the fetchData function in the handleRender function of requestHandler file , then followed by the code it calls the renderView method along with data(html) returned from the component.

Step8 :
Update the package.json start script to point to server side rendering beginning of the file, thats www under bin directory. Now server side rendering is really ready. 

  "scripts": {
    "start": "node bin.www",

Step9 : Running project:

  1. In the requestHandler file we will be pointing to index.html inside the build folder, hence we need to generate a build from react by running the command 
    npm run build
  2. Run the start command of your script by
    npm run start

        OR

    nodemon

        OR 

    node bin/www
  3. Since we are running this project on 5000 port, run http://localhost:5000 which is just a page without requesting for API, you simply see as like below
  4. I have made one more component with calling API and printing the results on screen,  run http://localhost:5000/about . I am using an open dummy api for printing list of posts,
    Ie: https://jsonplaceholder.typicode.com/posts

The output picture is shown below

An Example Source Code is in Github project Link : https://github.com/pilleanand/ssr-react16/tree/master/ssr-react-16

Common issues faced in React SSR Applications 

Posted by:

Anand S,

Software Engineer, Soczen Technologies Pvt Ltd,

Developer: https://sociallygood.com

ReactNative 0.59.8 project – unable to archive for for iOS while app store release & Validate Buttons is always grayed out

Recently we faced a very strange issue while releasing our ReactNative App to Apple App Store. We were unable to submit the app to iOS app store because we were failing to generate iOS Archive. XCode always generating Generic XCode Archive rather than iOS App Archive.

Since XCode was generating Generic XCode Archive, Validate button was always disabled ( grayed out). We were failing to proceed further to submit the app. After exploring the issue we came across an apple help page which was suggesting following fixes to be done for our app.

  1. Your archive contains header files.

If your app links against a static library, then your archive contains header files because the library probably uses a Headers build phase to export these files as shown in Figure 4. Headers build phases do not work correctly with static library targets when archiving in Xcode. Delete this phase, add a Copy Files build phase to your library, and use it to export your header files. See Copying Files While Building a Product for more information about adding a Copy File build phase to your project.

 2. Your archive contains static libraries or frameworks.

You must set “Skip Install” to YES to prevent your static libraries or framework from being added to your archive.

the second step was little easy , however the first step was a big headache, a react native app will be having lot of static libraries, in that changing all header build phase to copy files build phase is a big manual work and we will get lot of compilation errors like Redenition of MethodDescriptor in NativeModule.h kind of.

Errors we see after moving header files from headers build phase to copy files build phase

Redefinition of iOS errors

Redefinition of iOS errors

You can see a stackoverflow question on this : xcode is creating generic xcode archive instead of iOS App Archive -> SO-Question

Solution:

How to release iOS app to app store when archive is troubling in XCode v11.x.x

if you are using XCode v11.x then apple has removed Application Loader from XCode Developer tools. Now the alternative to that is Apple’s Transporter Application

Again the steps are same as given below to submit your app to app store,

Essentially, after you do the Clean Build Folder, and then Build, you find the .app file in: ~/Library/Developer/Xcode/DerivedData//Build/Products/Release-iphoneos/

Create a new folder on your desktop named Payload (this name is case-sensitive)

Copy your .app file and paste the copy in this Payload folder.

Right click the folder and choose “Compress Payload”

When you save this, do not save it with the .zip extension, but instead save it with a .ipa extension.

This is now your .ipa file for your app, and you can upload this through Xcode Transporter App

How to release iOS app to app store when archive is troubling in XCode v10.x.x

We have to follow different approach to release the app.

There is another way to upload your app build to the app store: by creating an .ipa file of your app, and uploading it through Application Loader in Xcode ( just click cmd + space in your mac machine and search Application Loader ).

I don’t remember all the resources I found that helped me figure this out, but this was one of them: How to build .ipa application for react-native-ios?

Essentially, after you do the Clean Build Folder, and then Build, you find the .app file in: ~/Library/Developer/Xcode/DerivedData//Build/Products/Release-iphoneos/

Create a new folder on your desktop named Payload (this name is case-sensitive)

Copy your .app file and paste the copy in this Payload folder.

Right click the folder and choose “Compress Payload”

When you save this, do not save it with the .zip extension, but instead save it with a .ipa extension.

This is now your .ipa file for your app, and you can upload this through Xcode Application Loader.

    NOTE: Application loader asks for app specific password , kindly refer to generate app specific password -> https://www.imore.com/how-generate-app-specific-passwords-iphone-ipad-mac

The upload process will tell you if there is anything wrong with your build, but if there is not, it will upload to the app store and you should be able to find it in App Store Connect in a few moments.

Hope this helps you and/or others!

Thanks to Matthew Hall for answering in Stackoverflow -> https://stackoverflow.com/a/57532876/526438

ReactJS Source Map : Hiding Source Code From Browser Console

When we deploy React Apps in production environment using npm run build which will generate an optimised production build. The browser shows source code of all the components when we go to Source tab in browser inspector window. In Google chrome browser in you go to Inspector window and enter cntr+p or cmd+p (in mac) you can see all components code.

To hide source code being exposed to outside world just enable GENERATE_SOURCEMAP = false in package.json file as follows

scripts: {
"build": "GENERATE_SOURCEMAP=false react-scripts build"
}

Reference: https://github.com/facebook/create-react-app/issues/4162