Use your React components into your elixir application, using webpack compilation, so :
TODO List :
reaxt/style
loader, currently it is ignored inserver side, which is a problem for URL remapping in CSS.See https://github.com/awetzel/reaxt-example for a ready to use exampleapplication, but lets look into details and requirements.
In your mix.exs, add the dependency and the custom compiler for webpack:
:reaxt
dependency to your project.deps and application.applicationscompilers: [:reaxt_webpack] ++ Mix.compilers
to your project, (:reaxtWebpack
for elixir < v1.0.3)In your config/config.exs, link the reaxt application to theapplication 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 dependenciesMIXROOT/web/webpack.config.js
containing only the client sidelogic, 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 :
WebPack.header
in the <head>
/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"})
The function return a %{html: html,css: css,js_render: js_render}
, you have to add in the html :
<style><%= render.css %></style>
<div id="myblockid"><%= render.html %></div>
)<script><%= render.js_render %>("myblockid")</script>
For example, if you want a page entirely generated by the reactcomponent 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.
When you serve files generated by webpack, use the plugWebPack.Plug.Static
instead of Plug.Static
, it containsan elixir implementation ofwebpack-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 ofyour compiled js application.
Then configure in your application configuration :
config :reaxt,:hot,true
to enable that:
/webpack
UI will be automatically reloaded if it is on your browserconfig :reaxt,:hot,:client
to enable the same hot loading, butwith webpack module hot loading on browser to avoid full page reload
react-hot-loader
to load yourcomponent to enable automatic browser hot reloading of your componentsreaxt/style
loader for your css enable hot reloading of your cssSee a full example in reaxt-example
Reaxt provides facilities to easily customize the rendering process at theserver 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 firstargument of Reaxt.render!(
.
reaxt_server_render(arg,render)
will
arg
from the second argument of Reaxt.render
,render(component,param)
when the wanting handler and propsare determined. param
is any stringifyable object passed to client renderingreaxt_client_render(props,render,param)
have to render thegood 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 renderingparam
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 implementationof 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-routerintegration (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}/>)
})
}
}
JS exceptions and stacktraces during rendering are converted intoElixir 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.
You can define a term in Elixir using Application env
global_config
which will be available globally in the server andthe 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 ifyou want to change this configuration at runtime, you need to reload all:reaxt
renderer with Reaxt.reload
. Remember : this is a costly reload, donot 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
The NodeJS renderers are managed in a pool (to obtain "multicore" JS rendering), so :
config :reaxt,:pool_size
configure the number of worker running permanentlyconfig :reaxt,:pool_max_overflow
configure the maximum extension of thepool when query happens an it is fullA 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 youcan 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 []
})()
}
最近对于react基础进行了学习以后,尝试写了一个简单的todolist的增删改查的功能希望可以给大家一些帮助 首先的准备工作 使用cmder进行脚手架搭建 命令行 creact-react-app 项目名称(不可以大写不可以使用中文) 以index.js作为入口文件引入相关需要的js文件 引入react import React from "react" 组件 在react中一切都是组件