Skip to content

Commit

Permalink
Add editorKey prop for SSR (facebookarchive#796)
Browse files Browse the repository at this point in the history
* add editorKey functionnality

* add simple tests for editorKey functionality

* fix flow error

* minimal working error case for universal rendering

adds a small express-backed universal react app that only accepts `/`
requests but that exhibits a client/server mismatch issue

* fix failing test when length of generated hash is small

* Update universal example

since this PR was created some changes were made and this updates the
example to fit with our other examples.

- moves into the version specific subdirectories
- updates package.json
- removes some ES6 destucturing temporarily because polyfill seems to be
  not loading correctly
  • Loading branch information
pofigizm authored and flarnie committed Mar 15, 2017
1 parent 559d4e4 commit 67ff195
Show file tree
Hide file tree
Showing 17 changed files with 371 additions and 1 deletion.
1 change: 1 addition & 0 deletions examples/draft-0-10-0/universal/.babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "presets": ["react"] }
2 changes: 2 additions & 0 deletions examples/draft-0-10-0/universal/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
static
node_modules
19 changes: 19 additions & 0 deletions examples/draft-0-10-0/universal/client.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule Draft
*/

'use strict';

var React = require('react');
var ReactDom = require('react-dom');

var SimpleEditor = require('./editor.js').SimpleEditor;

ReactDom.render(<SimpleEditor />, document.getElementById('react-content'));
44 changes: 44 additions & 0 deletions examples/draft-0-10-0/universal/editor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule Draft
*/

'use strict';

const Draft = require('draft-js');
const React = require('react');

class SimpleEditor extends React.Component {
constructor(props) {
super(props);

this.state = {editorState: Draft.EditorState.createWithContent(emptyContentState)};
this.onChange = (editorState) => this.setState({editorState});
}
render() {
const Editor = Draft.Editor;
const editorState = this.state.editorState;
return <Editor placeholder="heyyyyy" editorKey="foobaz" editorState={editorState} onChange={this.onChange} />;
}
}
module.exports = {
SimpleEditor: SimpleEditor,
};

const emptyContentState = Draft.convertFromRaw({
entityMap: {},
blocks: [
{
text: '',
key: 'foo',
type: 'unstyled',
entityRanges: [],
},
],
});
39 changes: 39 additions & 0 deletions examples/draft-0-10-0/universal/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule Draft
*/

'use strict';

var React = require('react');
var ReactDOMServer = require('react-dom/server');

var SimpleEditor = require('./editor.js').SimpleEditor;

var express = require('express');

var app = express();

app.use('/static', express.static('static'));

app.get('/', (req, res) => {
const rendered = ReactDOMServer.renderToString(<SimpleEditor />);
const page = `<!doctype html>
<html>
<body>
<div id="react-content">${ rendered }</div>
<script src="/static/bundle.js"></script>
</body>
</html>
`;
res.send(page);
});

app.listen(3003);
console.log('app now listening at http://localhost:3003');
24 changes: 24 additions & 0 deletions examples/draft-0-10-0/universal/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "universal",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"dependencies": {
"draft-js": "file:../../../",
"express": "^4.14.0",
"immutable": "^3.8.1",
"react": "^15.4.1",
"react-dom": "^15.4.1"
},
"devDependencies": {
"babel-cli": "^6.18.0",
"babel-preset-react": "^6.16.0",
"babelify": "^7.3.0",
"browserify": "^13.1.1"
},
"scripts": {
"build": "mkdir -p static; browserify client.js -t babelify -o static/bundle.js",
"start": "babel-node index.js",
"demo": "npm run build && npm run start"
}
}
29 changes: 29 additions & 0 deletions examples/draft-0-10-0/universal/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Universal rendering

Draft is well suited for universal (isomorphic) rendering contexts:

Here, we have three files:

* editor.js
A simple draftjs editor exported as `<SimpleEditor />`
* client.js
A simple clientside entrypoint that clientside renders the index page route's logic into a `#react-content` div.
* index.js
A simple express server that prerenders a <SimpleEditor /> in the `#react-content` div

you can run this by first building draft-js and then installing this demo's dependencies

```bash
# in draft-js folder
yarn
pushd examples/universal
yarn
```

then, run

`npm run demo`

