Server Side React with PostgreSQL

Reactjs It is nice. We are already running the services we have written with React.

Well, I think Server Side Rendering is one of Reactjs' selling. There are already those who are running in various languages. An example:

But wait a moment. If rendering on the server side you do not have to let the App server do it separately. Rather, if you let the database holding the data do it, it will be faster as there is no data movement.

So I tried implementing Server Side Rendering on PostgreSQL.

PL / v 8

To move the JavaScript in PostgreSQL is PL/v8 _ use. PL / v 8 is an extension to run the v8 JavaScript engine as it is on PostgreSQL. It seems to be usable even on Amazon RDS.

Preparation

1. Installing PL / v 8

It seems that PL / v 8 can be used if it is after 9.3.5 on Amazon RDS, but this time I prepared it in Ubuntu. postgresql-9.4-plv8 the is OK if the apt-get.

$ sudo apt-get install postgresql-9.4 postgresql-9.4 postgresql-9.4-plv8 postgresql-client-9.4

(createdbとかいろいろしてDBを作って下さい)

$ psql -c 'CREATE EXTENSION plv8'  # plv8拡張をインストールします

Now you can use plv8. (By the way ansible of postgresql_ext use the module and management Hakadori)

2. Read Reactjs in PL / v 8

To load external JavaScript in PL / v 8, do as follows. First, download Reactjs and execute the following SQL.

\set reactjs `cat react-0.13.2.js`

CREATE TABLE plv8_modules(modname text primary key, load_on_start boolean, code text);

INSERT INTO plv8_modules values ('reactjs', true, :'reactjs');

CREATE OR REPLACE FUNCTION plv8_startup()
RETURNS void
LANGUAGE plv8
AS
$$
load_module = function(modname)
{
    var rows = plv8.execute("SELECT code from plv8_modules " +
                            " where modname = $1", [modname]);
    for (var r = 0; r < rows.length; r++)
    {
        var code = rows[r].code;
        eval("(function() { " + code + "})")();
    }
};
$$;

plv8_modules to table that, in advance put the path of the required modules, plv8_startup() to eval load the module from this table in the function called, and that.

We are ready at this point.

Try it.

1. Write an application

First, write the application. Because it is a sample, it's easy.

/** @jsx React.DOM */
var Name = React.createClass({
    render: function() {
        return (
            <b>{ this.props.name }</b>
        );
    }
});

var Hello = React.createClass({
    render: function() {
        return (
            <td>Hello <Name name={ this.props.name } /></td>
        );
    }
});

This in jsx app.js leave writes to a file called.

$ jsx --harmony hello.jsx > app.js

Then load this app.js.

-- read app.js
\set appjs `cat app.js`
INSERT INTO plv8_modules values ('appjs',true,:'appjs');

Preparation is complete.

2. Create JS call function

Please write something like this. plv8_module of table appjs read the code from, and eval.

-- Function itself
CREATE OR REPLACE FUNCTION name_render(n text) RETURNS text
LANGUAGE plv8
AS
$$
load_module("reactjs");

var rows = plv8.execute("SELECT code from plv8_modules where modname = $1", ["appjs"]);
eval(rows[0].code);

var e = React.createElement(Hello, {name: n});
return React.renderToString(e);
$$;

In addition, it seems that v8 itself does not have a mechanism such as require or module, so I had a lot of difficulties. There may be better ways.

3. I actually call it

Let's actually call it.

test=# select plv8_startup();  -- 事前にload_module関数とかを読み込んでおく必要があります
test=# select name_render('world');
                                                                            name_render
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
 <td data-reactid=".1lf0zu1tg5c" data-react-checksum="-1307760157"><span data-reactid=".1lf0zu1tg5c.0">Hello </span><b data-reactid=".1lf0zu1tg5c.1">world</b></td>
(1 行)

HTML came out well.

It's an ordinary SQL function, so you can use whatever you want. unnest on whether Let's output to the expansion of the array in a row.

shirou=# select name_render(n) from unnest(ARRAY['shirou', 'rudi', 'tsukinowa']) as n;
                                                                            name_render
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
 <td data-reactid=".delxp6jitc" data-react-checksum="-896062726"><span data-reactid=".delxp6jitc.0">Hello </span><b data-reactid=".delxp6jitc.1">shirou</b></td>
 <td data-reactid=".1yy26e8ifpc" data-react-checksum="-2021250693"><span data-reactid=".1yy26e8ifpc.0">Hello </span><b data-reactid=".1yy26e8ifpc.1">rudi</b></td>
 <td data-reactid=".y9snhgvrb4" data-react-checksum="1022766062"><span data-reactid=".y9snhgvrb4.0">Hello </span><b data-reactid=".y9snhgvrb4.1">tsukinowa</b></td>
(3 行)

Somewhat reactid and others are noisy, but it is being output properly.

After that, it is the dimension that it will be rendered if you give it back to the browser side as it is.

Summary

  • I tried server side rendering of Reactjs with PostgreSQL
  • PLv 8 OK
  • I can not assume the responsibility for the results of actual battle