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

More lazy loading of react components to reduce bundle size #1888

Merged
merged 47 commits into from
Apr 21, 2021
Merged
Show file tree
Hide file tree
Changes from 33 commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
e76db14
Try some lazy react components
cmdcolin Apr 8, 2021
da6c2d2
Circular view lazy
cmdcolin Apr 8, 2021
f11f9e9
Make dotplot react component lazy
cmdcolin Apr 8, 2021
83022ab
Smaller icons
cmdcolin Apr 8, 2021
285afb4
Bit more lazy loading on start screen
cmdcolin Apr 8, 2021
3239cf9
Lazy react-ify spreadsheet view
cmdcolin Apr 8, 2021
a2a9a26
Import callback
cmdcolin Apr 8, 2021
cb56983
Fix some lint
cmdcolin Apr 8, 2021
dde7325
Add drawer widgets to lazy
cmdcolin Apr 8, 2021
faf24be
Remove LazyReactComponent, just use ReactComponent and require Suspense
cmdcolin Apr 8, 2021
bb54c7d
Modularize widgets
cmdcolin Apr 8, 2021
5ae5a7d
Lazy drawer widgets
cmdcolin Apr 8, 2021
c84db4b
Remove concept of track based dialog
cmdcolin Apr 9, 2021
a650652
Dialog on session
cmdcolin Apr 9, 2021
85f3afd
More intermediate
cmdcolin Apr 9, 2021
6521866
Incremental
cmdcolin Apr 9, 2021
11eb281
Add some suspense for tests
cmdcolin Apr 9, 2021
381cda9
Suspense
cmdcolin Apr 9, 2021
554dbdb
Update
cmdcolin Apr 9, 2021
3d04996
Couple more lazy
cmdcolin Apr 9, 2021
172360e
More wild stuff
cmdcolin Apr 9, 2021
4ec8f62
Updates
cmdcolin Apr 9, 2021
36c6893
Assemblymanager/variant detail widget code lazified
cmdcolin Apr 9, 2021
19ab66f
Add some tsdx configs to disable splitting bundle
cmdcolin Apr 9, 2021
863946c
Merge origin/main
cmdcolin Apr 13, 2021
01e68ff
Use a specific build of jbrowse-web to get lazy loading instead of fu…
cmdcolin Apr 13, 2021
e404b82
Increase timeout
cmdcolin Apr 13, 2021
a8606b0
Add a suspense on embedded mode but sometimes only menu shows up
cmdcolin Apr 13, 2021
f6af519
Fix some dialog props
cmdcolin Apr 15, 2021
6e1a9d8
Small refactors
cmdcolin Apr 15, 2021
d644db1
Merge remote-tracking branch 'origin/main' into lazyreact
cmdcolin Apr 15, 2021
a8c68dc
Merge origin/main
cmdcolin Apr 15, 2021
76a7469
More lazy
cmdcolin Apr 15, 2021
048db55
Better suspense fallback loading message
cmdcolin Apr 16, 2021
a38f469
Export name
cmdcolin Apr 16, 2021
a076345
Give display names to default exported react components, and add Lazy…
cmdcolin Apr 16, 2021
37fe032
Replace export default observer(() => {}) with expanded named functio…
cmdcolin Apr 16, 2021
9bdaf34
Update snaps
cmdcolin Apr 16, 2021
bb46a93
No warn
cmdcolin Apr 16, 2021
9a5ed0a
Silence warnings because BaseFeatureWidget uses safeReference to view…
cmdcolin Apr 16, 2021
8a8c039
Silence some warnings during tests
cmdcolin Apr 16, 2021
1db29ef
Add some timeout
cmdcolin Apr 16, 2021
e891114
Allow performance label for the github label triager
cmdcolin Apr 16, 2021
cc6c2ba
Merge origin/main
cmdcolin Apr 19, 2021
b2faeb6
Merge origin/main
cmdcolin Apr 19, 2021
dbb2a5c
Merge remote-tracking branch 'origin/main' into lazyreact
cmdcolin Apr 20, 2021
2a985e0
Unused suspense in test, clean up some types
cmdcolin Apr 20, 2021
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
22 changes: 20 additions & 2 deletions .github/workflows/push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ jobs:
run: |
cd website/
yarn build
buildjbrowseweb:
name: Build jbrowse-web on node 10.x and ubuntu-latest
buildwholerepo:
name: Build whole repo on node 10.x and ubuntu-latest
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
Expand All @@ -53,6 +53,24 @@ jobs:
run: yarn build
- name: Test build
run: BUILT_TESTS=1 yarn built-test-ci

