Skip to content

Commit

Permalink
fix: preload to return the same promise
Browse files Browse the repository at this point in the history
  • Loading branch information
theKashey committed Dec 6, 2018
1 parent 7bc0b0d commit 9a75a4b
Show file tree
Hide file tree
Showing 4 changed files with 50 additions and 11 deletions.
27 changes: 23 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ const Component = importedComponent( () => import('./Component'), {
ErrorComponent: FatalError
});

Component.preload();
Component.preload(); // force preload

// render it
<Component... />
Expand Down Expand Up @@ -79,7 +79,7 @@ Example: [React.lazy vs Imported-component](https://codesandbox.io/s/wkl95r0qw8)

- importedComponent`.preload` - static method to preload components.

- `lazy` - helper to mimic __React.lazy__ behavior, just _importedComponent_(fn, { async: true }).
- `lazy` - helper to mimic __React.lazy__ behavior (it is just `_importedComponent_(fn, { async: true })`).

- `ComponentLoader`, the React Component variant of importedComponent. accepts `importFunction` as a `loadable` prop.

Expand Down Expand Up @@ -306,6 +306,26 @@ resolve the promise.
It is super-not-fast, and you will literally re-render everything twice, but it works
(almost the same approach as react-async-component has).

### Works better in pair
You might not need to wait for all the chunks to be loaded before you can render you app -
just use [react-prerendered-component](https://github.com/theKashey/react-prerendered-component).
```js
import imported from 'react-imported-component';
import {PrerenderedComponent} from "react-prerendered-component";

const AsyncComponent = imported(() => import('./myComponent.js'));

<PrerenderedComponent
// component will "go live" when chunk loading would be done
live={AsyncComponent.preload()}
>
// until component is not "live" prerendered HTML code would be used
// that's why you need to `preload`
<AsyncComponent/>
</PrerenderedComponent>

```


## Comparison
* React.lazy
Expand All @@ -331,8 +351,7 @@ It is super-not-fast, and you will literally re-render everything twice, but it
* The most complex(inside) one. Just piece of Art.
* Loader: import only
* Front-end: RHL-friendly. (by forced preloading)
* SSR: semi-async(walkTree), __no wave reduction__, sees only currently loaded chunks.
* Simple HOC based API
* SSR: sync, webpack-bound.
* Support Suspense

* [react-universal-component](https://github.com/faceyspacey/react-universal-component)
Expand Down
17 changes: 13 additions & 4 deletions module.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,15 @@ declare module 'react-imported-component' {

type DefaultComponent<P> = ComponentType<P> | DefaultImportedComponent<P>;

type LoadableComponentState ='loading' | 'done' | 'error';
type LoadableComponentState = 'loading' | 'done' | 'error';

type ComponentRenderOption<P, K> = (Component: P, State: LoadableComponentState, props: K) => ReactNode;

type AdditionalHOC<T> = {
preload(): Promise<T>;
done: Promise<T>;
}

type ComponentOptions<P, K, RenderComponent = ComponentType<P>> = {
LoadingComponent?: ComponentType<any>,
ErrorComponent?: ComponentType<any>,
Expand All @@ -22,10 +27,12 @@ declare module 'react-imported-component' {
forwardRef?: Ref<P>;
}

type HOCType<P, K> = ComponentType<P | K> & AdditionalHOC<DefaultComponent<P>>;

interface HOC {
<P, K={}>(loader: () => Promise<DefaultComponent<P>>, options?: ComponentOptions<P, K>): ComponentType<P | K>;
<P, K = {}>(loader: () => Promise<DefaultComponent<P>>, options?: ComponentOptions<P, K>): HOCType<P, K>;

<P, K={}>(loader: () => Promise<P>, options?: ComponentOptions<P, K, P> & { render: ComponentRenderOption<P, K> }): ComponentType<K>;
<P, K = {}>(loader: () => Promise<P>, options?: ComponentOptions<P, K, P> & { render: ComponentRenderOption<P, K> }): HOCType<P, K>;
}

const importedComponent: HOC;
Expand All @@ -48,6 +55,8 @@ declare module 'react-imported-component' {

export default importedComponent;

export function lazy<P>(loader: () => Promise<DefaultComponent<P>>): HOCType<P, {}>;

export function printDrainHydrateMarks(streamId?: number): string;

export function drainHydrateMarks(streamId?: number): Array<string>;
Expand All @@ -62,5 +71,5 @@ declare module 'react-imported-component' {

export function loadableResource<P>(loader: () => Promise<DefaultComponent<P>>): LoadableResource<P>;

export function setConfiguration(config: {SSR?: boolean, hot?: boolean}): void;
export function setConfiguration(config: { SSR?: boolean, hot?: boolean }): void;
}
8 changes: 6 additions & 2 deletions src/HOC.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,15 @@ const loader = (loaderFunction, options = {}) => {
))
: ImportedComponent;

Imported.preload = () => loadable.load().catch(() => ({}));
Imported.preload = () => {
loadable.load().catch(() => ({}));
return loadable.resolution;
};
Imported.done = loadable.resolution;

return Imported;
};

export const lazy = loaderFunction => loader(loaderFunction, { async: true });
export const lazy = loaderFunction => loader(loaderFunction, {async: true});

export default loader;
9 changes: 8 additions & 1 deletion src/loadable.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,22 @@ const trimImport = str => str.replace(/['"]/g, '');

export const importMatch = functionString => {
const markMatches = functionString.match(/\(['"]imported-component['"],\s['"](.*),/g) || [];
return markMatches.map( match => trimImport(match.match(/\(['"]imported-component['"],\s['"]([^'"]*)['"],/i)[1]));
return markMatches.map(match => trimImport(match.match(/\(['"]imported-component['"],\s['"]([^'"]*)['"],/i)[1]));
}

const toLoadable = (importFunction, autoImport = true) => {
const _load = () => Promise.resolve().then(importFunction);
const mark = importMatch(importFunction.toString());

let resolveResolution;
const resolution = new Promise(r => {
resolveResolution = r;
});

const loadable = {
importFunction,
mark,
resolution,
done: false,
ok: false,
error: null,
Expand All @@ -41,6 +47,7 @@ const toLoadable = (importFunction, autoImport = true) => {
this.payload = payload;
this.error = null;
removeFromPending(promise);
resolveResolution(payload);
return payload;
}, (err) => {
this.done = true;
Expand Down

0 comments on commit 9a75a4b

Please sign in to comment.