Skip to content

Commit 69c319a

Browse files
committed
Optimizes CSS chunks handling (caching) by SplitRoute
1 parent ebf9a55 commit 69c319a

File tree

3 files changed

+30
-17
lines changed

3 files changed

+30
-17
lines changed

__tests__/shared/components/__snapshots__/Content.jsx.snap

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -405,7 +405,7 @@ exports[`Matches shallow shapshot 1`] = `
405405
<li>
406406
<Link
407407
replace={false}
408-
to="examples/error-message"
408+
to="/examples/error-message"
409409
>
410410
Error Message
411411
</Link>

src/shared/components/Content/index.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ export default function Content() {
169169
promise;
170170
</li>
171171
<li>
172-
<Link to="examples/error-message">Error Message</Link> - Demonstrates
172+
<Link to="/examples/error-message">Error Message</Link> - Demonstrates
173173
UI component for errors messaging;
174174
</li>
175175
<li>

src/shared/utils/router/SplitRoute.jsx

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,14 @@ import { isServerSide } from 'utils/isomorphy';
1919

2020
import ContentWrapper from './ContentWrapper';
2121

22+
/* Specifies the maximal number of unused CSS stylesheets to be kept in memory.
23+
*/
24+
const MAX_UNUSED_STYLESHEETS = 10;
25+
2226
const TMP_CHUNK_PREFIX = 'community-app-assets';
2327

28+
let unusedCssStamp = 0;
29+
2430
export default class SplitRoute extends React.Component {
2531
constructor(props) {
2632
super(props);
@@ -32,15 +38,12 @@ export default class SplitRoute extends React.Component {
3238
}
3339

3440
reset() {
35-
/* Removing chunk's stylesheet from the DOM. */
36-
/* NOTE: It look like caching CSS makes no sense, as it starts conflicting
37-
* with other stylesheets. */
38-
// if (!this.props.cacheCss) {
41+
/* Marking chunk's stylesheet as unused.
42+
* This works properly only when styling does not depend on the ordering
43+
* of loaded stylesheets, which is how our CSS should be written. */
3944
const link = document.querySelector(
4045
`link[data-chunk="${TMP_CHUNK_PREFIX}/${this.props.chunkName}"]`);
41-
const head = document.getElementsByTagName('head')[0];
42-
head.removeChild(link);
43-
// }
46+
link.setAttribute('data-chunk-unused', unusedCssStamp += 1);
4447

4548
/* Reset to the initial state. */
4649
this.setState({ component: null });
@@ -144,21 +147,31 @@ export default class SplitRoute extends React.Component {
144147
let link =
145148
document.querySelector(`link[data-chunk="${TMP_CHUNK_PREFIX}/${chunkName}"]`);
146149
if (link) {
147-
/* Even if the stylesheet is already loaded, we should move it
148-
* to the end of the head, to ensure that it gets priority over
149-
* anything else.
150-
* On the other hand, if we drop cacheCss option, this should not
151-
* be a problem, and can be more efficient.
152-
*/
153-
// const head = document.getElementsByTagName('head')[0];
154-
// head.appendChild(link);
150+
/* Marking the chunk being used again. */
151+
link.removeAttribute('data-chunk-unused');
155152
} else {
156153
link = document.createElement('link');
157154
link.setAttribute('data-chunk', `${TMP_CHUNK_PREFIX}/${chunkName}`);
158155
link.setAttribute('href', `/${TMP_CHUNK_PREFIX}/${chunkName}.css`);
159156
link.setAttribute('rel', 'stylesheet');
160157
const head = document.getElementsByTagName('head')[0];
161158
head.appendChild(link);
159+
160+
/* Unloads unused CSS stylesheets, if too many of them are
161+
* loaded. */
162+
const unused = head.querySelectorAll('link[data-chunk-unused]');
163+
if (unused.length > MAX_UNUSED_STYLESHEETS) {
164+
const arr = [];
165+
unused.forEach((x) => {
166+
/* eslint-disable no-param-reassign */
167+
x.chunkOrder = Number(x.getAttribute('data-chunk-unused'));
168+
/* eslint-enable no-param-reassign */
169+
arr.push(x);
170+
});
171+
arr.sort((a, b) => a.chunkOrder - b.chunkOrder);
172+
arr.slice(0, unused.length - MAX_UNUSED_STYLESHEETS)
173+
.forEach(x => head.removeChild(x));
174+
}
162175
}
163176

164177
/* Checking, whether we need to trigger async rendering process,

0 commit comments

Comments
 (0)