Skip to content

Commit b6455cf

Browse files
committed
updated react support
* updated to react 16. * created a component mounting helper to initalize react componenets from rails views * create a component registery, so that plugins can register their top level containers * broke down generate webpack chunks into plugin specific vs common js code (to avoid duplications of js code within the bundle) * change webpack source maps to inline so it can easily be used to debug in the browser. (see webpack/webpack#2145) * updated webpack configuration so it can read from a package.json defined on a plugin
1 parent 3734555 commit b6455cf

File tree

10 files changed

+106
-19
lines changed

10 files changed

+106
-19
lines changed

.eslintrc.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
{
22
"root": true,
3-
"installedESLint": true,
43
"env": {
54
"browser": true,
65
"jquery": true

app/helpers/application_helper.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ module ApplicationHelper
1212
include NumberHelper
1313
include PlanningHelper
1414
include Title
15+
include ReactjsHelper
1516

1617
VALID_PERF_PARENTS = {
1718
"EmsCluster" => :ems_cluster,

app/helpers/reactjs_helper.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
module ReactjsHelper
2+
def mount_react_component(name, selector, data = [])
3+
javascript_tag(:defer => 'defer') do
4+
"$(MiqReact.mount('#{name}', '#{selector}', #{data.to_json}));".html_safe
5+
end
6+
end
7+
end

app/javascript/packs/application-common.js

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@
66
//
77
// To reference this file, add <%= javascript_pack_tag 'application' %> to the appropriate
88
// layout file, like app/views/layouts/application.html.erb
9+
import { mount } from '../react/mounter';
10+
import componentRegistry from '../react/componentRegistry';
911

10-
console.log('Hello World from Webpacker')
11-
12-
import * as React from 'react';
13-
import * as ReactDOM from 'react-dom';
14-
window.React = React;
15-
window.ReactDOM = ReactDOM;
12+
// TODO: use ManageIQ object, once race conditions are fixed
13+
window.MiqReact = Object.assign(window.MiqReact || {}, {
14+
mount: mount,
15+
componentRegistry: componentRegistry
16+
});
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import React from 'react';
2+
import forEach from 'lodash/forEach';
3+
import map from 'lodash/map';
4+
5+
const componentRegistry = {
6+
registry: {},
7+
8+
register({ name = null, type = null, store = true, data = true }) {
9+
if (!name || !type) {
10+
throw new Error('Component name or type is missing');
11+
}
12+
if (this.registry[name]) {
13+
throw new Error(`Component name already taken: ${name}`);
14+
}
15+
16+
this.registry[name] = { type, store, data };
17+
return this.registry;
18+
},
19+
20+
registerMultiple(componentObjs) {
21+
return forEach(componentObjs, obj => {
22+
return this.register(obj);
23+
});
24+
},
25+
26+
getComponent(name) {
27+
return this.registry[name];
28+
},
29+
30+
registeredComponents() {
31+
return map(this.registry, (value, key) => {
32+
return key;
33+
}).join(', ');
34+
},
35+
36+
markup(name, data, store) {
37+
const currentComponent = this.getComponent(name);
38+
39+
if (!currentComponent) {
40+
throw new Error(
41+
`Component not found: ${name} among ${this.registeredComponents()}`
42+
);
43+
}
44+
const ComponentName = currentComponent.type;
45+
46+
return (
47+
<ComponentName
48+
data={currentComponent.data ? data : undefined}
49+
store={currentComponent.store ? store : undefined}
50+
/>
51+
);
52+
}
53+
};
54+
55+
const coreComponets = [];
56+
57+
componentRegistry.registerMultiple(coreComponets);
58+
59+
export default componentRegistry;

app/javascript/react/mounter.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import React from 'react';
2+
import ReactDOM from 'react-dom';
3+
import componentRegistry from './componentRegistry';
4+
5+
export function mount(component, selector, data = {}) {
6+
const reactNode = document.querySelector(selector);
7+
8+
if (reactNode) {
9+
ReactDOM.unmountComponentAtNode(reactNode);
10+
ReactDOM.render(componentRegistry.markup(component, data), reactNode);
11+
} else {
12+
// eslint-disable-next-line no-console
13+
console.log(
14+
`Cannot find \'${selector}\' element for mounting the \'${component}\'`
15+
);
16+
}
17+
}

app/views/layouts/application.html.haml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
= csrf_meta_tag
3333
= render :partial => 'layouts/i18n_js'
3434
-# FIXME: the conditional below is a temporary fix for a webpacker issue, remove when it's resolved
35+
= javascript_pack_tag 'vendor'
3536
- unless Rails.env.test?
3637
- Webpacker::Manifest.instance.data.keys.each do |pack|
3738
= javascript_pack_tag pack if pack.ends_with? '-common.js'

config/webpack/development.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ const sharedConfig = require('./shared.js')
55
const { settings, output } = require('./configuration.js')
66

77
module.exports = merge(sharedConfig, {
8-
devtool: 'cheap-eval-source-map',
8+
devtool: 'inline-source-map',
99

1010
stats: {
1111
errorDetails: true

config/webpack/shared.js

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,16 +56,18 @@ module.exports = {
5656

5757
new ManifestPlugin({
5858
publicPath: output.publicPath,
59-
writeToFileEmit: true
60-
})
59+
writeToFileEmit: true,
60+
}),
61+
new webpack.optimize.CommonsChunkPlugin({
62+
name: 'vendor',
63+
}),
6164
],
6265

6366
resolve: {
6467
extensions: settings.extensions,
65-
modules: [
66-
resolve(settings.source_path),
67-
'node_modules'
68-
]
68+
modules: [resolve(settings.source_path)].concat(
69+
Object.values(engines).map(engine => `${engine}/node_modules`)
70+
),
6971
},
7072

7173
resolveLoader: {

package.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,10 @@
2222
"@angular/core": "~4.0.3",
2323
"@angular/platform-browser": "~4.0.3",
2424
"@angular/platform-browser-dynamic": "~4.0.3",
25-
"babel-preset-react": "^6.24.1",
2625
"core-js": "~2.4.1",
27-
"prop-types": "^15.5.10",
28-
"react": "^15.6.1",
29-
"react-dom": "^15.6.1",
26+
"prop-types": "^15.6.0",
27+
"react": "^16.0.0",
28+
"react-dom": "^16.0.0",
3029
"rxjs": "~5.3.0",
3130
"ui-select": "0.19.8",
3231
"zone.js": "~0.8.5"
@@ -40,6 +39,7 @@
4039
"babel-plugin-transform-class-properties": "^6.24.1",
4140
"babel-polyfill": "^6.23.0",
4241
"babel-preset-env": "~1.4.0",
42+
"babel-preset-react": "^6.24.1",
4343
"coffee-loader": "~0.7.3",
4444
"coffee-script": "~1.12.5",
4545
"compression-webpack-plugin": "~0.4.0",
@@ -51,7 +51,7 @@
5151
"eslint-plugin-import": "~1.9.2",
5252
"eslint-plugin-jsx-a11y": "~1.5.3",
5353
"eslint-plugin-promise": "~3.3.0",
54-
"eslint-plugin-react": "~5.1.1",
54+
"eslint-plugin-react": "~7.4.0",
5555
"eslint-plugin-standard": "~2.0.1",
5656
"extract-text-webpack-plugin": "~2.1.0",
5757
"file-loader": "~0.11.1",

0 commit comments

Comments
 (0)