-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Async JavaScript Lazy Loading #899
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
Changes from 68 commits
6fbaa15
d4b56ab
937bc30
81408b9
3c1620d
d364090
42f6580
93cfc24
51b4ddf
a70f3c2
72fe8c2
3077b80
917f536
231765e
a387525
df362a1
8ee541a
10bde03
96cf8f5
659496f
4e787b6
cd1d1dc
9429047
cd69f6b
ba03895
35ba28a
953f65b
610ff28
b4e105a
9d24848
f32edbd
91771d1
58034cd
5478f83
9d95615
2f303af
ee608a0
ab5801f
be2eb1d
c5a1636
0a18d3c
24712eb
37e4c9e
4daa8eb
2c87000
deec3d6
42b62f4
766dad2
9b06789
99e437c
2650fa9
2ea2d48
1ce9792
3c3c81c
af35006
247bb64
3e13e82
884c74a
a598dae
8d6c137
0a6e4c6
8b864cb
92a5699
558bf6c
13e274e
1a7a470
7c3edaa
7852312
063185e
aa79b2f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
MIT License | ||
|
||
Copyright (c) 2019 Plotly | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
{ | ||
"name": "@plotly/dash-component-plugins", | ||
"version": "1.0.1", | ||
"description": "Plugins for Dash Components", | ||
"repository": { | ||
"type": "git", | ||
"url": "[email protected]:plotly/dash.git" | ||
}, | ||
"bugs": { | ||
"url": "https://github.com/plotly/dash/issues" | ||
}, | ||
"homepage": "https://github.com/plotly/dash", | ||
"main": "src/index.js", | ||
"author": "Marc-André Rivet", | ||
"license": "MIT" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import { lazy } from 'react'; | ||
|
||
export const asyncDecorator = (target, promise) => { | ||
let resolve; | ||
const isReady = new Promise(r => { | ||
resolve = r; | ||
}); | ||
|
||
const state = { | ||
isReady, | ||
get: lazy(() => { | ||
return Promise.resolve(promise()).then(res => { | ||
setTimeout(async () => { | ||
await resolve(true); | ||
state.isReady = true; | ||
}, 0); | ||
|
||
return res; | ||
}); | ||
}), | ||
}; | ||
|
||
Object.defineProperty(target, '_dashprivate_isLazyComponentReady', { | ||
get: () => state.isReady, | ||
}); | ||
|
||
return state.get; | ||
}; | ||
|
||
export const isReady = target => target && | ||
target._dashprivate_isLazyComponentReady; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import { asyncDecorator, isReady } from './dynamicImport'; | ||
|
||
export { asyncDecorator, isReady }; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
MIT License | ||
|
||
Copyright (c) 2019 Plotly | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
{ | ||
"name": "@plotly/webpack-dash-dynamic-import", | ||
"version": "1.0.0", | ||
"description": "Webpack Plugin for Dynamic Import in Dash", | ||
"repository": { | ||
"type": "git", | ||
"url": "[email protected]:plotly/dash.git" | ||
}, | ||
"bugs": { | ||
"url": "https://github.com/plotly/dash/issues" | ||
}, | ||
"homepage": "https://github.com/plotly/dash", | ||
"main": "src/index.js", | ||
"author": "Marc-André Rivet", | ||
"license": "MIT" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
const resolveImportSource = `\ | ||
Object.defineProperty(__webpack_require__, 'p', { | ||
get: (function () { | ||
let script = document.currentScript; | ||
if (!script) { | ||
/* Shim for IE11 and below */ | ||
/* Do not take into account async scripts and inline scripts */ | ||
const scripts = Array.from(document.getElementsByTagName('script')).filter(function(s) { return !s.async && !s.text && !s.textContent; }); | ||
script = scripts.slice(-1)[0]; | ||
} | ||
|
||
var url = script.src.split('/').slice(0, -1).join('/') + '/'; | ||
|
||
return function() { | ||
return url; | ||
}; | ||
})() | ||
});` | ||
|
||
class WebpackDashDynamicImport { | ||
apply(compiler) { | ||
compiler.hooks.compilation.tap('WebpackDashDynamicImport', compilation => { | ||
compilation.mainTemplate.hooks.requireExtensions.tap('WebpackDashDynamicImport > RequireExtensions', (source, chunk, hash) => { | ||
return [ | ||
source, | ||
resolveImportSource | ||
] | ||
}); | ||
}); | ||
} | ||
} | ||
|
||
module.exports = WebpackDashDynamicImport; |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
module.exports = { | ||
presets: [['@babel/preset-env', { | ||
useBuiltIns: 'usage', | ||
corejs: 3 | ||
}], '@babel/preset-react'], | ||
env: { | ||
test: { | ||
plugins: [ | ||
'@babel/plugin-transform-modules-commonjs' | ||
] | ||
} | ||
} | ||
}; |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,18 +33,21 @@ import cookie from 'cookie'; | |
import {uid, urlBase, isMultiOutputProp, parseMultipleOutputs} from '../utils'; | ||
import {STATUS} from '../constants/constants'; | ||
import {applyPersistence, prunePersistence} from '../persistence'; | ||
import setAppIsReady from './setAppReadyState'; | ||
|
||
export const updateProps = createAction(getAction('ON_PROP_CHANGE')); | ||
export const setRequestQueue = createAction(getAction('SET_REQUEST_QUEUE')); | ||
export const computeGraphs = createAction(getAction('COMPUTE_GRAPHS')); | ||
export const computePaths = createAction(getAction('COMPUTE_PATHS')); | ||
export const setLayout = createAction(getAction('SET_LAYOUT')); | ||
export const setAppLifecycle = createAction(getAction('SET_APP_LIFECYCLE')); | ||
export const setConfig = createAction(getAction('SET_CONFIG')); | ||
export const setHooks = createAction(getAction('SET_HOOKS')); | ||
export const setLayout = createAction(getAction('SET_LAYOUT')); | ||
export const onError = createAction(getAction('ON_ERROR')); | ||
export const resolveError = createAction(getAction('RESOLVE_ERROR')); | ||
|
||
export {setAppIsReady}; | ||
|
||
export function hydrateInitialOutputs() { | ||
return function(dispatch, getState) { | ||
triggerDefaultState(dispatch, getState); | ||
|
@@ -176,7 +179,7 @@ function reduceInputIds(nodeIds, InputGraph) { | |
/* | ||
* Create input-output(s) pairs, | ||
* sort by number of outputs, | ||
* and remove redudant inputs (inputs that update the same output) | ||
Marc-Andre-Rivet marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* and remove redundant inputs (inputs that update the same output) | ||
*/ | ||
const inputOutputPairs = nodeIds.map(nodeId => ({ | ||
input: nodeId, | ||
|
@@ -195,7 +198,7 @@ function reduceInputIds(nodeIds, InputGraph) { | |
* trigger components to update multiple times. | ||
* | ||
* For example, [A, B] => C and [A, D] => E | ||
* The unique inputs might be [A, B, D] but that is redudant. | ||
* The unique inputs might be [A, B, D] but that is redundant. | ||
* We only need to update B and D or just A. | ||
* | ||
* In these cases, we'll supply an additional list of outputs | ||
|
@@ -216,10 +219,15 @@ function reduceInputIds(nodeIds, InputGraph) { | |
} | ||
|
||
export function notifyObservers(payload) { | ||
return function(dispatch, getState) { | ||
return async function(dispatch, getState) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. notifyObservers may now have to wait defensively before sending callbacks |
||
const {id, props, excludedOutputs} = payload; | ||
|
||
const {graphs, requestQueue} = getState(); | ||
const {graphs, isAppReady, requestQueue} = getState(); | ||
|
||
if (isAppReady !== true) { | ||
await isAppReady; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If a known component is not ready, wait for it |
||
|
||
const {InputGraph} = graphs; | ||
/* | ||
* Figure out all of the output id's that depend on this input. | ||
|
@@ -907,6 +915,8 @@ function updateOutput( | |
); | ||
}); | ||
} | ||
|
||
dispatch(setAppIsReady()); | ||
alexcjohnson marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
}; | ||
if (multi) { | ||
|
Uh oh!
There was an error while loading. Please reload this page.