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

Remove dynamic loading. #2783

Merged
merged 4 commits into from
Mar 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@
All notable changes to `dash` will be documented in this file.
This project adheres to [Semantic Versioning](https://semver.org/).

## [UNRELEASED]

## Fixed

- [#2783](https://github.com/plotly/dash/pull/2783) Remove dynamic loading.

## [2.16.0] - 2024-03-01

## Fixed
Expand Down
8 changes: 8 additions & 0 deletions dash/_validate.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import sys
from collections.abc import MutableSequence
import re
from textwrap import dedent
Expand Down Expand Up @@ -356,6 +357,13 @@ def check_obsolete(kwargs):
See https://dash.plotly.com for details.
"""
)
if key in ["dynamic_loading", "preloaded_libraries"]:
# Only warns as this was only available for a short time.
print(
f"{key} has been removed and no longer a valid keyword argument in Dash.",
file=sys.stderr,
)
continue
# any other kwarg mimic the built-in exception
raise TypeError(f"Dash() got an unexpected keyword argument '{key}'")

Expand Down
44 changes: 10 additions & 34 deletions dash/dash-renderer/src/APIController.react.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
import {batch, connect} from 'react-redux';
import {includes, isEmpty} from 'ramda';
import React, {
useEffect,
useRef,
useState,
createContext,
useCallback
} from 'react';
import React, {useEffect, useRef, useState, createContext} from 'react';
import PropTypes from 'prop-types';
import TreeContainer from './TreeContainer';
import GlobalErrorContainer from './components/error/GlobalErrorContainer.react';
Expand All @@ -27,7 +21,6 @@ import {getAppState} from './reducers/constants';
import {STATUS} from './constants/constants';
import {getLoadingState, getLoadingHash} from './utils/TreeContainer';
import wait from './utils/wait';
import LibraryManager from './libraries/LibraryManager';

export const DashContext = createContext({});

Expand All @@ -53,10 +46,6 @@ const UnconnectedContainer = props => {
if (!events.current) {
events.current = new EventEmitter();
}

const [libraryReady, setLibraryReady] = useState(false);
const onLibraryReady = useCallback(() => setLibraryReady(true), []);

const renderedTree = useRef(false);

const propsRef = useRef({});
Expand All @@ -71,9 +60,7 @@ const UnconnectedContainer = props => {
})
});

useEffect(
storeEffect.bind(null, props, events, setErrorLoading, libraryReady)
);
useEffect(storeEffect.bind(null, props, events, setErrorLoading));

useEffect(() => {
if (renderedTree.current) {
Expand Down Expand Up @@ -130,23 +117,14 @@ const UnconnectedContainer = props => {
content = <div className='_dash-loading'>Loading...</div>;
}

return (
<LibraryManager
requests_pathname_prefix={config.requests_pathname_prefix}
onReady={onLibraryReady}
ready={libraryReady}
layout={layoutRequest && layoutRequest.content}
>
{config && config.ui === true ? (
<GlobalErrorContainer>{content}</GlobalErrorContainer>
) : (
content
)}
</LibraryManager>
return config && config.ui === true ? (
<GlobalErrorContainer>{content}</GlobalErrorContainer>
) : (
content
);
};

function storeEffect(props, events, setErrorLoading, libraryReady) {
function storeEffect(props, events, setErrorLoading) {
const {
appLifecycle,
dependenciesRequest,
Expand All @@ -165,7 +143,7 @@ function storeEffect(props, events, setErrorLoading, libraryReady) {
}
dispatch(apiThunk('_dash-layout', 'GET', 'layoutRequest'));
} else if (layoutRequest.status === STATUS.OK) {
if (isEmpty(layout) && libraryReady) {
if (isEmpty(layout)) {
if (typeof hooks.layout_post === 'function') {
hooks.layout_post(layoutRequest.content);
}
Expand Down Expand Up @@ -208,8 +186,7 @@ function storeEffect(props, events, setErrorLoading, libraryReady) {
layoutRequest.status === STATUS.OK &&
!isEmpty(layout) &&
// Hasn't already hydrated
appLifecycle === getAppState('STARTED') &&
libraryReady
appLifecycle === getAppState('STARTED')
) {
let hasError = false;
try {
Expand Down Expand Up @@ -258,8 +235,7 @@ const Container = connect(
graphs: state.graphs,
history: state.history,
error: state.error,
config: state.config,
paths: state.paths
config: state.config
}),
dispatch => ({dispatch})
)(UnconnectedContainer);
Expand Down
30 changes: 0 additions & 30 deletions dash/dash-renderer/src/CheckedComponent.react.js

This file was deleted.

68 changes: 54 additions & 14 deletions dash/dash-renderer/src/TreeContainer.js
Original file line number Diff line number Diff line change
@@ -1,44 +1,79 @@
import React, {Component, memo, useContext} from 'react';
import PropTypes from 'prop-types';
import Registry from './registry';
import {propTypeErrorHandler} from './exceptions';
import {
addIndex,
assoc,
assocPath,
concat,
dissoc,
equals,
has,
isEmpty,
isNil,
has,
keys,
map,
mapObjIndexed,
path as rpath,
pathOr,
mergeRight,
pick,
pickBy,
propOr,
path as rpath,
pathOr,
type
} from 'ramda';
import {batch} from 'react-redux';

import {notifyObservers, updateProps, onError} from './actions';
import isSimpleComponent from './isSimpleComponent';
import {recordUiEdit} from './persistence';
import ComponentErrorBoundary from './components/error/ComponentErrorBoundary.react';
import checkPropTypes from './checkPropTypes';
import {getWatchedKeys, stringifyId} from './actions/dependencies';
import {
getLoadingHash,
getLoadingState,
validateComponent
} from './utils/TreeContainer';
import {DashContext} from './APIController.react';
import LibraryComponent from './libraries/LibraryComponent';
import {batch} from 'react-redux';

const NOT_LOADING = {
is_loading: false
};

function CheckedComponent(p) {
const {element, extraProps, props, children, type} = p;

const errorMessage = checkPropTypes(
element.propTypes,
props,
'component prop',
element
);
if (errorMessage) {
propTypeErrorHandler(errorMessage, props, type);
}

return createElement(element, props, extraProps, children);
}

CheckedComponent.propTypes = {
children: PropTypes.any,
element: PropTypes.any,
layout: PropTypes.any,
props: PropTypes.any,
extraProps: PropTypes.any,
id: PropTypes.string
};

function createElement(element, props, extraProps, children) {
const allProps = mergeRight(props, extraProps);
if (Array.isArray(children)) {
return React.createElement(element, allProps, ...children);
}
return React.createElement(element, allProps, children);
}

function isDryComponent(obj) {
return (
type(obj) === 'Object' &&
Expand Down Expand Up @@ -215,6 +250,8 @@ class BaseTreeContainer extends Component {
}
validateComponent(_dashprivate_layout);

const element = Registry.resolve(_dashprivate_layout);

// Hydrate components props
const childrenProps = pathOr(
[],
Expand Down Expand Up @@ -418,14 +455,17 @@ class BaseTreeContainer extends Component {
dispatch={_dashprivate_dispatch}
error={_dashprivate_error}
>
<LibraryComponent
children={children}
type={_dashprivate_layout.type}
namespace={_dashprivate_layout.namespace}
props={props}
extraProps={extraProps}
props_check={_dashprivate_config.props_check}
/>
{_dashprivate_config.props_check ? (
<CheckedComponent
children={children}
element={element}
props={props}
extraProps={extraProps}
type={_dashprivate_layout.type}
/>
) : (
createElement(element, props, extraProps, children)
)}
</ComponentErrorBoundary>
);
}
Expand Down
43 changes: 3 additions & 40 deletions dash/dash-renderer/src/actions/callbacks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import {
CallbackResponseData
} from '../types/callbacks';
import {isMultiValued, stringifyId, isMultiOutputProp} from './dependencies';
import {crawlLayout, urlBase} from './utils';
import {urlBase} from './utils';
import {getCSRFHeader} from '.';
import {createAction, Action} from 'redux-actions';
import {addHttpHeaders} from '../actions';
Expand All @@ -44,9 +44,6 @@ import {handlePatch, isPatch} from './patch';
import {getPath} from './paths';

import {requestDependencies} from './requestDependencies';
import loadLibrary from '../libraries/loadLibrary';
import fetchDist from '../libraries/fetchDist';
import {setLibraryLoaded} from './libraries';

export const addBlockedCallbacks = createAction<IBlockedCallback[]>(
CallbackActionType.AddBlocked
Expand Down Expand Up @@ -366,7 +363,6 @@ function handleServerside(
let runningOff: any;
let progressDefault: any;
let moreArgs = additionalArgs;
const libraries = Object.keys(getState().libraries);

if (running) {
sideUpdate(running.running, dispatch, paths);
Expand Down Expand Up @@ -512,41 +508,8 @@ function handleServerside(
}

if (!long || data.response !== undefined) {
const newLibs: string[] = [];
Object.values(data.response as any).forEach(
(newData: any) => {
Object.values(newData).forEach(newProp => {
crawlLayout(newProp, (c: any) => {
if (
c.namespace &&
!libraries.includes(c.namespace) &&
!newLibs.includes(c.namespace)
) {
newLibs.push(c.namespace);
}
});
});
}
);
if (newLibs.length) {
fetchDist(
getState().config.requests_pathname_prefix,
newLibs
)
.then(data => {
return Promise.all(data.map(loadLibrary));
})
.then(() => {
completeJob();
finishLine(data);
dispatch(
setLibraryLoaded({libraries: newLibs})
);
});
} else {
completeJob();
finishLine(data);
}
completeJob();
finishLine(data);
} else {
// Poll chain.
setTimeout(
Expand Down
10 changes: 0 additions & 10 deletions dash/dash-renderer/src/actions/libraries.ts

This file was deleted.

Loading