Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/kbrw/reaxt
Use React template into your Elixir application for server rendering
https://github.com/kbrw/reaxt
elixir javascript react server-side-rendering webpack
Last synced: 1 day ago
JSON representation
Use React template into your Elixir application for server rendering
- Host: GitHub
- URL: https://github.com/kbrw/reaxt
- Owner: kbrw
- License: mit
- Created: 2015-01-02T02:55:17.000Z (about 10 years ago)
- Default Branch: master
- Last Pushed: 2024-11-05T09:39:47.000Z (2 months ago)
- Last Synced: 2025-01-05T17:06:06.353Z (8 days ago)
- Topics: elixir, javascript, react, server-side-rendering, webpack
- Language: Elixir
- Homepage:
- Size: 365 KB
- Stars: 374
- Watchers: 13
- Forks: 38
- Open Issues: 9
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
Awesome Lists containing this project
- freaking_awesome_elixir - Elixir - React template into your Elixir application for server rendering. (Build Tools)
- fucking-awesome-elixir - reaxt - React template into your Elixir application for server rendering. (Build Tools)
- awesome-elixir - reaxt - React template into your Elixir application for server rendering. (Build Tools)
README
Reaxt
=====Use your [React](http://facebook.github.io/react/) components into your elixir application, using [webpack](http://webpack.github.io/) 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.TODO List :
- [ ] Handle Source map in server side for combined stacktrace generation
- [ ] Add Source map in client side
- [ ] Currently the compiler compile in parallel server entry and client
entries, but server side compilation does not handle *cacheable* and slow
down very much the compilation
- [ ] handle css loader for `reaxt/style` loader, currently it is ignored in
server side, which is a problem for URL remapping in CSS.## 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, (`:reaxtWebpack` for elixir < v1.0.3)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 componentsIn your elixir code generating HTML :
- add `WebPack.header` in the ``
- add a script with src `/your/public/path/<%= WebPack.file_of(:entry_name) %>`Then render your server side HTML :
```elixir
# 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 :
- the css `<%= render.css %>`
- the html in an identified block (`<%= render.html %>`)
- the client side rendering call with `<%= render.js_render %>("myblockid")`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 :```elixir
EEx.eval_string("""
<%= WebPack.header %>
<%= render.css %>
<%= render.html %>
<%= render.js_render %>("content")
""",render: Reaxt.render!(:app,%{my: "props"}))
```Finally, you have to serve files generated by webpack :
```elixir
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](https://www.npmjs.com/package/webpack-dev-server),
and a [nice UI](http://webpack.github.io/analyse/).```elixir
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## Dynamic Handler and customize rendering (useful with react-router)
See a full example in [reaxt-example](https://github.com/awetzel/reaxt-example/blob/master/web/components/my_router.js)
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!(`.- `reaxt_server_render(arg,render)` will
- take `arg` from the second argument of `Reaxt.render`,
- have to execute `render(component,param)` when the wanting handler and props
are determined. `param` is any stringifyable object passed to client rendering
- `reaxt_client_render(props,render,param)` have to render the
good selected component on the client side.
- `props` is the initial props used in server rendering,
- `render` is function you have to call to make the client react rendering
- `param` is the deserialized version of the third parameter of the callback in `reaxt_server_render`To understand how they work, let's look at the default implementation
of these functions (what happened when they are not implemented).```javascript
// 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(,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()
}
```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](https://github.com/awetzel/reaxt-example/blob/master/web/components/my_router.js)```elixir
Reaxt.render!(:router_handler,full_path(conn))
``````javascript
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()
})
},
reaxt_client_render: function(props,render){
Router.run(Routes,Router.HistoryLocation,function(Handler,state){
render()
})
}
}
```## 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')`.```elixir
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.```elixir
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 :
```javascript
require('reaxt/config').some_config1
```## 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 fullA clever configuration could be :
```elixir
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.```elixir
{
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