React.js in      Rakuten Taiwan

Integration with Content Management System

Jayden Lin

Python Django Co-Creater   Jacob Kaplan-Moss  @ Pycon 2015

Hi, I'm Jayden, and I'm a much more mediocre programmer.

Yahoo! Taiwan Intern (2012~2013)

Rakuten Taiwan F2E Engineer (2014~)

Outline

  • Problem:  What a mess
  • Solution: Content Management System + React.js
  • Technical Sharing:
    • Server side rendering troubleshooting
    • Asyc loading script setting with webpack

Mess ??

"Move the section to right"

 

"Move that section down.."

 

"Switch the position of that two sections.."

 

"Then.. add a banner between them.."

 

"Add a carousel here"

CVR & RSR

Matters!

 

CVR & RSR

Matters!

 

Text

API Input

API Input

API Input

API Input

API Input

API Input

Manually Input

Manually Input

Manually Input

Manually Input

Manually Input

Manually Input

Manully Input

Exchange

Exchange

Manully Input

Manully Input

Manully Input

Manully Input

API Input

API Input

API Input

API Input

There are other more 40 channel pages...

and there is only 1 f2e engineer at the time.

Mess Up!!!

Problems that we faced...

(1) Can't respond to changes with speed

(2) Code maintenance

 

Assemble them yourself! 

Could you kindly assemble them by yourself?

Introduce CMS                             for arranging the page

(An open source WYSIWYG Editor written by PHP)

more demo about C5: https://www.youtube.com/watch?v=KEThnpJcFjc

Exchange

Manully Input

Manully Input

Manully Input

Manully Input

React Component

React Component

React

Component

React

Component

React

Component

Manually Input and API input

Why React + Webpack

It's easy for management of each component's

html markup & js , css

Architecture Overview

Node.js

Server

Markup

API

Style

API

(webpack)

CMS

 

CDN

Backend Data API

deploy js & css

request

html

script

&link

tags

request

request

deploy

combined

html

Manully Input

Manully Input

Manully Input

Manully Input

node module

node module

node module

node module

node module

ref: https://github.com/facebook/react/tree/master/examples/server-rendering

Inspired by Facebook server side rendering example

Markup API

React.renderToString()

Style API

1. Collect all components' file path 

2. write the temp entry file

3. run webpack on server site

4. deploy files to CDN

5. return <script> & <link> tags

 

(1) Unify each component's rendering code (sample code)

(2) Seperate css for each componet


var SuperFocus = require("./components/super_focus.jsx");
React.render(<SuperFocus id="super-focus" 
contentObject={window.["super-focus"].data}/>,
 document.getElementById('super-focus'));
                                        
                    
var TopBanner = require("./components/top_banner.jsx");
React.render(<TopBanner id="top-banner" 
contentObject={window.["top-banner"].data}/>,
 document.getElementById('top-banner'));
                     
                   
var HotKeywords=require("./components/hot_keywords.jsx");
React.render(<HotKeywords id="hot-keywords" 
contentObject={window.["hot-keywords"].data}/>, 
document.getElementById('hot-keywords'));

                   
require("./components/super_focus.css"); 
var SuperFocus = require("./components/super_focus.jsx");

                    
require("./components/top_banner.css");                     
var TopBanner = require("./components/top_banner.jsx");
                     

require("./components/hot_keywords.css");                   
var HotKeywords=require("./components/hot_keywords.jsx");

                   

Pros

1. Composability.

2. Response to changes with speed.

(no need programmers)

3. Easy for optimization and refactoring

Cons

1. Interactions between components is hard to be implemented.

 

2.  BE CAREFUL for developing components without messy dependencies.

Technical Sharing

1. Server side rendering troubleshooting

 

2. Asyc loading script setting with webpack

 

Libraries that use dom or window...

Issue: 

Solution: 

var jsdom = require("jsdom").jsdom;
global.document = jsdom("hello world");
global.window = document.parentWindow;
var swiper = require("swiper");

1. Use jsdom

2. put them into compontDidMount

renderToString doesn't wait asyc API call

Issue: 

Solution: 

 var TopBanner = require("./components/top_banner.jsx");
 React.render(<TopBanner id="top-banner" contentObject={window.data}/>,
 document.getElementById('top-banner'));
<script>
window.data={ ... }
</script>
<div id="top-banner"> <img src="..."/> </div> 

Webpack require("xxx.css") breaks the server side rendering

Issue: 

Solution: 

require("./components/top_banner.css"); 
var TopBanner = require("./components/top_banner.jsx");
 React.render(<TopBanner id="top-banner" contentObject={window.data}/>,
 document.getElementById('top-banner'));

Aync loading script with webpack setting


{
    entry: { a: "./a", b: "./b" },
    output: { filename: "[name].js" },
    plugins: [ new webpack.optimize.CommonsChunkPlugin("init.js") ]
}

                   

webpack.optimize.CommonsChunkPlugin

&

aync 

<script src="init.js"/>
<script src="a.js" asyc/>
<script src="b.js" asyc/>

                   
/*sample code*/ 
var ready=function(fn) {
  if (document.readyState != 'loading'){
    fn();
  } else if (document.addEventListener) {
    document.addEventListener('DOMContentLoaded', fn);
  } else {
    document.attachEvent('onreadystatechange', function() {
      if (document.readyState != 'loading')
        fn();
    });
  }
}
ready(function(){
    [
        'init.js', 
        'a.js',
        'b.js'
    ].forEach(function(src,index)
    {  
       var script = document.createElement('script'); 
       if(index===0){
          script.async=false; 
       }
       script.src = src; 
       document.body.appendChild(script); 
    );
});

webpack.optimize.CommonsChunkPlugin

 

/*callback hell*/
var React=require("react");
require("./chucks/view0.jsx")(React,function(){
    require("./chucks/view1.jsx")(React,function(){
        require("./chucks/view2.jsx")(React,function(){
            require("./chucks/view3.jsx")(React,function(){
                require("./chucks/view4.jsx")(React,function(){
                    require("./chucks/view5.jsx")(Reactfunction(){
                        require("./chucks/view6.jsx")(React,function(){
            
                        });
                    });
                });
            });      
        });       
   });                    
});
             
                   

require.ensure

One more thing...

Q&A

 var TopBanner = require("./components/top_banner.jsx");
 React.render(<TopBanner id="top-banner" contentObject={window.data}/>,
 document.getElementById('top-banner'));
<script>
window.data={ ... }
</script>
<div id="top-banner"> <img src="..."/> </div> 

Issue 1: Better way to put the server values to client ?

Issue 2: Duplicated React key 

 WE ARE HIRING!!

Node.js & React.js

Jenkins + Docker + Mocha

 

 

Made with Slides.com