Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lazy loading components #967

Closed
wants to merge 26 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
3a5d0d9
First working version of lazy loading components
pnicolli Oct 28, 2019
6662b2a
Changelog and cleanup
pnicolli Oct 29, 2019
6fe7837
Merge branch 'master' into lazy_load_components
sneridagh Nov 13, 2019
b9b0f34
Fixes path to loadable-stats.json in a Volto project
sneridagh Nov 13, 2019
24a6aa8
Fix duplicated js on Header and Body in dev
sneridagh Nov 13, 2019
70303fa
Upgrade autoprefixer, remove deprecated browsers option, move to brow…
sneridagh Nov 13, 2019
8baf4a1
Fix test
sneridagh Nov 14, 2019
de9029c
[WIP] Using loadable for components, still using index.js as centrali…
sneridagh Nov 14, 2019
bfcd12a
Merge branch 'master' into lazy_load_components
pnicolli Dec 10, 2019
f410bbb
Merge branch 'master' into lazy_load_components
pnicolli Dec 11, 2019
08ed258
wip: test fixing
pnicolli Jan 4, 2020
2c53c79
Merge branch 'master' into lazy_load_components
pnicolli Jan 29, 2020
e44a333
Fix jest tests
pnicolli Jan 29, 2020
af0f008
Merge branch 'master' into lazy_load_components
sneridagh Mar 7, 2020
36b0574
Fix missing merge jest config
sneridagh Mar 7, 2020
01bb7dd
WIP
sneridagh Mar 8, 2020
d53d8fa
Finally, green
sneridagh Mar 14, 2020
b5f5af3
Add missing imports
sneridagh Mar 14, 2020
c7c2cac
Remove bogus 'components'
sneridagh Mar 14, 2020
f952b57
Fix prettier
sneridagh Mar 14, 2020
301f072
Merge branch 'master' into lazy_load_components
sneridagh Mar 15, 2020
fbc61bb
Merge branch 'master' into lazy_load_components
sneridagh Mar 18, 2020
e1de0e7
Fix yarn.lock conflicts
sneridagh Mar 18, 2020
2051dc3
Fix tests once loadable component are in place in production mode as …
sneridagh Mar 21, 2020
85adc6e
Merge branch 'master' into lazy_load_components
sneridagh Mar 21, 2020
b816989
Merge error lost correct full path on server.jsx
sneridagh Mar 21, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
- Remove Docker build from tests @sneridagh
- Removed Enzyme @pnicolli
- Added testing-library (react and cypress) @pnicolli
- Added lazy loading for routes, toolbar and other components @pnicolli

## 4.0.0-alpha.9 (2019-10-09)

Expand Down
1 change: 1 addition & 0 deletions babel.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ module.exports = function(api) {
messagesDir: './build/messages/',
},
],
'@loadable/babel-plugin',
];

return {
Expand Down
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,10 @@
"@babel/plugin-proposal-throw-expressions": "7.2.0",
"@babel/plugin-syntax-import-meta": "7.2.0",
"@babel/preset-stage-0": "7.0.0",
"@loadable/babel-plugin": "5.10.3",
"@loadable/component": "5.10.3",
"@loadable/server": "5.10.3",
"@loadable/webpack-plugin": "5.7.1",
"@testing-library/cypress": "5.0.2",
"@testing-library/jest-dom": "4.2.0",
"@testing-library/react": "9.3.0",
Expand Down Expand Up @@ -285,6 +289,5 @@
"svgo-loader": "2.1.0",
"tlds": "1.203.1",
"xmlrpc": "1.3.2"
},
"devDependencies": {}
}
}
20 changes: 20 additions & 0 deletions razzle.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const autoprefixer = require('autoprefixer');
const makeLoaderFinder = require('razzle-dev-utils/makeLoaderFinder');
const nodeExternals = require('webpack-node-externals');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const LoadablePlugin = require('@loadable/webpack-plugin');
const fs = require('fs');
const { map } = require('lodash');
const glob = require('glob').sync;
Expand Down Expand Up @@ -125,6 +126,25 @@ module.exports = {
__SERVER__: false,
}),
);

config.plugins.push(
new LoadablePlugin({
outputAsset: false,
writeToDisk: { filename: path.resolve(__dirname, 'build') },
}),
);

config.output.filename = dev
? 'static/js/[name].js'
: 'static/js/[name].[chunkhash:8].js';

config.optimization = Object.assign({}, config.optimization, {
runtimeChunk: true,
splitChunks: {
chunks: 'all',
name: dev,
},
});
}