buildjbrowseweb:
name: Build only jbrowse-web and upload to s3 on node 10.x and ubuntu-latest
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Use Node.js 10.x
uses: actions/setup-node@v1
with:
node-version: 10.x
- name: Install deps (with cache)
uses: bahmutov/npm-install@v1
- name: Build project
run: |
echo $RELEASE_VERSION
cd products/jbrowse-web/
NODE_OPTIONS='--max-old-space-size=6500' yarn build
cd ../../
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
Expand Down
30 changes: 15 additions & 15 deletions packages/core/BaseFeatureWidget/BaseFeatureDetail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -421,21 +421,6 @@ function isEmpty(obj: Record<string, unknown>) {
return Object.keys(obj).length === 0
}

export const BaseFeatureDetails = observer((props: BaseInputProps) => {
const { model } = props
const { featureData } = model

if (!featureData) {
return null
}
const feature = JSON.parse(JSON.stringify(featureData))

if (isEmpty(feature)) {
return null
}
return <FeatureDetails model={model} feature={feature} />
})

export const FeatureDetails = (props: {
model: IAnyStateTreeNode
feature: SimpleFeatureSerialized & { name?: string; id?: string }
Expand Down Expand Up @@ -499,3 +484,18 @@ export const FeatureDetails = (props: {
</BaseCard>
)
}

export default observer((props: BaseInputProps) => {
cmdcolin marked this conversation as resolved.
Show resolved Hide resolved
const { model } = props
const { featureData } = model

if (!featureData) {
return null
}
const feature = JSON.parse(JSON.stringify(featureData))

if (isEmpty(feature)) {
return null
}
return <FeatureDetails model={model} feature={feature} />
})
8 changes: 5 additions & 3 deletions packages/core/BaseFeatureWidget/index.test.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import React, { Suspense } from 'react'
import { render } from '@testing-library/react'
import React from 'react'
import { types } from 'mobx-state-tree'
import { ConfigurationSchema } from '@jbrowse/core/configuration'
import PluginManager from '../PluginManager'
import { stateModelFactory } from '.'
import { BaseFeatureDetails as ReactComponent } from './BaseFeatureDetail'
import BaseFeatureDetails from './BaseFeatureDetail'

test('open up a widget', () => {
console.warn = jest.fn()
Expand All @@ -20,7 +20,9 @@ test('open up a widget', () => {
widget: { type: 'BaseFeatureWidget' },
})
const { container, getByText } = render(
<ReactComponent model={model.widget} />,
<Suspense fallback={<div>Loading...</div>}>
<BaseFeatureDetails model={model.widget} />
</Suspense>,
cmdcolin marked this conversation as resolved.
Show resolved Hide resolved
)
model.widget.setFeatureData({
start: 2,
Expand Down
1 change: 0 additions & 1 deletion packages/core/BaseFeatureWidget/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,3 @@ export default function stateModelFactory(pluginManager: PluginManager) {
}

export { configSchema, stateModelFactory }
export { BaseFeatureDetails as ReactComponent } from './BaseFeatureDetail'
15 changes: 15 additions & 0 deletions packages/core/CorePlugin.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { lazy } from 'react'
import { configSchema, stateModelFactory } from './BaseFeatureWidget'
import Plugin from './Plugin'
import PluginManager from './PluginManager'
import * as coreRpcMethods from './rpc/coreRpcMethods'
import WidgetType from './pluggableElementTypes/WidgetType'

/** the core plugin, which registers types that ALL JBrowse applications are expected to need. */
export default class CorePlugin extends Plugin {
Expand All @@ -11,5 +14,17 @@ export default class CorePlugin extends Plugin {
Object.values(coreRpcMethods).forEach(RpcMethod => {
pluginManager.addRpcMethod(() => new RpcMethod(pluginManager))
})

pluginManager.addWidgetType(() => {
return new WidgetType({
name: 'BaseFeatureWidget',
heading: 'Feature details',
configSchema,
stateModel: stateModelFactory(pluginManager),
ReactComponent: lazy(
() => import('./BaseFeatureWidget/BaseFeatureDetail'),
),
})
})
}
}
10 changes: 0 additions & 10 deletions packages/core/pluggableElementTypes/models/BaseTrackModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,6 @@ export function createBaseTrackModel(
pluginManager.pluggableMstType('display', 'stateModel'),
),
})
.volatile(() => ({
DialogComponent: undefined as React.FC | undefined,
DialogDisplay: undefined as any,
}))
.actions(self => ({
setDialogComponent(dlg?: React.FC, context?: any) {
self.DialogComponent = dlg
self.DialogDisplay = context
},
}))
.views(self => ({
get rpcSessionId() {
return self.configuration.trackId
Expand Down
59 changes: 35 additions & 24 deletions packages/core/ui/App.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
/* eslint-disable react/prop-types */
import React from 'react'
import AppBar from '@material-ui/core/AppBar'
import { makeStyles } from '@material-ui/core/styles'
import Fab from '@material-ui/core/Fab'
import React, { Suspense } from 'react'
import { AppBar, Fab, Toolbar, Tooltip, makeStyles } from '@material-ui/core'
import LaunchIcon from '@material-ui/icons/Launch'
import Toolbar from '@material-ui/core/Toolbar'
import Tooltip from '@material-ui/core/Tooltip'
import { observer } from 'mobx-react'
import { getEnv } from 'mobx-state-tree'
import DrawerWidget from './DrawerWidget'
Expand Down Expand Up @@ -82,16 +77,22 @@ const useStyles = makeStyles(theme => ({
},
}))

function App({ session, HeaderButtons }) {
export default observer(({ session, HeaderButtons }) => {
const classes = useStyles()
const { pluginManager } = getEnv(session)
const { visibleWidget, drawerWidth, minimized, activeWidgets } = session
const {
visibleWidget,
drawerWidth,
minimized,
activeWidgets,
savedSessionNames,
name,
menus,
views,
} = session

function handleNameChange(newName) {
if (
session.savedSessionNames &&
session.savedSessionNames.includes(newName)
) {
if (savedSessionNames && savedSessionNames.includes(newName)) {
session.notify(
`Cannot rename session to "${newName}", a saved session with that name already exists`,
'warning',
Expand All @@ -109,11 +110,19 @@ function App({ session, HeaderButtons }) {
}`,
}}
>
{session.DialogComponent ? (
<Suspense fallback={<div />}>
<session.DialogComponent
handleClose={() => session.setDialogComponent(undefined, undefined)}
{...session.DialogProps}
/>
</Suspense>
) : null}
<div className={classes.menuBarAndComponents}>
<div className={classes.menuBar}>
<AppBar className={classes.appBar} position="static">
<Toolbar>
{session.menus.map(menu => (
{menus.map(menu => (
<DropDownMenu
key={menu.label}
menuTitle={menu.label}
Expand All @@ -124,7 +133,7 @@ function App({ session, HeaderButtons }) {
<div className={classes.grow} />
<Tooltip title="Rename Session" arrow>
<EditableTypography
value={session.name}
value={name}
setValue={handleNameChange}
variant="body1"
classes={{
Expand All @@ -143,7 +152,7 @@ function App({ session, HeaderButtons }) {
</AppBar>
</div>
<div className={classes.components}>
{session.views.map(view => {
{views.map(view => {
const viewType = pluginManager.getViewType(view.type)
if (!viewType) {
throw new Error(`unknown view type ${view.type}`)
Expand All @@ -155,14 +164,18 @@ function App({ session, HeaderButtons }) {
view={view}
onClose={() => session.removeView(view)}
>
<ReactComponent
model={view}
session={session}
getTrackType={pluginManager.getTrackType}
/>
<Suspense fallback={<div>Loading...</div>}>
<ReactComponent
model={view}
session={session}
getTrackType={pluginManager.getTrackType}
/>
</Suspense>
</ViewContainer>
)
})}

{/* blank space at the bottom of screen allows scroll */}
<div style={{ height: 300 }} />
</div>
</div>
Expand All @@ -189,6 +202,4 @@ function App({ session, HeaderButtons }) {
<Snackbar session={session} />
</div>
)
}

export default observer(App)
})
14 changes: 8 additions & 6 deletions packages/core/ui/DrawerWidget.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState } from 'react'
import React, { Suspense, useState } from 'react'
import {
AppBar,
IconButton,
Expand Down Expand Up @@ -162,11 +162,13 @@ export default observer(({ session }) => {
return (
<Drawer session={session} open={Boolean(activeWidgets.size)}>
<DrawerHeader session={session} setToolbarHeight={setToolbarHeight} />
<ReactComponent
model={visibleWidget}
session={session}
toolbarHeight={toolbarHeight}
/>
<Suspense fallback={<div>Loading...</div>}>
<ReactComponent
model={visibleWidget}
session={session}
toolbarHeight={toolbarHeight}
/>
</Suspense>
</Drawer>
)
})
Loading