Fast Rich Client Rails Development With Webpack and the ES6 Transpiler

I think until:

  1. The browsers support better performance for many small files
  2. You really want to support a small download on mobile

Then you are better off with a single JS download that is cached. You definitely don’t want to have duplicates JS code wrapped up with the Sprockets application.js requires.

Yes, 100% correct. In the other thing is that the multiple entry point library is amazing. Webpack inspects the modules, and figures out which dependencies are shared between all(most?) and automatically extracts them out to the common bundle.

https://webpack.github.io/docs/list-of-plugins.html#commonschunkplugin

Webpack is amazing.

Have you considered turning this into a gem?

@justin do you know https://rails-assets.org/? It seems like a solution for all JS dependencies in much simpler way.

I looked into it, but I really wanted the JSX and ES6 transpilers.

You might be interested in the 6to5 transformer for sprockets (i.e. Rails): https://github.com/josh/sprockets-es6

6to5 automatically gives you all ES6 features and it transpiles JSX out of the box also. So with this and rails-assets you can save yourself a whole lot of work and have all the main features you want, except of course the hot module replacement, which in my opinion is not worth the tradeoff.

@waynehoover, that’s awesome! Do you know what the best strategy for integrating npm for dependencies?

@justin Great write up! Do you think there’s a way to make your app component available in the components.js to take advantage of {prerender: true} option from react-rails?

Hi @Tuan_Bui, I think you’re asking for this. If you could put together a PR, we’d be thrilled.

@justin Thanks for this tutorial. I’m on a new project and am thankfully able to set something like this up pretty much from day one, so a nice ES6/React/Webpack-y future for me.

This app I’m on is a more traditional web app with some turbolinks thrown in there for good measure. A couple of the views have some embedded content at the bottom of the view that gets rendered on page load to sprinkle in some functionality and looks like this:

<%= content_for :javascripts do %>
<script type="text/javascript">
  jQuery(document).on('page:change', function(){
    // do some stuff
  })
</script>
<% end %>

Is there an idiomatic way to move this script out of this template and into its own script that gets called when this view is hit? All I can really come up with is assigning that script to a global that gets called instead:

<%= content_for :javascripts do %>
<script type="text/javascript">
  jQuery(document).on('page:change', function(){
    CallMyGlobal()
  })
</script>
<% end %>

But that seems inelegant.

I’ve been mainly working on a single page web app for the last couple years, right before turbolinks took off, so I’m not sure how best to go at this hybrid approach.

Thank you very much for any advice.

@ericdfields I really don’t know without doing some testing. However, I’ll be very interested to see what you come up with!

Heads up: https://github.com/justin808/react-webpack-rails-tutorial/pull/19

Latest code examples moved the “/webpack” directory to “/client”

Do not EVER, EVER!! mess with the permissions of system files!! Don’t install node as sudo! Please install node the right way! Use nvm if you want the simplest solution. You’re going to permanently mess up your node and other library installs to circumvent a problem that doesn’t exist in the first place. Please edit your blog post to remove this bad advice!!!

@mark_trinidad I’m using nvm. Would you agree with that? @martin and I are about update the article and this is great feedback.

Thanks for the tutorial!

I have added devise for people who want to start with an app with user functionality: https://github.com/djkz/rails-devise-react-boilerplate

The only issue is the compiled javascript is over 2MB. How can I check and reduce that size?

I’ve thought about adding devise to the tutorial, but it would seem to take from the focus of a super simple example.

My consulting team is building a greenfield “fun” real world Silicon Valley startup app based on the tutorial, so if anybody is interested in joining this venture, get in touch! I’ll soon be making about post about all the interesting things we’re doing. However, if you want to work on a real-world project with these technologies, get in touch with me at justin@railsonmaui.com.

Just read this article today. Great stuff - thanks Justin and team! A question that occurs to me is did you considered replacing the Rails asset pipeline with Gulp? It seems like you could get more control over your integration of technologies. The main thing that you need the react-rails gem for is to plug into the asset pipeline, right?

Here’s one example talking about building a new asset pipeline with Gulp: http://viget.com/extend/gulp-rails-asset-pipeline

And here’s an example talking about using the pipeline with Webpack and Gulp but without the react-rails gem (uses 6to5 loader to transpile ES6 and JSX): http://aergonaut.com/rails-4-gulp-webpack-react/

@pickettd, Webpack is the way to go. Several key members in the React community suggested it.

@justin hello justin, i try to deploy the heroku, but, i got this:

-----> Preparing app for Rails asset pipeline
       Running: rake assets:precompile
       cd client && $(npm bin)/webpack --config './config/webpack/production.config.js'
       module.js:338
       throw err;
       ^
       Error: Cannot find module 'jquery'
       at Function.Module._resolveFilename (module.js:336:15)
       at Function.require.resolve (module.js:388:19)
       at Object.<anonymous> (/tmp/build_d29d23c4c49fcec213baff4ad1d9a8d0/client/config/webpack/production.config.js:32:18)
       at Module._compile (module.js:460:26)
       at Object.Module._extensions..js (module.js:478:10)
       at Module.load (module.js:355:32)
       at Function.Module._load (module.js:310:12)
       at Module.require (module.js:365:17)
       at require (module.js:384:17)
       at module.exports (/tmp/build_d29d23c4c49fcec213baff4ad1d9a8d0/client/node_modules/webpack/bin/convert-argv.js:80:13)
       rake aborted!
       Command failed with status (1): [cd client && $(npm bin)/webpack --config '...]
       /tmp/build_d29d23c4c49fcec213baff4ad1d9a8d0/lib/tasks/assets.rake:16:in `block (2 levels) in <top (required)>'
       Tasks: TOP => assets:precompile => assets:compile_environment => assets:webpack
       (See full trace by running task with --trace)

do you know what happend?

i use the

externals: {
    jquery: 'var jQuery'
  },

but looks not working.

If you look at the example webpack config files and look for the string jQuery, jquery, or $, you’ll see the line that allows webpack to know that jQuery is globally exported by Rails.