Home

Awesome

Reaxt

Use your React components into your elixir application, using webpack compilation, so :

TODO List :

Usage

See https://github.com/awetzel/reaxt-example for a ready to use example application, but lets look into details and requirements.

In your mix.exs, add the dependency and the custom compiler for webpack:

In your config/config.exs, link the reaxt application to the application containing the JS web app

Create the good directory and file layout:

In your elixir code generating HTML :

Then render your server side HTML :

# if web/components/thefile exports the react component
Reaxt.render!(:thefile,%{it: "is", the: "props"})

# if web/components/thefile exports an object containing a react component
# at the key "component_key"

Reaxt.render!({:thefile,:component_key},%{it: "is", the: "props"})

The function return a %{html: html,css: css,js_render: js_render}, you have to add in the html :

For example, if you want a page entirely generated by the react component exported at web/components/app.js, then in your elixir web server, send :

EEx.eval_string("""
  <html>
  <head> <%= WebPack.header %>
    <style><%= render.css %></style>
  </head>
  <body>
    <div id="content"><%= render.html %></div>
    <script src="/public/<%= WebPack.file_of(:main) %>"></script>
    <script><%= render.js_render %>("content")</script>
  </body>
  </html>
""",render: Reaxt.render!(:app,%{my: "props"}))

Finally, you have to serve files generated by webpack :

plug Plug.Static, at: "/public", from: :yourapp

Then iex -S mix and enjoy, but the best is to come.

Custom Plug : Live reloading and WebPack web UI

When you serve files generated by webpack, use the plug WebPack.Plug.Static instead of Plug.Static, it contains an elixir implementation of webpack-dev-server, and a nice UI.

  if Mix.env == :dev do 
    use Plug.Debugger
    plug WebPack.Plug.Static, at: "/public", from: :myweb
  else
    plug Plug.Static, at: "/public", from: :myweb
  end

Then go to http://yourhost/webpack to see a beautiful summary of your compiled js application.

Then configure in your application configuration :

Dynamic Handler and customize rendering (useful with react-router)

See a full example in reaxt-example

Reaxt provides facilities to easily customize the rendering process at the server and the client side : this is done by attaching reaxt_server_render and/or reaxt_client_render to the module or object referenced by the first argument of Reaxt.render!(.

To understand how they work, let's look at the default implementation of these functions (what happened when they are not implemented).

// default server rendering only take the exported module as the
// handler to render and the argument as the props
default_reaxt_server_render = function(arg,render){
  render(<this {...arg}/>,null)
}
// default client rendering only take the exported module as the
// handler to render, the param is ignored
default_reaxt_client_render = function(props,render,param){
  render(<this {...props}/>)
}

Now let's see an example usage of these functions : react-router integration (Reaxt.render second argument is the Path): See a full example in reaxt-example

Reaxt.render!(:router_handler,full_path(conn))
var App = require("./app")
var Router = require("react-router")
var Routes = require("./routes")
module.exports = {
  reaxt_server_render: function(path,render){
    Router.run(Routes, path,function (Handler, state) {
      render(<Handler/>)
    })
  },
  reaxt_client_render: function(props,render){
    Router.run(Routes,Router.HistoryLocation,function(Handler,state){
      render(<Handler {...props}/>)
    })
  }
}

Error management

JS exceptions and stacktraces during rendering are converted into Elixir one with a fake stacktrace pointing to the generated javascript file.

This is really nice because you can see javascript stacktrace in the Plug.Debugger UI on exception.

Global Configuration

You can define a term in Elixir using Application env global_config which will be available globally in the server and the client side with require('reaxt/config').

config :reaxt,:global_config, %{
  some_config1: "value1",
  some_config2: "value2"
}

This configuration is static once the :reaxt application has started. So if you want to change this configuration at runtime, you need to reload all :reaxt renderer with Reaxt.reload. Remember : this is a costly reload, do not use it to maintain a state at real time but only for configuration purpose.

Application.put_env :reaxt, :global_config, %{
  some_config1: "value3",
  some_config2: "value4"
}
Reaxt.reload

Then in your javascript component, you can use this config using :

require('reaxt/config').some_config1

Perfs and pool management

The NodeJS renderers are managed in a pool (to obtain "multicore" JS rendering), so :

A clever configuration could be :

config :reaxt,:pool_size, if(Mix.env == :dev, do: 1, else: 10)

For minification, remember that webpack compilation is launched by Mix, so you can use process.env.MIX_ENV in your webpack config.

{
  externals: { react: "React" },
  plugins: (function(){
    if(process.env.MIX_ENV == "prod") 
      return [new webpack.optimize.UglifyJsPlugin({minimize: true})]
    else
      return []
  })()
}

CONTRIBUTING

Hi, and thank you for wanting to contribute. Please refer to the centralized informations available at: https://github.com/kbrw#contributing