Skip to content

Commit

Permalink
Fix server side memory leak (fixes #40)
Browse files Browse the repository at this point in the history
  • Loading branch information
denvned committed Jul 26, 2016
1 parent 7935799 commit 9a98a19
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 9 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "isomorphic-relay-router",
"version": "0.8.0",
"version": "0.8.1",
"description": "Adds server side rendering support to react-router-relay",
"author": "Denis Nedelyaev",
"homepage": "https://github.com/denvned/isomorphic-relay",
Expand Down Expand Up @@ -35,7 +35,7 @@
},
"dependencies": {
"babel-runtime": "^6.3.19",
"react-router-relay": "0.13.2"
"react-router-relay": "0.13.2 - 0.13.3"
},
"devDependencies": {
"babel-cli": "^6.3.17",
Expand Down
34 changes: 34 additions & 0 deletions src/AggregateContainer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
function filterVariables(component, variableMapping) {
const result = {};
for (const [name, value] of Object.entries(variableMapping)) {
if (component.hasVariable(name)) {
result[name] = value;
}
}

return result;
}

export default class AggregateContainer {
constructor(fragmentSpecs) {
this.fragmentSpecs = fragmentSpecs;
}

getFragmentNames() {
return Object.keys(this.fragmentSpecs);
}

getFragment(fragmentName, variableMapping) {
const { component, queryName } = this.fragmentSpecs[fragmentName];

return component.getFragment(queryName, filterVariables(component, variableMapping));
}

hasFragment(fragmentName) {
return !!this.fragmentSpecs[fragmentName];
}

hasVariable(variableName) {
return true;
}
}
10 changes: 10 additions & 0 deletions src/IsomorphicQueryAggregator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import QueryAggregator from 'react-router-relay/lib/QueryAggregator';
import getAggregateContainer from './getAggregateContainer';

export default class IsomorphicQueryAggregator extends QueryAggregator {
updateQueryConfig(routerProps) {
super.updateQueryConfig(routerProps);

this.Container = getAggregateContainer(this.fragmentSpecs);
}
}
2 changes: 1 addition & 1 deletion src/IsomorphicRelayRouterContext.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export default class IsomorphicRelayRouterContext extends RelayRouterContext {
return (
<IsomorphicRelay.Renderer
{...this.props}
Container={this.queryAggregator}
Container={this.queryAggregator.Container}
queryConfig={this.queryAggregator.queryConfig}
render={this.renderCallback}
/>
Expand Down
38 changes: 38 additions & 0 deletions src/getAggregateContainer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import AggregateContainer from './AggregateContainer';

const containerIds = new WeakMap;
let nextContainerId = 0;

function getContainerId(container) {
let id = containerIds.get(container);
if (id === void 0) {
id = nextContainerId++;
containerIds.set(container, id);
}

return id;
}

function getCacheKey(fragmentSpecs) {
return JSON.stringify(
Object.entries(fragmentSpecs)
.map(([fragmentName, { component, queryName }]) =>
[fragmentName, getContainerId(component), queryName]
)
.sort(([a], [b]) => a.localeCompare(b))
);
}

const containerCache = new Map;

export default function getAggregateContainer(fragmentSpecs) {
const cacheKey = getCacheKey(fragmentSpecs);

let container = containerCache.get(cacheKey);
if (!container) {
container = new AggregateContainer(fragmentSpecs);
containerCache.set(cacheKey, container);
}

return container;
}
6 changes: 3 additions & 3 deletions src/prepareData.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import IsomorphicRelay from 'isomorphic-relay';
import QueryAggregator from 'react-router-relay/lib/QueryAggregator';
import IsomorphicQueryAggregator from './IsomorphicQueryAggregator';
import render from './render';

export default function prepareData(renderProps, networkLayer) {
const queryAggregator = new QueryAggregator(renderProps);
const queryAggregator = new IsomorphicQueryAggregator(renderProps);

return IsomorphicRelay.prepareData(
{
Container: queryAggregator,
Container: queryAggregator.Container,
queryConfig: queryAggregator.queryConfig,
},
networkLayer
Expand Down
6 changes: 3 additions & 3 deletions src/prepareInitialRender.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import IsomorphicRelay from 'isomorphic-relay';
import QueryAggregator from 'react-router-relay/lib/QueryAggregator';
import IsomorphicQueryAggregator from './IsomorphicQueryAggregator';
import render from './render';

export default function prepareInitialRender(environment, renderProps) {
const queryAggregator = new QueryAggregator(renderProps);
const queryAggregator = new IsomorphicQueryAggregator(renderProps);

return IsomorphicRelay.prepareInitialRender({
environment,
Container: queryAggregator,
Container: queryAggregator.Container,
queryConfig: queryAggregator.queryConfig,
}).then(({ initialReadyState }) => ({
...renderProps,
Expand Down

0 comments on commit 9a98a19

Please sign in to comment.