which will open a server listening on [http://localhost:3003](http://localhost:3003)

visiting the main route will return a simple unstyled draft editor but the client, on re-rendering the `<SimpleEditor />` will complain that there is a mismatch between the server rendered content and the client-rendered content.
1 change: 1 addition & 0 deletions examples/draft-0-9-1/universal/.babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{ "presets": ["react"] }
2 changes: 2 additions & 0 deletions examples/draft-0-9-1/universal/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
static
node_modules
19 changes: 19 additions & 0 deletions examples/draft-0-9-1/universal/client.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule Draft
*/

'use strict';

var React = require('react');
var ReactDom = require('react-dom');

var SimpleEditor = require('./editor.js').SimpleEditor;

ReactDom.render(<SimpleEditor />, document.getElementById('react-content'));
44 changes: 44 additions & 0 deletions examples/draft-0-9-1/universal/editor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule Draft
*/

'use strict';

const Draft = require('draft-js');
const React = require('react');

class SimpleEditor extends React.Component {
constructor(props) {
super(props);

this.state = {editorState: Draft.EditorState.createWithContent(emptyContentState)};
this.onChange = (editorState) => this.setState({editorState});
}
render() {
const Editor = Draft.Editor;
const editorState = this.state.editorState;
return <Editor placeholder="heyyyyy" editorKey="foobaz" editorState={editorState} onChange={this.onChange} />;
}
}
module.exports = {
SimpleEditor: SimpleEditor,
};

const emptyContentState = Draft.convertFromRaw({
entityMap: {},
blocks: [
{
text: '',
key: 'foo',
type: 'unstyled',
entityRanges: [],
},
],
});
39 changes: 39 additions & 0 deletions examples/draft-0-9-1/universal/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* Copyright (c) 2013-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule Draft
*/

'use strict';

var React = require('react');
var ReactDOMServer = require('react-dom/server');

var SimpleEditor = require('./editor.js').SimpleEditor;

var express = require('express');

var app = express();

app.use('/static', express.static('static'));

app.get('/', (req, res) => {
const rendered = ReactDOMServer.renderToString(<SimpleEditor />);
const page = `<!doctype html>
<html>
<body>
<div id="react-content">${ rendered }</div>
<script src="/static/bundle.js"></script>
</body>
</html>
`;
res.send(page);
});

app.listen(3003);
console.log('app now listening at http://localhost:3003');
24 changes: 24 additions & 0 deletions examples/draft-0-9-1/universal/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"name": "universal",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"dependencies": {
"draft-js": "file:../../../",
"express": "^4.14.0",
"immutable": "^3.8.1",
"react": "^15.4.1",
"react-dom": "^15.4.1"
},
"devDependencies": {
"babel-cli": "^6.18.0",
"babel-preset-react": "^6.16.0",
"babelify": "^7.3.0",
"browserify": "^13.1.1"
},
"scripts": {
"build": "mkdir -p static; browserify client.js -t babelify -o static/bundle.js",
"start": "babel-node index.js",
"demo": "npm run build && npm run start"
}
}
29 changes: 29 additions & 0 deletions examples/draft-0-9-1/universal/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Universal rendering

Draft is well suited for universal (isomorphic) rendering contexts:

Here, we have three files:

* editor.js
A simple draftjs editor exported as `<SimpleEditor />`
* client.js
A simple clientside entrypoint that clientside renders the index page route's logic into a `#react-content` div.
* index.js
A simple express server that prerenders a <SimpleEditor /> in the `#react-content` div

you can run this by first building draft-js and then installing this demo's dependencies

```bash
# in draft-js folder
yarn
pushd examples/universal
yarn
```

then, run

`npm run demo`

which will open a server listening on [http://localhost:3003](http://localhost:3003)

visiting the main route will return a simple unstyled draft editor but the client, on re-rendering the `<SimpleEditor />` will complain that there is a mismatch between the server rendered content and the client-rendered content.
2 changes: 1 addition & 1 deletion src/component/base/DraftEditor.react.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ class DraftEditor extends React.Component {
this._clipboard = null;
this._handler = null;
this._dragCount = 0;
this._editorKey = generateRandomKey();
this._editorKey = props.editorKey || generateRandomKey();
this._placeholderAccessibilityID = 'placeholder-' + this._editorKey;
this._latestEditorState = props.editorState;

Expand Down
3 changes: 3 additions & 0 deletions src/component/base/DraftEditorProps.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ export type DraftEditorProps = {
editorState: EditorState,
onChange: (editorState: EditorState) => void,

// specify whether using ssr
editorKey?: string,

placeholder?: string,

// Specify whether text alignment should be forced in a direction
Expand Down
Loading

0 comments on commit 67ff195

Please sign in to comment.