if (target === 'node') {
Expand Down
50 changes: 25 additions & 25 deletions src/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,65 +5,65 @@
*/
export Anontools from '@plone/volto/components/theme/Anontools/Anontools';
export Breadcrumbs from '@plone/volto/components/theme/Breadcrumbs/Breadcrumbs';
export ContactForm from '@plone/volto/components/theme/ContactForm/ContactForm';
// export ContactForm from '@plone/volto/components/theme/ContactForm/ContactForm';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pnicolli @sneridagh @robgietema this is technically a breaking change, correct? Do we have to assume ppl rely on those imports already? This has nothing to do with this PR really. We just have to somehow define our Volto API for semantic versioning/releases and upgrade guides.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tisto It is, but for code splitting work as expected, we need to remove them which kind of sucks... Unless we find a better/elegant way.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that's a breaking change :( Also, my current implementation is absolutely non-elegant, it would be awesome to find a better one. One components index per split bundle, for example, but that would mean having a better idea of what bundles we will split.

export Footer from '@plone/volto/components/theme/Footer/Footer';
export Header from '@plone/volto/components/theme/Header/Header';
export Icon from '@plone/volto/components/theme/Icon/Icon';
export Logo from '@plone/volto/components/theme/Logo/Logo';
export Navigation from '@plone/volto/components/theme/Navigation/Navigation';
export SearchWidget from '@plone/volto/components/theme/SearchWidget/SearchWidget';
export Title from '@plone/volto/components/theme/Title/Title';
export App from '@plone/volto/components/theme/App/App';
// export App from '@plone/volto/components/theme/App/App';
export DefaultView from '@plone/volto/components/theme/View/DefaultView';
export FileView from '@plone/volto/components/theme/View/FileView';
export ImageView from '@plone/volto/components/theme/View/ImageView';
export NewsItemView from '@plone/volto/components/theme/View/NewsItemView';
export ListingView from '@plone/volto/components/theme/View/ListingView';
export Login from '@plone/volto/components/theme/Login/Login';
export Logout from '@plone/volto/components/theme/Logout/Logout';
export NotFound from '@plone/volto/components/theme/NotFound/NotFound';
// export Login from '@plone/volto/components/theme/Login/Login';
// export Logout from '@plone/volto/components/theme/Logout/Logout';
// export NotFound from '@plone/volto/components/theme/NotFound/NotFound';
export Pagination from '@plone/volto/components/theme/Pagination/Pagination';
export SummaryView from '@plone/volto/components/theme/View/SummaryView';
export Search from '@plone/volto/components/theme/Search/Search';
// export Search from '@plone/volto/components/theme/Search/Search';
export SearchTags from '@plone/volto/components/theme/Search/SearchTags';
export TabularView from '@plone/volto/components/theme/View/TabularView';
export View from '@plone/volto/components/theme/View/View';
// export View from '@plone/volto/components/theme/View/View';
export Comments from '@plone/volto/components/theme/Comments/Comments';
export CommentEditModal from '@plone/volto/components/theme/Comments/CommentEditModal';
export SocialSharing from '@plone/volto/components/theme/SocialSharing/SocialSharing';
export Tags from '@plone/volto/components/theme/Tags/Tags';
export Register from '@plone/volto/components/theme/Register/Register';
export PasswordReset from '@plone/volto/components/theme/PasswordReset/PasswordReset';
export RequestPasswordReset from '@plone/volto/components/theme/PasswordReset/RequestPasswordReset';
// export Register from '@plone/volto/components/theme/Register/Register';
// export PasswordReset from '@plone/volto/components/theme/PasswordReset/PasswordReset';
// export RequestPasswordReset from '@plone/volto/components/theme/PasswordReset/RequestPasswordReset';

export Actions from '@plone/volto/components/manage/Actions/Actions';
export Add from '@plone/volto/components/manage/Add/Add';
export Contents from '@plone/volto/components/manage/Contents/Contents';
// export Add from '@plone/volto/components/manage/Add/Add';
// export Contents from '@plone/volto/components/manage/Contents/Contents';
export ContentsIndexHeader from '@plone/volto/components/manage/Contents/ContentsIndexHeader';
export ContentsItem from '@plone/volto/components/manage/Contents/ContentsItem';
export ContentsUploadModal from '@plone/volto/components/manage/Contents/ContentsUploadModal';
export ContentsPropertiesModal from '@plone/volto/components/manage/Contents/ContentsPropertiesModal';
export ContentsRenameModal from '@plone/volto/components/manage/Contents/ContentsRenameModal';
export ContentsWorkflowModal from '@plone/volto/components/manage/Contents/ContentsWorkflowModal';
export ContentsTagsModal from '@plone/volto/components/manage/Contents/ContentsTagsModal';
export Controlpanel from '@plone/volto/components/manage/Controlpanels/Controlpanel';
export Controlpanels from '@plone/volto/components/manage/Controlpanels/Controlpanels';
export ModerateComments from '@plone/volto/components/manage/Controlpanels/ModerateComments';
export UsersControlpanel from '@plone/volto/components/manage/Controlpanels/UsersControlpanel';
// export Controlpanel from '@plone/volto/components/manage/Controlpanels/Controlpanel';
// export Controlpanels from '@plone/volto/components/manage/Controlpanels/Controlpanels';
// export ModerateComments from '@plone/volto/components/manage/Controlpanels/ModerateComments';
// export UsersControlpanel from '@plone/volto/components/manage/Controlpanels/UsersControlpanel';
export UsersControlpanelGroups from '@plone/volto/components/manage/Controlpanels/UsersControlpanelGroups';
export VersionOverview from '@plone/volto/components/manage/Controlpanels/VersionOverview';
export Delete from '@plone/volto/components/manage/Delete/Delete';
// export Delete from '@plone/volto/components/manage/Delete/Delete';
export UsersControlpanelUser from '@plone/volto/components/manage/Controlpanels/UsersControlpanelUser';
export Diff from '@plone/volto/components/manage/Diff/Diff';
// export Diff from '@plone/volto/components/manage/Diff/Diff';
export DiffField from '@plone/volto/components/manage/Diff/DiffField';
export Display from '@plone/volto/components/manage/Display/Display';
export Edit from '@plone/volto/components/manage/Edit/Edit';
// export Edit from '@plone/volto/components/manage/Edit/Edit';
export Form from '@plone/volto/components/manage/Form/Form';
export Field from '@plone/volto/components/manage/Form/Field';
export ModalForm from '@plone/volto/components/manage/Form/ModalForm';
export History from '@plone/volto/components/manage/History/History';
// export ModalForm from '@plone/volto/components/manage/Form/ModalForm';
// export History from '@plone/volto/components/manage/History/History';
export Messages from '@plone/volto/components/manage/Messages/Messages';
export ChangePassword from '@plone/volto/components/manage/Preferences/ChangePassword';
// export ChangePassword from '@plone/volto/components/manage/Preferences/ChangePassword';
export PersonalPreferences from '@plone/volto/components/manage/Preferences/PersonalPreferences';
export PersonalInformation from '@plone/volto/components/manage/Preferences/PersonalInformation';
export ArrayWidget from '@plone/volto/components/manage/Widgets/ArrayWidget';
Expand All @@ -78,10 +78,10 @@ export SelectWidget from '@plone/volto/components/manage/Widgets/SelectWidget';
export SidebarTextWidget from '@plone/volto/components/manage/Widgets/SidebarTextWidget';
export Sidebar from '@plone/volto/components/manage/Sidebar/Sidebar';
export SidebarPortal from '@plone/volto/components/manage/Sidebar/SidebarPortal';
export Sharing from '@plone/volto/components/manage/Sharing/Sharing';
// export Sharing from '@plone/volto/components/manage/Sharing/Sharing';
export TextareaWidget from '@plone/volto/components/manage/Widgets/TextareaWidget';
export TextWidget from '@plone/volto/components/manage/Widgets/TextWidget';
export Toolbar from '@plone/volto/components/manage/Toolbar/Toolbar';
// export Toolbar from '@plone/volto/components/manage/Toolbar/Toolbar';
export WysiwygWidget from '@plone/volto/components/manage/Widgets/WysiwygWidget';
export Workflow from '@plone/volto/components/manage/Workflow/Workflow';

Expand Down Expand Up @@ -111,4 +111,4 @@ export ImageSidebar from '@plone/volto/components/manage/Sidebar/ImageSidebar';
export PersonalTools from '@plone/volto/components/manage/Toolbar/PersonalTools';
export More from '@plone/volto/components/manage/Toolbar/More';
export Types from '@plone/volto/components/manage/Toolbar/Types';
export Toast from '@plone/volto/components/manage/Toast/Toast';
// export Toast from '@plone/volto/components/manage/Toast/Toast';
8 changes: 7 additions & 1 deletion src/components/manage/Actions/Actions.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,16 @@ import { Link } from 'react-router-dom';
import { Dropdown, Icon } from 'semantic-ui-react';
import { toast } from 'react-toastify';
import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
import loadable from '@loadable/component';

import { cut, copy, copyContent, moveContent } from '../../../actions';
import { getBaseUrl } from '../../../helpers';
import { ContentsRenameModal, Toast } from '../../../components';
// import { ContentsRenameModal, Toast } from '../../../components';

const ContentsRenameModal = loadable(() =>
import('../Contents/ContentsRenameModal'),
);
const Toast = loadable(() => import('../Toast/Toast'));

const messages = defineMessages({
cut: {
Expand Down
12 changes: 7 additions & 5 deletions src/components/manage/Actions/Actions.test.jsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import '@testing-library/jest-dom/extend-expect';
import React from 'react';
import renderer from 'react-test-renderer';
import configureStore from 'redux-mock-store';
import { Provider } from 'react-intl-redux';
import { MemoryRouter } from 'react-router-dom';
import { render, wait } from '@testing-library/react';

import Actions from './Actions';

Expand All @@ -13,7 +14,7 @@ jest.mock('../Contents/ContentsRenameModal', () =>
);

describe('Actions', () => {
it('renders an actions component', () => {
it('renders an actions component', async () => {
const store = mockStore({
actions: {
actions: {
Expand Down Expand Up @@ -121,14 +122,15 @@ describe('Actions', () => {
messages: {},
},
});
const component = renderer.create(
const { container } = render(
<Provider store={store}>
<MemoryRouter>
<Actions pathname="/test" />
</MemoryRouter>
</Provider>,
);
const json = component.toJSON();
expect(json).toMatchSnapshot();
await wait(() => {
expect(container.firstChild).toMatchSnapshot();
});
});
});
46 changes: 18 additions & 28 deletions src/components/manage/Actions/__snapshots__/Actions.test.jsx.snap
Original file line number Diff line number Diff line change
Expand Up @@ -2,91 +2,81 @@

exports[`Actions renders an actions component 1`] = `
<div
aria-expanded={false}
className="ui item dropdown"
aria-expanded="false"
class="ui item dropdown"
id="toolbar-actions"
onBlur={[Function]}
onChange={[Function]}
onClick={[Function]}
onFocus={[Function]}
onMouseDown={[Function]}
role="listbox"
tabIndex={0}
tabindex="0"
>
<span>
<i
aria-hidden="true"
className="lightning big icon"
class="lightning big icon"
/>

Actions
</span>
<i
aria-hidden="true"
className="dropdown icon"
onClick={[Function]}
class="dropdown icon"
/>
<div
className="menu transition"
class="menu transition"
>
<div
className="item"
onClick={[Function]}
class="item"
role="option"
>
<i
aria-hidden="true"
className="cut icon"
class="cut icon"
/>
<span
className="text"
class="text"
>
Cut
</span>
</div>
<div
className="item"
onClick={[Function]}
class="item"
role="option"
>
<i
aria-hidden="true"
className="copy icon"
class="copy icon"
/>
<span
className="text"
class="text"
>
Copy
</span>
</div>
<a
className="item"
class="item"
href="/test/delete"
onClick={[Function]}
>
<i
aria-hidden="true"
className="trash icon"
class="trash icon"
/>
Delete
</a>
<div
className="item"
onClick={[Function]}
class="item"
role="option"
>
<i
aria-hidden="true"
className="text cursor icon"
class="text cursor icon"
/>
<span
className="text"
class="text"
>
Rename
</span>
</div>
<div
className="RenameModal"
class="RenameModal"
/>
</div>
</div>
Expand Down
5 changes: 4 additions & 1 deletion src/components/manage/Add/Add.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@ import { Portal } from 'react-portal';
import { DragDropContext } from 'react-dnd';
import HTML5Backend from 'react-dnd-html5-backend';
import qs from 'query-string';
import loadable from '@loadable/component';
import { settings } from '~/config';

import { createContent, getSchema } from '../../../actions';
import { Form, Icon, Toolbar, Sidebar } from '../../../components';
import { Form, Icon /*, Toolbar */, Sidebar } from '../../../components';
import {
getBaseUrl,
hasTilesData,
Expand All @@ -28,6 +29,8 @@ import {
import saveSVG from '../../../icons/save.svg';
import clearSVG from '../../../icons/clear.svg';

const Toolbar = loadable(() => import('../../manage/Toolbar/Toolbar'));

const messages = defineMessages({
add: {
id: 'Add {type}',
Expand Down
8 changes: 6 additions & 2 deletions src/components/manage/Contents/Contents.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,18 @@ import {
ContentsTagsModal,
ContentsPropertiesModal,
Pagination,
Toolbar,
Toast,
// Toolbar,
// Toast,
Icon as IconNext,
} from '../../../components';
import { toast } from 'react-toastify';
import loadable from '@loadable/component';

import backSVG from '../../../icons/back.svg';

const Toast = loadable(() => import('../Toast/Toast'));
const Toolbar = loadable(() => import('../Toolbar/Toolbar'));

const defaultIndexes = ['ModificationDate', 'EffectiveDate', 'review_state'];
const messages = defineMessages({
back: {
Expand Down
5 changes: 4 additions & 1 deletion src/components/manage/Contents/ContentsPropertiesModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,12 @@ import { connect } from 'react-redux';
import { compose } from 'redux';
import { isEmpty, map } from 'lodash';
import { defineMessages, injectIntl } from 'react-intl';
import loadable from '@loadable/component';

import { updateContent } from '../../../actions';
import { ModalForm } from '../../../components';
// import { ModalForm } from '../../../components';

const ModalForm = loadable(() => import('../Form/ModalForm'));

const messages = defineMessages({
properties: {
Expand Down
Loading