技术控

    今日:0| 主题:49390
收藏本版 (1)
最新软件应用技术尽在掌握

[其他] React on Rails

[复制链接]
Nostalgia留恋 发表于 2016-10-8 04:12:49
126 7

立即注册CoLaBug.com会员,免费获得投稿人的专业资料,享用更多功能,玩转个人品牌!

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
Reverb’s main application is a well loved Rails monolith. It serves our API and view level traffic admirably. As we’ve grown, we’ve added more interactive UI elements, and as we did we followed the Rails Way™. We decorated our behavior with jQuery and we left templating to Rails. This approach, yes even in 2016, is still a great choice for a small amount of UI interactivity, but after a couple of years we began to search for something that could help structure our javascript components which were growing in sophistication.
  During our search we had a few criteria:
  
       
  • Plays well with a largely server side rendered application   
  • Can be mounted in isolation   
  • Allows for simple unit testing   
  • Could be easily taught to developers of all levels  
  React was and is a great fit for our current application. We needed isolated components that could encapsulate complex view logic that could be injected anywhere on the page. We’ve had great success with Ember in the past for standalone applications, but React’s composability provided a better model for allowing us to grow into JS components piece by piece.
  Rails has a JavaScript problem

   We originally used react-rails to mount our components directly inside Rails views. This provided a quick way to get started, but even after a few components we were seeing similar issues to our jQuery components: dependencies were implicit and exposed via global state. Without adequate JavaScript module support or incremental rebuilds, our React components didn’t solve all of the issues we wanted to address, but got us closer to our goal.
   React itself was not the issue, nor really was the react-rails gem to blame (they’re doing the best they can atop the existing asset pipeline). The Rails asset pipeline is showing its age and has struggled to keep up with tools available in the JavaScript ecosystem. We attempted to cobble together a few solutions that decorated the asset pipeline. browserify-rails helped tremendously, but in the end we ditched the asset pipeline in favor of Webpack. JavaScript is simply not a first class consideration in the Rails ecosystem and solutions that ride atop the existing asset pipeline offered more headaches than solutions.
  The Switch to Webpack

   It took us a few iterations, but eventually we landed on Webpack as our standalone asset build tool. Webpack provided all of the tooling we needed and along with plugins like webpack-manifest we were able to easily compliment the asset pipeline conventions established by Rails.
  We ditched the react-rails gem, but adopted its best parts; namely, its view helper and its ujs style javascript library for client side rendering. One downside to this approach is that isolated React components still had to be exposed to window, but any components used within a component could be imported without polluting the global namespace.
  Replacing the asset pipeline itself for our JavaScript (and incidentally our stylesheets) was a challenge. We started by isolating all of our React and ES6 JavaScript files into its own folder; a clear dividing line between the Rails asset pipeline and a convenient entry point for our webpack build.
  How we React

  Using our helper we generate a bit of DOM that is later hydrated by our client side rendering engine. Using this approach we can still inject properties from the server side rendered view, which allows us to build dynamic components that don’t yet need an API to receive the data they need. This provides a fantastic bridge for us to sprinkle in bits of React where needed.
  I’ve included here an example of a Rails view helper, a client side renderer, and the breadcrumbs we leave server side to bridge the server to client side gap.
  Our view helper looks a whole lot like the one from react-rails. No reason to re-invent something that works. We use this to build a blank div with some data properties that the client side renderer will use to replace with actual React components.
        Rails View Helper      We use this helper alongside our normal Rails rendered views, which allows us to mix in React components as we’re adding UI interactivity. It also allows us to iterate into larger React components without having to replace the entire server side rendered view in a big bang release.
  The helper renders a small snippet into the DOM, which becomes a placeholder for our React client side renderer.
        DOM Snippet Waiting for the React Renderer      After our view is rendered server side, our client side renderer scans the DOM for divs that are waiting to be hydrated by actual React components. These components need to be accessible via window, but we take care to namespace these entry components to prevent collisions. More complex components will usually just use the react-router as its entry point where components are rendered based on the current route.
        Client Side React Renderer      With these tools in place we had an adaptable platform that allowed us to iterate into client side rendered views where appropriate, replace hard to test jQuery interactions, and as a side effect gave us a great platform to do development in. I can’t express enough, especially in a large Rails application, how empowering tools like Hot Module Replacement, a real module system, spectacular linting tools, and robust testing frameworks are to our ability to iterate quickly on interactions and designs with confidence.
  What was that?! Flicker?! I miss Rails views :’(

  React’s view abstractions were a considerable improvement over jQuery and its simple API meant quick adoption among the developers here at Reverb. Soon we went from a few isolated components to entire views completely composed of React components. This is when we hit some issues.
  On those more complex views where the header and footer were server side rendered, but the body was predominately React rendered, we had to wait and wait and wait as React took control of the DOM and rendered in our components. This can cause some jarring UI experiences.
         
React on Rails-1 (rails,react,webpack,react,rails,react,on,react,router,onleave)
       Even where we carefully planned for good empty states we were left with UI components that flickered into existence and caused the DOM to shift around as views were hydrated. This can be mitigated by guessing at div sizes and creating good empty containers and we even went so far as to server side render our empty states with Rails only to have React remove those empty divs as they mounted, but this was far from ideal. It meant maintaining identical DOM partials in both React components and Rails’ views and clever use of jQuery to remove those empty divs once the React component was in place.
   We heard the siren song of universal javascript, but felt late to the party. Our backend didn’t speak JavaScript. There have been some attempts at solving this problem in Rails and we learned a lot from reading over @shakacode ’s react_on_rails examples, but found that some of their server side JavaScript tooling did not quite meet our needs. Their approach seemed sane though and we started to iterate on a solution to better meet our needs.
  How I Learned to Stop Worrying and Love Node.js

   Now that our JS was being shipped to our frontend in bundles produced by Webpack, we figured we could deliver that same bundle to a Node.js application to help out our Rails backend in rendering some server side React. React comes with server side rendering support out of the box , but we had to do some extra work to get our routed components to work well both client and server side.
   At Reverb, we’ve been using react-router for client side routing and we didn’t want to have to maintain yet another routing stack server side. Luckily after a bit of finagling, cursing at docs, and ample finger crossing we were able to put something together that worked perfectly on both sides of the stack.
  While we ship the same Routes.jsx file to the server and client, the server side code uses a slightly different (non browser history based) router to accomplish the same task as our client side Router.
  The React Rendering Engine

  Returning Results from Rails

  While this simple Node.js app could render our React components we still needed a way to get these back into our Rails views. With a few modifications to our `react_component` helper we were able to call through to Node.js when needed.
  Since we deploy our React Rendering Engine alongside our core Rails stack, we utilize a socket connection to communicate between the two frameworks. This separation of concerns allows our React Rendering Engine to be shared between a variety of different stacks and languages as we grow.
  With these pieces in place we can serve React snippets from our backend that are later picked up by our client side renderer. This means a dramatic difference in the UX for those views that were predominately rendered via React without forcing us to use arbitrary blank containers divs. In fact we can deliver many side effect free components (ie. those that contain no external API calls) instantly to the user.
  Flicker be gone!

React on Rails-2 (rails,react,webpack,react,rails,react,on,react,router,onleave)
       React has been a great boon to view development here at Reverb. With React components we can easily unit test our views, close the iteration gap with Hot Module Reloading, and provide isolated re-usable components across our application platforms. Work like this gets us closer to creating the kind of experience we want for our users.
  Have some questions? Feel free to reach out. We’ll be evaluating extracting some of these components into open source projects in the coming weeks so keep your ear to the ground, you might like what you hear.
  This work was the result of some great efforts from:
友荐云推荐




上一篇:In case you missed it: Septemer 2016 roundup
下一篇:宇宙射线会导致路由器 bug,思科你认真的吗?
酷辣虫提示酷辣虫禁止发表任何与中华人民共和国法律有抵触的内容!所有内容由用户发布,并不代表酷辣虫的观点,酷辣虫无法对用户发布内容真实性提供任何的保证,请自行验证并承担风险与后果。如您有版权、违规等问题,请通过"联系我们"或"违规举报"告知我们处理。

弘文 发表于 2016-10-8 11:21:47
吾表兄,年四十余.始从文,连考三年而不中.遂习武,练武场上发一矢,中鼓吏,逐之出.改学医,自撰一良方,服之,卒.
回复 支持 反对

使用道具 举报

Atman 发表于 2016-10-8 12:30:05
学习下...
回复 支持 反对

使用道具 举报

廖建 发表于 2016-10-12 03:53:35
我们都知道恶虎架不住群狼。说明:”团队很重要!”
回复 支持 反对

使用道具 举报

tmddl 发表于 2016-11-9 06:54:50
秀起来~
回复 支持 反对

使用道具 举报

wx_mnCNbm6Z 发表于 2016-11-13 08:42:12
走,MM,咱们化蝶去……  
回复 支持 反对

使用道具 举报

天使人家 发表于 2016-11-17 11:27:42
我真的不愿意用脚趾头鄙视你。但是,是你逼我这么做的!
回复 支持 反对

使用道具 举报

快乐引擎 发表于 2016-11-19 23:13:37
我知道在一个没有人的角落,楼主一边紧盯着屏幕,一边用颤抖的小手按着刷新,一遍一遍,零回复!又是零回复吗?楼主内心涌现出一种失望,眼神中透露着凄凉。是的,楼主,我理解你,这种冷落的感觉在这个地方太常见了,在这里该火的贴不会火,骗回复的帖子却永远被回复着。楼主的无奈我很懂,所以我来了,带来了经验,带来了人气,带来了零点几秒的首页显示。而我问楼主讨要的,仅仅是一层楼而已,是的,不用谢我,但请记住我,记住我来过。
回复 支持 反对

使用道具 举报

*滑动验证:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

我要投稿

推荐阅读

扫码访问 @iTTTTT瑞翔 的微博
回页顶回复上一篇下一篇回列表手机版
手机版/CoLaBug.com ( 粤ICP备05003221号 | 文网文[2010]257号 )|网站地图 酷辣虫

© 2001-2016 Comsenz Inc. Design: Dean. DiscuzFans.

返回顶部 返回列表