react_webpack_rails 0.0.5 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.babelrc +3 -0
- data/.gitignore +3 -0
- data/.npmignore +1 -0
- data/.travis.yml +37 -3
- data/CHANGELOG.md +56 -0
- data/README.md +6 -0
- data/Rakefile +42 -6
- data/bin/setup +2 -0
- data/docs/README.md +10 -9
- data/docs/api.md +103 -99
- data/js/.eslintrc +12 -0
- data/js/src/env.js +1 -0
- data/js/src/index.js +30 -0
- data/js/src/integrations-manager.js +22 -0
- data/js/src/integrations/react-router.js +48 -0
- data/js/src/integrations/react.js +49 -0
- data/js/src/nodes.js +51 -0
- data/js/src/version.js +1 -0
- data/js/test/env.spec.js +10 -0
- data/js/test/integrations-manager.spec.js +38 -0
- data/js/test/integrations/react-router.spec.js +133 -0
- data/js/test/integrations/react.spec.js +96 -0
- data/js/test/nodes.spec.js +121 -0
- data/lib/assets/javascripts/react_integration.js.erb +74 -155
- data/lib/generators/react_webpack_rails/templates/.babelrc +1 -1
- data/lib/generators/react_webpack_rails/templates/karma.conf.js +1 -1
- data/lib/generators/react_webpack_rails/templates/package.json.erb +9 -3
- data/lib/generators/react_webpack_rails/templates/react/index.js.erb +4 -6
- data/lib/generators/react_webpack_rails/templates/webpack.config.js +1 -1
- data/lib/react_webpack_rails/railtie.rb +5 -0
- data/lib/react_webpack_rails/version.rb +1 -1
- data/lib/react_webpack_rails/view_helpers.rb +24 -12
- data/package.json +49 -0
- metadata +19 -4
@@ -0,0 +1,121 @@
|
|
1
|
+
import expect, { spyOn, createSpy } from 'expect';
|
2
|
+
import Nodes from '../src/nodes';
|
3
|
+
import IntegrationsManager from '../src/integrations-manager';
|
4
|
+
|
5
|
+
const { mountNodes, unmountNodes } = Nodes;
|
6
|
+
|
7
|
+
const node = {
|
8
|
+
nodeType: 1,
|
9
|
+
nodeName: 'DIV',
|
10
|
+
getAttribute: createSpy().andCall(function (attribute) {
|
11
|
+
return {
|
12
|
+
'data-react-element': 'data-react-component',
|
13
|
+
'data-payload': '{"color":"sampleColor"}',
|
14
|
+
'data-integration-name': 'basicIntegration',
|
15
|
+
'data-options': '{"prerender":false}',
|
16
|
+
}[attribute];
|
17
|
+
}),
|
18
|
+
};
|
19
|
+
|
20
|
+
describe('Nodes', function () {
|
21
|
+
beforeEach(function () {
|
22
|
+
IntegrationsManager.register(
|
23
|
+
'basicIntegration',
|
24
|
+
{
|
25
|
+
mount: () => {},
|
26
|
+
unmount: () => {},
|
27
|
+
}
|
28
|
+
);
|
29
|
+
});
|
30
|
+
|
31
|
+
afterEach(function () {
|
32
|
+
IntegrationsManager.integrations = {};
|
33
|
+
expect.restoreSpies();
|
34
|
+
});
|
35
|
+
|
36
|
+
describe('#mountNodes', function () {
|
37
|
+
context('when nodes could not be found', function () {
|
38
|
+
beforeEach(function () {
|
39
|
+
global.document = {
|
40
|
+
querySelectorAll: createSpy().andReturn([]),
|
41
|
+
};
|
42
|
+
});
|
43
|
+
|
44
|
+
it('does nothing', function () {
|
45
|
+
const mountSpy = spyOn(IntegrationsManager.get('basicIntegration'), 'mount');
|
46
|
+
mountNodes('[selectorWithoutNodes]');
|
47
|
+
|
48
|
+
expect(mountSpy.calls.length).toEqual(0);
|
49
|
+
});
|
50
|
+
});
|
51
|
+
|
52
|
+
context('when nodes were found', function () {
|
53
|
+
beforeEach(function () {
|
54
|
+
global.document = {
|
55
|
+
querySelectorAll: createSpy().andReturn([node]),
|
56
|
+
};
|
57
|
+
});
|
58
|
+
|
59
|
+
it('uses "data-react-element" as default selector', function () {
|
60
|
+
const documentSpy = spyOn(document, 'querySelectorAll');
|
61
|
+
mountNodes();
|
62
|
+
|
63
|
+
expect(documentSpy.calls.length).toEqual(1);
|
64
|
+
expect(documentSpy).toHaveBeenCalledWith('[data-react-element]');
|
65
|
+
});
|
66
|
+
|
67
|
+
it('mounts nodes', function () {
|
68
|
+
const mountSpy = spyOn(IntegrationsManager.get('basicIntegration'), 'mount');
|
69
|
+
const documentSpy = spyOn(document, 'querySelectorAll');
|
70
|
+
mountNodes('[selectorWithNodes]');
|
71
|
+
|
72
|
+
expect(mountSpy.calls.length).toEqual(1);
|
73
|
+
expect(documentSpy.calls.length).toEqual(1);
|
74
|
+
expect(documentSpy).toHaveBeenCalledWith('[selectorWithNodes]');
|
75
|
+
});
|
76
|
+
});
|
77
|
+
});
|
78
|
+
|
79
|
+
describe('#unmountNodes', function () {
|
80
|
+
context('when nodes could not be found', function () {
|
81
|
+
beforeEach(function () {
|
82
|
+
global.document = {
|
83
|
+
querySelectorAll: createSpy().andReturn([]),
|
84
|
+
};
|
85
|
+
});
|
86
|
+
|
87
|
+
it('does nothing', function () {
|
88
|
+
const unmountSpy = spyOn(IntegrationsManager.get('basicIntegration'), 'unmount');
|
89
|
+
unmountNodes('[selectorWithoutNodes]');
|
90
|
+
|
91
|
+
expect(unmountSpy.calls.length).toEqual(0);
|
92
|
+
});
|
93
|
+
});
|
94
|
+
|
95
|
+
context('when nodes were found', function () {
|
96
|
+
beforeEach(function () {
|
97
|
+
global.document = {
|
98
|
+
querySelectorAll: createSpy().andReturn([node]),
|
99
|
+
};
|
100
|
+
});
|
101
|
+
|
102
|
+
it('uses "data-react-element" as default selector', function () {
|
103
|
+
const documentSpy = spyOn(document, 'querySelectorAll');
|
104
|
+
unmountNodes();
|
105
|
+
|
106
|
+
expect(documentSpy.calls.length).toEqual(1);
|
107
|
+
expect(documentSpy).toHaveBeenCalledWith('[data-react-element]');
|
108
|
+
});
|
109
|
+
|
110
|
+
it('unmounts nodes', function () {
|
111
|
+
const unmountSpy = spyOn(IntegrationsManager.get('basicIntegration'), 'unmount');
|
112
|
+
const documentSpy = spyOn(document, 'querySelectorAll');
|
113
|
+
unmountNodes('[selectorsWithNodes]');
|
114
|
+
|
115
|
+
expect(unmountSpy.calls.length).toEqual(1);
|
116
|
+
expect(documentSpy.calls.length).toEqual(1);
|
117
|
+
expect(documentSpy).toHaveBeenCalledWith('[selectorsWithNodes]');
|
118
|
+
});
|
119
|
+
});
|
120
|
+
});
|
121
|
+
});
|
@@ -1,169 +1,88 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
var
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
},
|
66
|
-
|
67
|
-
registerRouter: function(name, routes) {
|
68
|
-
window.ReactRailsUJS.reactRouters[name] = routes;
|
69
|
-
},
|
70
|
-
|
71
|
-
getRouter: function(name) {
|
72
|
-
return window.ReactRailsUJS.reactRouters[name];
|
73
|
-
},
|
74
|
-
|
75
|
-
renderRouter: function(name, element) {
|
76
|
-
if(window.ReactRailsUJS.routerEnabled == true){
|
77
|
-
throw new Error("Error when renering " + name + "router: can't render more than one router.")
|
78
|
-
}
|
79
|
-
window.ReactRailsUJS.routerEnabled = true;
|
80
|
-
var router = window.ReactRailsUJS.getRouter(name);
|
81
|
-
_ReactDOM().render(router, element);
|
82
|
-
},
|
83
|
-
|
84
|
-
mountComponents: function(searchSelector) {
|
85
|
-
var nodes = window.ReactRailsUJS._findDOMNodes(searchSelector);
|
86
|
-
|
87
|
-
for (var i = 0; i < nodes.length; ++i) {
|
88
|
-
var node = nodes[i];
|
89
|
-
var className = node.getAttribute(window.ReactRailsUJS.CLASS_NAME_ATTR);
|
90
|
-
var propsJson = node.getAttribute(window.ReactRailsUJS.PROPS_ATTR);
|
91
|
-
try {
|
92
|
-
var isRouter = JSON.parse(node.getAttribute(window.ReactRailsUJS.ROUTER_FLAG));
|
93
|
-
} catch(error) {
|
94
|
-
var isRouter = false
|
95
|
-
}
|
96
|
-
var props = propsJson && JSON.parse(propsJson);
|
97
|
-
if (isRouter) {
|
98
|
-
window.ReactRailsUJS.renderRouter(className, node)
|
99
|
-
} else {
|
100
|
-
window.ReactRailsUJS.renderComponent(className, props, node)
|
101
|
-
}
|
102
|
-
}
|
103
|
-
},
|
104
|
-
|
105
|
-
unmountComponents: function(searchSelector) {
|
106
|
-
var nodes = window.ReactRailsUJS._findDOMNodes(searchSelector);
|
107
|
-
window.ReactRailsUJS.routerEnabled = false;
|
108
|
-
for (var i = 0; i < nodes.length; ++i) {
|
109
|
-
var node = nodes[i];
|
110
|
-
window.ReactRailsUJS.unmountComponent(node);
|
111
|
-
}
|
112
|
-
}
|
113
|
-
};
|
114
|
-
|
115
|
-
// expose helpers globally
|
116
|
-
window.registerComponent = ReactRailsUJS.registerComponent;
|
117
|
-
window.getComponent = ReactRailsUJS.getComponent;
|
118
|
-
window.createComponent = ReactRailsUJS.createComponent;
|
119
|
-
window.renderComponent = ReactRailsUJS.renderComponent;
|
120
|
-
window.unmountComponent = ReactRailsUJS.unmountComponent;
|
121
|
-
|
122
|
-
window.registerRouter = ReactRailsUJS.registerRouter;
|
123
|
-
window.getRouter = ReactRailsUJS.getRouter;
|
124
|
-
window.renderRouter = ReactRailsUJS.renderRouter;
|
125
|
-
|
126
|
-
// functions not exposed publicly
|
127
|
-
function handleTurbolinksEvents () {
|
128
|
-
var handleEvent;
|
1
|
+
var __RWR_ENV__ = {
|
2
|
+
name: "<%=Rails.env%>",
|
3
|
+
config: <%=JSON(Rails.application.config.react.shared)%>
|
4
|
+
};
|
5
|
+
|
6
|
+
function deprecatedError(helperName) {
|
7
|
+
var lines = [
|
8
|
+
helperName + ' was removed.',
|
9
|
+
'use RWR.' + helperName + ' instead.',
|
10
|
+
'check react_webpack_rails changelog for details.'
|
11
|
+
]
|
12
|
+
console.error(lines.join("\n"));
|
13
|
+
}
|
14
|
+
|
15
|
+
function registerComponent() {
|
16
|
+
deprecatedError('registerComponent');
|
17
|
+
}
|
18
|
+
|
19
|
+
function getComponent() {
|
20
|
+
deprecatedError('getComponent');
|
21
|
+
}
|
22
|
+
|
23
|
+
function createComponent() {
|
24
|
+
deprecatedError('createComponent');
|
25
|
+
}
|
26
|
+
|
27
|
+
function renderComponent() {
|
28
|
+
deprecatedError('renderComponent');
|
29
|
+
}
|
30
|
+
|
31
|
+
function unmountComponent() {
|
32
|
+
deprecatedError('unmountComponent');
|
33
|
+
}
|
34
|
+
|
35
|
+
function renderRouter() {
|
36
|
+
deprecatedError('renderRouter');
|
37
|
+
}
|
38
|
+
|
39
|
+
function registerRouter() {
|
40
|
+
deprecatedError('registerRouter');
|
41
|
+
}
|
42
|
+
|
43
|
+
function unmountRouter() {
|
44
|
+
deprecatedError('unmountRouter');
|
45
|
+
}
|
46
|
+
|
47
|
+
function getRouter() {
|
48
|
+
deprecatedError('getRouter');
|
49
|
+
}
|
50
|
+
|
51
|
+
var RWRhandlers = {
|
52
|
+
_mountNodes: function _mountNodes() {
|
53
|
+
RWR.mountNodes();
|
54
|
+
},
|
55
|
+
|
56
|
+
_unmountNodes: function _unmountNodes() {
|
57
|
+
RWR.unmountNodes();
|
58
|
+
},
|
59
|
+
|
60
|
+
_handleEvent: function(eventName, callback) {
|
61
|
+
document.addEventListener(eventName, callback);
|
62
|
+
},
|
63
|
+
|
64
|
+
handleTurbolinksEvents: function handleTurbolinksEvents() {
|
129
65
|
var unmountEvent;
|
130
66
|
|
131
|
-
if ($) {
|
132
|
-
handleEvent = function(eventName, callback) {
|
133
|
-
$(document).on(eventName, callback);
|
134
|
-
};
|
135
|
-
|
136
|
-
} else {
|
137
|
-
handleEvent = function(eventName, callback) {
|
138
|
-
document.addEventListener(eventName, callback);
|
139
|
-
};
|
140
|
-
}
|
141
|
-
|
142
67
|
if (Turbolinks.EVENTS) {
|
143
68
|
unmountEvent = Turbolinks.EVENTS.BEFORE_UNLOAD;
|
144
69
|
} else {
|
145
70
|
unmountEvent = 'page:receive';
|
146
71
|
Turbolinks.pagesCached(0);
|
147
|
-
|
148
|
-
if (window.ReactRailsUJS.RAILS_ENV_DEVELOPMENT) {
|
149
|
-
console.warn('The Turbolinks cache has been disabled (Turbolinks >= 2.4.0 is recommended). See https://github.com/reactjs/react-rails/issues/87 for more information.');
|
150
|
-
}
|
151
72
|
}
|
152
|
-
|
153
|
-
|
154
|
-
}
|
73
|
+
RWRhandlers._handleEvent('page:change', RWRhandlers._mountNodes);
|
74
|
+
RWRhandlers._handleEvent(unmountEvent, RWRhandlers._unmountNodes);
|
75
|
+
},
|
155
76
|
|
156
|
-
function handleNativeEvents() {
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
document.addEventListener('DOMContentLoaded', function() {window.ReactRailsUJS.mountComponents()});
|
161
|
-
}
|
162
|
-
}
|
77
|
+
handleNativeEvents: function handleNativeEvents() {
|
78
|
+
document.addEventListener('DOMContentLoaded', RWRhandlers._mountNodes);
|
79
|
+
},
|
80
|
+
};
|
163
81
|
|
82
|
+
(function reactMain() {
|
164
83
|
if (typeof Turbolinks !== 'undefined' && Turbolinks.supported) {
|
165
|
-
handleTurbolinksEvents();
|
84
|
+
RWRhandlers.handleTurbolinksEvents();
|
166
85
|
} else {
|
167
|
-
handleNativeEvents();
|
86
|
+
RWRhandlers.handleNativeEvents();
|
168
87
|
}
|
169
88
|
})(document, window);
|
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "<%="#{Rails.application.class.parent_name}"%>",
|
3
3
|
"devDependencies": {
|
4
|
-
"babel-eslint": "^
|
4
|
+
"babel-eslint": "^5.0.0-beta6",
|
5
5
|
"eslint": "^1.7.3",
|
6
6
|
"eslint-plugin-react": "^3.6.3",
|
7
7
|
"expect": "^1.12.2",
|
@@ -11,19 +11,25 @@
|
|
11
11
|
"karma-sinon": "^1.0.4",
|
12
12
|
"karma-sourcemap-loader": "^0.3.6",
|
13
13
|
"karma-webpack": "^1.7.0",
|
14
|
+
"mocha": "^2.3.4",
|
15
|
+
"sinon": "^1.17.2",
|
14
16
|
"react-hot-loader": "^1.3.0",
|
15
17
|
"webpack-dev-server": "^1.12.1",
|
16
18
|
"webpack-notifier": "^1.2.1"
|
17
19
|
},
|
18
20
|
"dependencies": {
|
19
|
-
"babel-core": "^
|
20
|
-
"babel-loader": "^
|
21
|
+
"babel-core": "^6.4.0",
|
22
|
+
"babel-loader": "^6.2.1",
|
23
|
+
"babel-preset-es2015": "^6.3.13",
|
24
|
+
"babel-preset-react": "^6.3.13",
|
25
|
+
"babel-preset-stage-1": "^6.3.13",
|
21
26
|
"extract-text-webpack-plugin": "^0.8.2",
|
22
27
|
"node-sass": "^3.3.3",
|
23
28
|
"react": "^0.14.0",
|
24
29
|
"react-dom": "^0.14.0",
|
25
30
|
<%= options.router ? ' "react-router": "1.0.0-rc3",' : ''%>
|
26
31
|
"react-tools": "*",
|
32
|
+
"react-webpack-rails": "0.1.0",
|
27
33
|
"sass-loader": "^3.0.0",
|
28
34
|
"webpack": "^1.12.1"
|
29
35
|
},
|
@@ -1,12 +1,10 @@
|
|
1
|
-
import
|
2
|
-
|
3
|
-
window.React = React;
|
4
|
-
window.ReactDOM = ReactDOM;
|
1
|
+
import RWR from 'react-webpack-rails';
|
2
|
+
window.RWR = RWR;
|
5
3
|
<% if options.example %>
|
6
4
|
import HelloWorld from './components/hello-world';
|
7
|
-
registerComponent('HelloWorld', HelloWorld);
|
5
|
+
RWR.registerComponent('HelloWorld', HelloWorld);
|
8
6
|
<% else %>
|
9
7
|
// example usage:
|
10
8
|
// import HelloWorld from './components/hello-world';
|
11
|
-
// registerComponent('HelloWorld', HelloWorld);
|
9
|
+
// RWR.registerComponent('HelloWorld', HelloWorld);
|
12
10
|
<% end %>
|
@@ -2,6 +2,11 @@ require 'react_webpack_rails/view_helpers'
|
|
2
2
|
|
3
3
|
module ReactWebpackRails
|
4
4
|
class Railtie < ::Rails::Railtie
|
5
|
+
config.react = ActiveSupport::OrderedOptions.new
|
6
|
+
# Sensible defaults. Can be overridden in application.rb
|
7
|
+
config.react.camelize_props = false # pass in an underscored hash but get a camelized hash
|
8
|
+
config.react.shared = {}
|
9
|
+
|
5
10
|
initializer 'react_webpack_rails.view_helpers' do
|
6
11
|
ActionView::Base.send :include, ViewHelpers
|
7
12
|
end
|