Skip to content

Support webpacker in generators #684

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 5, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 39 additions & 22 deletions lib/assets/javascripts/react_ujs.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory(require("react"), require("react-dom"));
module.exports = factory(require("react"), require("react-dom"), require("react-dom/server"));
else if(typeof define === 'function' && define.amd)
define(["react", "react-dom"], factory);
define(["react", "react-dom", "react-dom/server"], factory);
else if(typeof exports === 'object')
exports["ReactRailsUJS"] = factory(require("react"), require("react-dom"));
exports["ReactRailsUJS"] = factory(require("react"), require("react-dom"), require("react-dom/server"));
else
root["ReactRailsUJS"] = factory(root["React"], root["ReactDOM"]);
})(this, function(__WEBPACK_EXTERNAL_MODULE_3__, __WEBPACK_EXTERNAL_MODULE_4__) {
root["ReactRailsUJS"] = factory(root["React"], root["ReactDOM"], root["ReactDOMServer"]);
})(this, function(__WEBPACK_EXTERNAL_MODULE_3__, __WEBPACK_EXTERNAL_MODULE_4__, __WEBPACK_EXTERNAL_MODULE_5__) {
return /******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};
Expand Down Expand Up @@ -73,18 +73,18 @@ return /******/ (function(modules) { // webpackBootstrap
/******/ __webpack_require__.p = "";
/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 5);
/******/ return __webpack_require__(__webpack_require__.s = 6);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {

var nativeEvents = __webpack_require__(6)
var pjaxEvents = __webpack_require__(7)
var turbolinksEvents = __webpack_require__(8)
var turbolinksClassicDeprecatedEvents = __webpack_require__(10)
var turbolinksClassicEvents = __webpack_require__(9)
var nativeEvents = __webpack_require__(7)
var pjaxEvents = __webpack_require__(8)
var turbolinksEvents = __webpack_require__(9)
var turbolinksClassicDeprecatedEvents = __webpack_require__(11)
var turbolinksClassicEvents = __webpack_require__(10)

// see what things are globally available
// and setup event handlers to those things
Expand Down Expand Up @@ -127,13 +127,13 @@ module.exports = function(ujs) {
// Also, try to gracefully import Babel 6 style default exports
module.exports = function(className) {
var constructor;

var topLevel = typeof window === "undefined" ? this : window;
// Try to access the class globally first
constructor = window[className];
constructor = topLevel[className];

// If that didn't work, try eval
if (!constructor) {
constructor = eval.call(window, className);
constructor = eval.call(topLevel, className);
}

// Lastly, if there is a default attribute try that
Expand All @@ -160,7 +160,6 @@ module.exports = function(reqctx) {
var parts = className.split(".")
var filename = parts.shift()
var keys = parts
console.log(filename, keys)
// Load the module:
var component = reqctx("./" + filename)
// Then access each key:
Expand Down Expand Up @@ -190,10 +189,17 @@ module.exports = __WEBPACK_EXTERNAL_MODULE_4__;

/***/ }),
/* 5 */
/***/ (function(module, exports) {

module.exports = __WEBPACK_EXTERNAL_MODULE_5__;

/***/ }),
/* 6 */
/***/ (function(module, exports, __webpack_require__) {

var React = __webpack_require__(3)
var ReactDOM = __webpack_require__(4)
var ReactDOMServer = __webpack_require__(5)

var detectEvents = __webpack_require__(0)
var constructorFromGlobal = __webpack_require__(1)
Expand All @@ -209,7 +215,7 @@ var ReactRailsUJS = {
PROPS_ATTR: 'data-react-props',

// If jQuery is detected, save a reference to it for event handlers
jQuery: (typeof window.jQuery !== 'undefined') && window.jQuery,
jQuery: (typeof window !== 'undefined') && (typeof window.jQuery !== 'undefined') && window.jQuery,

// helper method for the mount and unmount methods to find the
// `data-react-class` DOM elements
Expand Down Expand Up @@ -252,6 +258,14 @@ var ReactRailsUJS = {
this.getConstructor = constructorFromRequireContext(req)
},

// Render `componentName` with `props` to a string,
// using the specified `renderFunction` from `react-dom/server`.
serverRender: function(renderFunction, componentName, props) {
var componentClass = this.getConstructor(componentName)
var element = React.createElement(componentClass, props)
return ReactDOMServer[renderFunction](element)
},

// Within `searchSelector`, find nodes which should have React components
// inside them, and mount them with their props.
mountComponents: function(searchSelector) {
Expand Down Expand Up @@ -289,13 +303,16 @@ var ReactRailsUJS = {
},
}

detectEvents(ReactRailsUJS)
if (typeof window !== "undefined") {
// Only setup events for browser (not server-rendering)
detectEvents(ReactRailsUJS)
}

module.exports = ReactRailsUJS


/***/ }),
/* 6 */
/* 7 */
/***/ (function(module, exports) {

module.exports = {
Expand All @@ -316,7 +333,7 @@ module.exports = {


/***/ }),
/* 7 */
/* 8 */
/***/ (function(module, exports) {

module.exports = {
Expand All @@ -330,7 +347,7 @@ module.exports = {


/***/ }),
/* 8 */
/* 9 */
/***/ (function(module, exports) {

module.exports = {
Expand All @@ -343,7 +360,7 @@ module.exports = {


/***/ }),
/* 9 */
/* 10 */
/***/ (function(module, exports) {

module.exports = {
Expand All @@ -357,7 +374,7 @@ module.exports = {


/***/ }),
/* 10 */
/* 11 */
/***/ (function(module, exports) {

module.exports = {
Expand Down
36 changes: 24 additions & 12 deletions lib/generators/react/component_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ class ComponentGenerator < ::Rails::Generators::NamedBase
source_root File.expand_path '../../templates', __FILE__
desc <<-DESC.strip_heredoc
Description:
Scaffold a react component into app/assets/javascripts/components.
Scaffold a React component into `components/` of your Webpacker source or asset pipeline.
The generated component will include a basic render function and a PropTypes
hash to help with development.

Expand Down Expand Up @@ -90,17 +90,29 @@ class ComponentGenerator < ::Rails::Generators::NamedBase
}

def create_component_file
extension = case
when options[:es6]
'es6.jsx'
when options[:coffee]
'js.jsx.coffee'
else
'js.jsx'
end

file_path = File.join('app/assets/javascripts/components', "#{file_name}.#{extension}")
template("component.#{extension}", file_path)
template_extension = case
when options[:es6]
'es6.jsx'
when options[:coffee]
'js.jsx.coffee'
else
'js.jsx'
end

# Prefer webpacker to sprockets:
if defined?(Webpacker)
extension = options[:coffee] ? "coffee" : "js"
target_dir = Webpacker::Configuration.source_path
.join("components")
.relative_path_from(::Rails.root)
.to_s
else
extension = template_extension
target_dir = 'app/assets/javascripts/components'
end

file_path = File.join(target_dir, "#{file_name}.#{extension}")
template("component.#{template_extension}", file_path)
end

private
Expand Down
90 changes: 64 additions & 26 deletions lib/generators/react/install_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,60 @@ class InstallGenerator < ::Rails::Generators::Base
default: false,
desc: "Don't generate server_rendering.js or config/initializers/react_server_rendering.rb"

# Make an empty `components/` directory in the right place:
def create_directory
empty_directory 'app/assets/javascripts/components'
empty_directory File.join(javascript_dir, 'components')
if !options[:skip_git]
create_file 'app/assets/javascripts/components/.gitkeep'
create_file File.join(javascript_dir, 'components/.gitkeep')
end
end

def inject_react
require_react = "//= require react\n"
# Add requires, setup UJS
def setup_react
if webpacker?
setup_react_webpacker
else
setup_react_sprockets
end
end

def create_server_rendering
if options[:skip_server_rendering]
return
elsif webpacker?
ssr_manifest_path = File.join(javascript_dir, "server_rendering.js")
template("server_rendering_pack.js", ssr_manifest_path)
else
ssr_manifest_path = File.join(javascript_dir, "server_rendering.js")
template("server_rendering.js", ssr_manifest_path)
initializer_path = "config/initializers/react_server_rendering.rb"
template("react_server_rendering.rb", initializer_path)
end
end

private

def webpacker?
!!defined?(Webpacker)
end

def javascript_dir
if webpacker?
Webpacker::Configuration.source_path
.join(Webpacker::Configuration.entry_path)
.relative_path_from(::Rails.root)
.to_s
else
'app/assets/javascripts'
end
end

def manifest
Pathname.new(destination_root).join(javascript_dir, 'application.js')
end

def setup_react_sprockets
require_react = "//= require react\n//= require react_ujs\n//= require components\n"

if manifest.exist?
manifest_contents = File.read(manifest)
Expand All @@ -39,34 +84,27 @@ def inject_react
else
create_file manifest, require_react
end
end

def inject_components
inject_into_file manifest, "//= require components\n", {after: "//= require react\n"}
end

def inject_react_ujs
inject_into_file manifest, "//= require react_ujs\n", {after: "//= require react\n"}
end

def create_components
components_js = "//= require_tree ./components\n"
components_file = File.join(*%w(app assets javascripts components.js))
components_file = File.join(javascript_dir, "components.js")
create_file components_file, components_js
end

def create_server_rendering
return if options[:skip_server_rendering]
manifest_path = "app/assets/javascripts/server_rendering.js"
template("server_rendering.js", manifest_path)
initializer_path = "config/initializers/react_server_rendering.rb"
template("react_server_rendering.rb", initializer_path)
end

private
WEBPACKER_SETUP_UJS = <<-JS
// Support component names relative to this directory:
var componentRequireContext = require.context("components", true)
var ReactRailsUJS = require("react_ujs")
ReactRailsUJS.loadContext(componentRequireContext)
JS

def manifest
Pathname.new(destination_root).join('app/assets/javascripts', 'application.js')
def setup_react_webpacker
yarn_binstub = File.expand_path("./bin/yarn", ::Rails.root)
`#{yarn_binstub} add react_ujs`
if manifest.exist?
append_file(manifest, WEBPACKER_SETUP_UJS)
else
create_file(manifest, WEBPACKER_SETUP_UJS)
end
end
end
end
Expand Down
1 change: 1 addition & 0 deletions lib/generators/templates/server_rendering.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
//= require react-server
//= require react_ujs
//= require ./components
//
// By default, this file is loaded for server-side rendering.
Expand Down
5 changes: 5 additions & 0 deletions lib/generators/templates/server_rendering_pack.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// By default, this pack is loaded for server-side rendering.
// It must expose react_ujs as `ReactRailsUJS` and prepare a require context.
var componentRequireContext = require.context("components", true)
var ReactRailsUJS = require("react_ujs")
ReactRailsUJS.loadContext(componentRequireContext)
2 changes: 1 addition & 1 deletion lib/react/server_rendering/exec_js_renderer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def render_from_parts(before, main, after)

def main_render(component_name, props, prerender_options)
render_function = prerender_options.fetch(:render_function, "renderToString")
"ReactDOMServer.#{render_function}(React.createElement(#{component_name}, #{props}))"
"ReactRailsUJS.serverRender('#{render_function}', #{component_name}, #{props})"
end

def compose_js(before, main, after)
Expand Down
Loading