From 6c359089493ab671a4b8a6f811a7db348e50b0be Mon Sep 17 00:00:00 2001 From: David Baker Date: Mon, 6 Jul 2015 14:13:02 +0100 Subject: [PATCH] Add example shwing how to customise, make customising work and document all the ways in which browserify will break and how to work around it being dumb. --- README.md | 7 ++++++ examples/custom/CustomMTextTile.js | 40 ++++++++++++++++++++++++++++++ examples/custom/README.md | 4 +++ examples/custom/index.html | 12 +++++++++ examples/custom/index.js | 40 ++++++++++++++++++++++++++++++ examples/custom/package.json | 29 ++++++++++++++++++++++ src/ComponentBroker.js | 40 ++++++++++++++++++++++-------- 7 files changed, 161 insertions(+), 11 deletions(-) create mode 100644 examples/custom/CustomMTextTile.js create mode 100644 examples/custom/README.md create mode 100644 examples/custom/index.html create mode 100644 examples/custom/index.js create mode 100644 examples/custom/package.json diff --git a/README.md b/README.md index 82325cae47..14ef7c29cd 100644 --- a/README.md +++ b/README.md @@ -30,3 +30,10 @@ Note that you may need to restart the CSS builder if you add a new file. Note that `npm start` builds debug versions of the the javascript and CSS, which are much larger than the production versions build by the `npm run build` commands. +IMPORTANT: If you customise components in your application (and hence require +react from your app) you must be sure to: + +1. Make your app depend on react directly +2. If you `npm link` matrix-react-sdk, manually remove the 'react' directory + from matrix-react-sdk's `node_modules` folder, otherwise browserify will + pull in both copies of react which causes the app to break. diff --git a/examples/custom/CustomMTextTile.js b/examples/custom/CustomMTextTile.js new file mode 100644 index 0000000000..983bd0b8fb --- /dev/null +++ b/examples/custom/CustomMTextTile.js @@ -0,0 +1,40 @@ +/* +Copyright 2015 OpenMarket Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +'use strict'; + +var React = require('react'); + +var MTextTileController = require("matrix-react-sdk/src/controllers/molecules/MTextTile"); + +module.exports = React.createClass({ + displayName: 'MTextTile', + mixins: [MTextTileController], + + render: function() { + var content = this.props.mxEvent.getContent(); + return ( + + {content.body} + + ); + }, + + onClick: function(ev) { + global.alert(this.props.mxEvent.getContent().body); + } +}); + diff --git a/examples/custom/README.md b/examples/custom/README.md new file mode 100644 index 0000000000..8125053ce0 --- /dev/null +++ b/examples/custom/README.md @@ -0,0 +1,4 @@ +matrix-react-example +==================== + +An example of how to use the Matrix React SDK to build a more customised app diff --git a/examples/custom/index.html b/examples/custom/index.html new file mode 100644 index 0000000000..98703e2715 --- /dev/null +++ b/examples/custom/index.html @@ -0,0 +1,12 @@ + + + + + Matrix Flux + + +
+ + + + diff --git a/examples/custom/index.js b/examples/custom/index.js new file mode 100644 index 0000000000..d52c1d460c --- /dev/null +++ b/examples/custom/index.js @@ -0,0 +1,40 @@ +/* +Copyright 2015 OpenMarket Ltd + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +'use strict'; + +// Remember to make your project depend on react directly as soon as +// you add a require('react') to any file in your project. Do not rely +// on react being pulled in via matrix-react-sdk: browserify breaks +// horribly in this situation and can end up pulling in multiple copies +// of react. +var React = require("react"); + +// We pull in the component broker first, separately, as we need to replace +// components before the SDK loads. +var ComponenetBroker = require("matrix-react-sdk/src/ComponentBroker"); + +var CustomMTextTile = require('./CustomMTextTile'); + +ComponenetBroker.set('molecules/MTextTile', CustomMTextTile); + +var MatrixReactSdk = require("matrix-react-sdk"); +//var MatrixReactSdk = require("../../src/index"); + +React.render( + , + document.getElementById('matrixchat') +); diff --git a/examples/custom/package.json b/examples/custom/package.json new file mode 100644 index 0000000000..6acec803fa --- /dev/null +++ b/examples/custom/package.json @@ -0,0 +1,29 @@ +{ + "name": "matrix-react-example", + "version": "0.0.1", + "description": "Example usage of matrix-react-sdk", + "author": "matrix.org", + "repository": { + "type": "git", + "url": "https://github.com/matrix-org/matrix-react-sdk" + }, + "license": "Apache-2.0", + "devDependencies": { + "browserify": "^10.2.3", + "envify": "^3.4.0", + "http-server": "^0.8.0", + "matrix-react-sdk": "../../", + "npm-css": "^0.2.3", + "parallelshell": "^1.2.0", + "reactify": "^1.1.1", + "uglify-js": "^2.4.23", + "watchify": "^3.2.1" + }, + "scripts": { + "build": "browserify -t [ envify --NODE_ENV production ] -g reactify index.js | uglifyjs -c -m -o bundle.js", + "start": "parallelshell 'watchify -v -d -g reactify index.js -o bundle.js' 'http-server'" + }, + "dependencies": { + "react": "^0.13.3" + } +} diff --git a/src/ComponentBroker.js b/src/ComponentBroker.js index 0726106104..61b2d85ee0 100644 --- a/src/ComponentBroker.js +++ b/src/ComponentBroker.js @@ -16,31 +16,48 @@ limitations under the License. 'use strict'; -var components = {}; - function load(name) { var module = require("../skins/base/views/"+name); - components[name] = module; return module; }; -module.exports = { - get: function(name) { - if (components[name]) return components[name]; +var ComponentBroker = function() { + this.components = {}; +}; - components[name] = load(name); - return components[name]; +ComponentBroker.prototype = { + get: function(name) { + if (this.components[name]) { + return this.components[name]; + } + + this.components[name] = load(name); + return this.components[name]; }, set: function(name, module) { - components[name] = module; + this.components[name] = module; } }; -// Statically require all the components we know about, -// otherwise browserify has no way of knowing what module to include +// We define one Component Broker globally, because the intention is +// very much that it is a singleton. Relying on there only being one +// copy of the module can be dicey and not work as browserify's +// behaviour with multiple copies of files etc. is erratic at best. +// XXX: We can still end up with the same file twice in the resulting +// JS bundle which is nonideal. +if (global.componentBroker === undefined) { + global.componentBroker = new ComponentBroker(); +} +module.exports = global.componentBroker; + +// We need to tell browserify to include all the components +// by direct require syntax in here, but we don't want them +// to be evaluated in this file because then we wouldn't be +// able to override them. if (0) does this. // Must be in this file (because the require is file-specific) and // must be at the end because the components include this file. +if (0) { require('../skins/base/views/atoms/LogoutButton'); require('../skins/base/views/atoms/EnableNotificationsButton'); require('../skins/base/views/atoms/MessageTimestamp'); @@ -62,3 +79,4 @@ require('../skins/base/views/organisms/RoomList'); require('../skins/base/views/organisms/RoomView'); require('../skins/base/views/templates/Login'); require('../skins/base/views/organisms/Notifier'); +}