Skip to content
/ reaxt Public
forked from kbrw/reaxt

Use React template into your Elixir application for server rendering

License

Notifications You must be signed in to change notification settings

gluecode/reaxt

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

36 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Reaxt

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

  • An isomorphic ready library (SEO/JS are now nice together), but with Elixir on the server side
  • Just a Library, with a minimum constraint about your application organization and layout :
    • use any javascript compiled language
    • use any javascript routing logic or library
    • you can use JS React rendered component only for parts of your webpage
  • Nice fluent dev workflow, with :
    • combined stacktrace : elixir | javascript
    • hot loading on both server and browser
    • NPM/Webpack as the only config for respectively dependencies/compilation
    • A cool UI to have an overview of your compiled javascript application
    • You do not have to think about the server side Javascript configuration, just write a webpack conf for the browser, and it is ready to use.

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:

  • Add the :reaxt dependency to your project.deps and application.applications
  • Add compilers: [:reaxt_webpack] ++ Mix.compilers to your project

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

  • config :reaxt,:otp_app,:yourapp

Create the good directory and file layout:

  • MIXROOT/web
  • MIXROOT/web/package.json containing your app NPM dependencies
  • MIXROOT/web/webpack.config.js containing only the client side logic, use "reaxt/style" instead of "style" loader to load your css. A typical output path is ../priv/static.
  • MIXROOT/web/components containing modules exporting React components

In your elixir code generating HTML :

  • add WebPack.header in the <head>
  • add a script with src /your/public/path/<%= WebPack.file_of(:entry_name) %>

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"})

# if you want to use javascript to dynamically find your component and initial props
# then thefile should exports a function(arg,callback) 
# which then call callback(handler,props)
# WARNING : your dynamically loaded component must have a displayName of
#           "componentFileName.componentProperty" or "componentFileName"
Reaxt.render!(:thefile,args,dyn_handler: true)

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

  • the css <style><%= render.css %></style>
  • the html in an identified block (<div id="myblockid"><%= render.html %></div>)
  • the client side rendering call with <script><%= render.js_render %>("myblockid")</script>

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 :

  • config :reaxt,:hot,true to enable that:
    • server and client side JS will be compiled each time you change files
    • server side renderers will be restarted at each compilation
    • client browser page will be reloaded, a desktop notification will be triggered
    • The /webpack UI will be automatically reloaded if it is on your browser
  • config :reaxt,:hot,:client to enable the same hot loading, but with webpack module hot loading on browser to avoid full page reload
    • use the webpack loader react-hot-loader to load your component to enable automatic browser hot reloading of your components
    • the reaxt/style loader for your css enable hot reloading of your css

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.

Perfs and pool management

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

  • config :reaxt,:pool_size configure the number of worker running permanently
  • config :reaxt,:pool_max_overflow configure the maximum extension of the pool when query happens an it is full

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 []
  })()
}

About

Use React template into your Elixir application for server rendering

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Elixir 53.7%
  • JavaScript 46.3%