Rails/Webpack Khor, @neth_6, re:Culture, Xenon Ventures 2017-03-08
Rails/WebpackKhor, @neth_6, re:Culture, Xenon Ventures
2017-03-08
Goal● Rubyists be comfortable with Javascript
○ Installing webpack onto Rails app○ Directory structure conventions○ Configuration options○ Simple javascript web app
Agenda● Rails & Javascript History● Why Webpack● ‘Live-coding’ from scratch to simple app
# Gemfilegem 'jquery-rails'
The gem Way
The gem Way - Noooo!
● gem creation● gem updated
The cowboy Way ● app/assets/javascripts● lib/assets/javascripts● vendor/assets/javascripts
The cowboy way - sidekickvendorer gem
Dependencies
The cowboy way - Noooo!
JS package names
Can require JS, CSS, etc.
The rails-assets Way
JS packages
RubyGem
Manage dependencies Convert JS into Gem
The rails-assets Way - Future● Will bower be around?● Will rails-assets be around?● Tested in JS but not tested in Rails assets?
Browserify, Webpack, etc.
Rails+Relay+GraphQL+React+Browserify
https://medium.com/react-weekly/relay-facebook-on-rails-8b4af2057152
Rails/Webpack
Javascript as First-class Citizen
First-class Citizen
Javascript tools do packaging, manage dependencies, etc.
What You Already Know> curl -sSL https://get.rvm.io | bash -s stable --ruby
> rvm install 2.3.0
> rvm use 2.3.0@global
> gem install bundle
> rvm use 2.3.0
> rvm gemset create rails_webpack
> rvm gemset use rails_webpack
> gem install rails
rvm
bundler
gem
Live Coding> rails new rails_webpack
> echo 2.3.0 > rails_webpack/.ruby-version
> echo rails_webpack > rails_webpack/.ruby-gemset
> cd rails_webpack
> echo “gem ‘webpacker’, github: ‘rails/webpacker’” >> Gemfile
> echo “gem ‘foreman’” >> Gemfile
> bundle install
> rails webpack:install
rails app
webpack
rails env
rails webpack:install
Webpack config
Webpack config
config/webpack/shared.js entry: glob.sync(path.join('app', 'javascript', 'packs', '*.js*')).reduce( (map, entry) => { const basename = path.basename(entry, extname(entry)) const localMap = map localMap[basename] = path.resolve(entry) return localMap }, {} ),
output: { filename: '[name].js', path: path.resolve('public', ‘packs’) },
Bundle entry points
Generated bundles
config/webpack/production.jsmodule.exports = merge(sharedConfig.config, { output: { filename: '[name]-[chunkhash].js' },
plugins: [ new webpack.LoaderOptionsPlugin({ minimize: true }), new webpack.optimize.UglifyJsPlugin(), new CompressionPlugin({ asset: '[path].gz[query]', algorithm: 'gzip', test: /\.js$/ })
Do stuff required for production
Javascript Code
Where JS code lives
Webpack config
app/javascriptCommon structure:
+-- app/javascript/ | +-- <app name>/ | +-- components/ +-- index.js
app/javascript/simple/index.jsimport _ from 'lodash';
function component () { var element = document.createElement('div');
/* lodash is required for the next line to work */ element.innerHTML = _.join(['Woohoo','webpack'], ' ');
return element;}
document.body.appendChild(component());
Bundle Entry Points
Where JS code livesBundle entry points
Refers to code
Webpack config
app/javascript/packs/simple.js// Refers to code in app/javascript
import ‘../simple’
Bundle Output
Where JS code livesBundle entry points
Refers to code
/public/packsOutputs to
Webpack config
public/packs/simple.js/******/ (function(modules) { // webpackBootstrap/******/ // The module cache/******/ var installedModules = {};....
function component() { var element = document.createElement('div'); /* lodash is required for the next line to work */ element.innerHTML = __WEBPACK_IMPORTED_MODULE_0_lodash___default.a.join(['Woohoo', 'webpack'], ' '); return element;}
Live Coding (cont.)> rails g controller page index rails view
app/views/pages/index.html.erb<%= javascript_pack_tag 'simple' %>
Tada….the most meaningless web app
Tada….the most meaningless web app
<%= javascript_pack_tag 'simple' %> <html> <body>
…. < assets stuff > ...
<script src="/packs/simple.js"></script>
</body></html>
Webpack Wrappers
Where JS code livesBundle entry points
Refers to code
/public/packsOutputs to
Webpack config
WebpackWrappers
Webpack Wrapper (cont.)● bin/webpack
○ Compiling bundles
● bin/webpack-watcher○ Watch for bundle changes and re-compile with Webpack into public/packs
● bin/webpack-dev-server○ Live-reloading
■ Watch for bundle changes, re-compile with Webpack, and refresh■ Can serve pages from public/packs
Manual compile (e.g., production deploy): rails webpack:compile
Procfile
# Run Rails & Webpack concurrentlyrails: bundle exec puma -p $PORTwpwatcher: ./bin/webpack-watcher
Procfile (webpack-dev-server)# Run Rails & Webpack concurrentlyrails: bundle exec puma -p $PORTwebpack-dev-server: ./bin/webpack-dev-server
# config/environments/development.rb
# For webpack-dev-serverconfig.x.webpacker[:dev_server_host] = "http://localhost:8080"
Other webpacker commands
rails webpack:install - Compile assetsrails webpack:install:react - Install react
Is CoffeeScript Gone?// config/webpack/shared.js
module: { rules: [ { test: /\.coffee(\.erb)?$/, loader: 'coffee-loader' }, ... },}
Accessing Assets from Javascript// config/webpack/shared.js
module: { rules: [ { test: /\.js(\.erb)?$/, exclude: /node_modules/, loader: 'babel-loader', options: { presets: [ ['env', { modules: false }] ] } },
Accessing Assets from Javascript (cont.)// app/javascript/simple/index.js.erb
<% helpers = ActionController::Base.helpers %>var railsImagePath = "<%= helpers.image_path('rails.png') %>";
References● Unholy Javascript:
○ http://railsapps.github.io/rails-javascript-include-external.html
● Webpacker: ○ https://medium.com/statuscode/introducing-webpacker-7136d66cddfb
Thank You!
Convox Tokyo Meetup 23 Mar 2017https://www.meetup.com/Convox-Meetup/events/237726139/