Merge pull request #6768 from tchak/refactor-js-imports
refactor(js): use dynamic import
This commit is contained in:
commit
52750f1800
17 changed files with 140 additions and 77 deletions
|
@ -1,24 +0,0 @@
|
|||
import React, { Suspense, lazy } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const Loader = () => <div className="spinner left" />;
|
||||
|
||||
function LazyLoad({ component: Component, ...props }) {
|
||||
return (
|
||||
<Suspense fallback={<Loader />}>
|
||||
<Component {...props} />
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
|
||||
LazyLoad.propTypes = {
|
||||
component: PropTypes.object
|
||||
};
|
||||
|
||||
export default function Loadable(loader) {
|
||||
const LazyComponent = lazy(loader);
|
||||
|
||||
return function PureComponent(props) {
|
||||
return <LazyLoad component={LazyComponent} {...props} />;
|
||||
};
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
import Loadable from '../components/Loadable';
|
||||
|
||||
export default Loadable(() => import('../components/Chartkick'));
|
|
@ -1,3 +0,0 @@
|
|||
import Loadable from '../components/Loadable';
|
||||
|
||||
export default Loadable(() => import('../components/ComboAdresseSearch'));
|
|
@ -1,5 +0,0 @@
|
|||
import Loadable from '../components/Loadable';
|
||||
|
||||
export default Loadable(() =>
|
||||
import('../components/ComboAnnuaireEducationSearch')
|
||||
);
|
|
@ -1,3 +0,0 @@
|
|||
import Loadable from '../components/Loadable';
|
||||
|
||||
export default Loadable(() => import('../components/ComboCommunesSearch'));
|
|
@ -1,3 +0,0 @@
|
|||
import Loadable from '../components/Loadable';
|
||||
|
||||
export default Loadable(() => import('../components/ComboDepartementsSearch'));
|
|
@ -1,5 +0,0 @@
|
|||
import Loadable from '../components/Loadable';
|
||||
|
||||
export default Loadable(() =>
|
||||
import('../components/ComboMultipleDropdownList')
|
||||
);
|
|
@ -1,3 +0,0 @@
|
|||
import Loadable from '../components/Loadable';
|
||||
|
||||
export default Loadable(() => import('../components/ComboPaysSearch'));
|
|
@ -1,3 +0,0 @@
|
|||
import Loadable from '../components/Loadable';
|
||||
|
||||
export default Loadable(() => import('../components/ComboRegionsSearch'));
|
|
@ -1,3 +0,0 @@
|
|||
import Loadable from '../components/Loadable';
|
||||
|
||||
export default Loadable(() => import('../components/MapEditor'));
|
|
@ -1,3 +0,0 @@
|
|||
import Loadable from '../components/Loadable';
|
||||
|
||||
export default Loadable(() => import('../components/MapReader'));
|
|
@ -1,3 +0,0 @@
|
|||
import Loadable from '../components/Loadable';
|
||||
|
||||
export default Loadable(() => import('../components/Trix'));
|
|
@ -1,3 +0,0 @@
|
|||
import Loadable from '../components/Loadable';
|
||||
|
||||
export default Loadable(() => import('../components/TypesDeChampEditor'));
|
|
@ -2,7 +2,6 @@ import '../shared/polyfills';
|
|||
import Rails from '@rails/ujs';
|
||||
import * as ActiveStorage from '@rails/activestorage';
|
||||
import 'whatwg-fetch'; // window.fetch polyfill
|
||||
import ReactRailsUJS from 'react_ujs';
|
||||
|
||||
import '../shared/page-update-event';
|
||||
import '../shared/activestorage/ujs';
|
||||
|
@ -48,6 +47,38 @@ import {
|
|||
showNewAccountPasswordConfirmation
|
||||
} from '../new_design/fc-fusion';
|
||||
|
||||
import {
|
||||
registerReactComponents,
|
||||
Loadable
|
||||
} from '../shared/register-react-components';
|
||||
|
||||
registerReactComponents({
|
||||
Chartkick: Loadable(() => import('../components/Chartkick')),
|
||||
ComboAdresseSearch: Loadable(() =>
|
||||
import('../components/ComboAdresseSearch')
|
||||
),
|
||||
ComboAnnuaireEducationSearch: Loadable(() =>
|
||||
import('../components/ComboAnnuaireEducationSearch')
|
||||
),
|
||||
ComboCommunesSearch: Loadable(() =>
|
||||
import('../components/ComboCommunesSearch')
|
||||
),
|
||||
ComboDepartementsSearch: Loadable(() =>
|
||||
import('../components/ComboDepartementsSearch')
|
||||
),
|
||||
ComboMultipleDropdownList: Loadable(() =>
|
||||
import('../components/ComboMultipleDropdownList')
|
||||
),
|
||||
ComboPaysSearch: Loadable(() => import('../components/ComboPaysSearch')),
|
||||
ComboRegionsSearch: Loadable(() =>
|
||||
import('../components/ComboRegionsSearch')
|
||||
),
|
||||
MapEditor: Loadable(() => import('../components/MapEditor')),
|
||||
MapReader: Loadable(() => import('../components/MapReader')),
|
||||
Trix: Loadable(() => import('../components/Trix')),
|
||||
TypesDeChampEditor: Loadable(() => import('../components/TypesDeChampEditor'))
|
||||
});
|
||||
|
||||
// This is the global application namespace where we expose helpers used from rails views
|
||||
const DS = {
|
||||
fire: (eventName, data) => Rails.fire(document, eventName, data),
|
||||
|
@ -69,7 +100,3 @@ ActiveStorage.start();
|
|||
|
||||
// Expose globals
|
||||
window.DS = window.DS || DS;
|
||||
|
||||
// eslint-disable-next-line no-undef, react-hooks/rules-of-hooks
|
||||
ReactRailsUJS.useContext(require.context('loaders', true));
|
||||
addEventListener('ds:page:update', ReactRailsUJS.handleMount);
|
||||
|
|
108
app/javascript/shared/register-react-components.jsx
Normal file
108
app/javascript/shared/register-react-components.jsx
Normal file
|
@ -0,0 +1,108 @@
|
|||
import React, { Suspense, lazy, createElement } from 'react';
|
||||
import { render } from 'react-dom';
|
||||
|
||||
// This attribute holds the name of component which should be mounted
|
||||
// example: `data-react-class="MyApp.Items.EditForm"`
|
||||
const CLASS_NAME_ATTR = 'data-react-class';
|
||||
|
||||
// This attribute holds JSON stringified props for initializing the component
|
||||
// example: `data-react-props="{\"item\": { \"id\": 1, \"name\": \"My Item\"} }"`
|
||||
const PROPS_ATTR = 'data-react-props';
|
||||
|
||||
// A unique identifier to identify a node
|
||||
const CACHE_ID_ATTR = 'data-react-cache-id';
|
||||
|
||||
const CLASS_NAME_SELECTOR = `[${CLASS_NAME_ATTR}]`;
|
||||
|
||||
// helper method for the mount and unmount methods to find the
|
||||
// `data-react-class` DOM elements
|
||||
function findDOMNodes(searchSelector) {
|
||||
const [selector, parent] = getSelector(searchSelector);
|
||||
return parent.querySelectorAll(selector);
|
||||
}
|
||||
|
||||
function getSelector(searchSelector) {
|
||||
switch (typeof searchSelector) {
|
||||
case 'undefined':
|
||||
return [CLASS_NAME_SELECTOR, document];
|
||||
case 'object':
|
||||
return [CLASS_NAME_SELECTOR, searchSelector];
|
||||
case 'string':
|
||||
return [
|
||||
['', ' ']
|
||||
.map(
|
||||
(separator) => `${searchSelector}${separator}${CLASS_NAME_SELECTOR}`
|
||||
)
|
||||
.join(', '),
|
||||
document
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
class ReactComponentRegistry {
|
||||
#cache = {};
|
||||
#components;
|
||||
|
||||
constructor(components) {
|
||||
this.#components = components;
|
||||
}
|
||||
|
||||
getConstructor(className) {
|
||||
return this.#components[className];
|
||||
}
|
||||
|
||||
mountComponents(searchSelector) {
|
||||
const nodes = findDOMNodes(searchSelector);
|
||||
|
||||
for (const node of nodes) {
|
||||
const className = node.getAttribute(CLASS_NAME_ATTR);
|
||||
const ComponentClass = this.getConstructor(className);
|
||||
const propsJson = node.getAttribute(PROPS_ATTR);
|
||||
const props = propsJson && JSON.parse(propsJson);
|
||||
const cacheId = node.getAttribute(CACHE_ID_ATTR);
|
||||
|
||||
if (!ComponentClass) {
|
||||
const message = `Cannot find component: "${className}"`;
|
||||
console?.log(
|
||||
`%c[react-rails] %c${message} for element`,
|
||||
'font-weight: bold',
|
||||
'',
|
||||
node
|
||||
);
|
||||
throw new Error(
|
||||
`${message}. Make sure your component is available to render.`
|
||||
);
|
||||
} else {
|
||||
let component = this.#cache[cacheId];
|
||||
if (!component) {
|
||||
this.#cache[cacheId] = component = createElement(
|
||||
ComponentClass,
|
||||
props
|
||||
);
|
||||
}
|
||||
|
||||
render(component, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const Loader = () => <div className="spinner left" />;
|
||||
|
||||
export function Loadable(loader) {
|
||||
const LazyComponent = lazy(loader);
|
||||
|
||||
return function PureComponent(props) {
|
||||
return (
|
||||
<Suspense fallback={<Loader />}>
|
||||
<LazyComponent {...props} />
|
||||
</Suspense>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
export function registerReactComponents(components) {
|
||||
const registry = new ReactComponentRegistry(components);
|
||||
|
||||
addEventListener('ds:page:update', () => registry.mountComponents());
|
||||
}
|
|
@ -36,7 +36,6 @@
|
|||
"react-popper": "^2.2.5",
|
||||
"react-query": "^3.9.7",
|
||||
"react-sortable-hoc": "^1.11.0",
|
||||
"react_ujs": "^2.6.1",
|
||||
"trix": "^1.2.3",
|
||||
"use-debounce": "^5.2.0",
|
||||
"webpack": "^4.46.0",
|
||||
|
|
|
@ -12394,13 +12394,6 @@ react@^17.0.1:
|
|||
loose-envify "^1.1.0"
|
||||
object-assign "^4.1.1"
|
||||
|
||||
react_ujs@^2.6.0, react_ujs@^2.6.1:
|
||||
version "2.6.1"
|
||||
resolved "https://registry.yarnpkg.com/react_ujs/-/react_ujs-2.6.1.tgz#a202a33c95c9e2bb18ab56926b7e79f3325ec855"
|
||||
integrity sha512-9M33/A8cubStkZ2cpJSimcTD0RlCWiqXF6e90IQmMw/Caf/W0dtAzOtHtiQE3JjLbt/nhRR7NLPxMfnlm141ig==
|
||||
dependencies:
|
||||
react_ujs "^2.6.0"
|
||||
|
||||
read-cache@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/read-cache/-/read-cache-1.0.0.tgz#e664ef31161166c9751cdbe8dbcf86b5fb58f774"
|
||||
|
|
Loading…
Reference in a new issue