Skip to content

Commit

Permalink
feat: add ImportedController
Browse files Browse the repository at this point in the history
  • Loading branch information
theKashey committed Mar 4, 2021
1 parent 03165dc commit d67a211
Show file tree
Hide file tree
Showing 10 changed files with 101 additions and 14 deletions.
4 changes: 2 additions & 2 deletions .size-limit.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ module.exports = [
{
path: ['dist/es2015/entrypoints/index.js', 'dist/es2015/entrypoints/boot.js'],
ignore: ['tslib'],
limit: '3.9 KB',
limit: '4.1 KB',
},
{
path: 'dist/es2015/entrypoints/index.js',
ignore: ['tslib'],
limit: '3.6 KB',
limit: '3.8 KB',
},
{
path: 'dist/es2015/entrypoints/boot.js',
Expand Down
4 changes: 2 additions & 2 deletions .size.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
{
"name": "dist/es2015/entrypoints/index.js, dist/es2015/entrypoints/boot.js",
"passed": true,
"size": 3975
"size": 4187
},
{
"name": "dist/es2015/entrypoints/index.js",
"passed": true,
"size": 3606
"size": 3817
},
{
"name": "dist/es2015/entrypoints/boot.js",
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
"main": "dist/es5/entrypoints/index.js",
"jsnext:main": "dist/es2015/entrypoints/index.js",
"module": "dist/es2015/entrypoints/index.js",
"sideEffects": false,
"types": "dist/es5/entrypoints/index.d.ts",
"sideEffects": false,
"scripts": {
"build:ci": "lib-builder build && yarn size",
"build": "rm -Rf ./dist/* && lib-builder build && yarn size && yarn size:report",
Expand Down Expand Up @@ -79,7 +79,7 @@
"crc-32": "^1.2.0",
"detect-node-es": "^1.0.0",
"scan-directory": "^2.0.0",
"tslib": "^1.10.0"
"tslib": "^2.0.0"
},
"engines": {
"node": ">=8.5.0"
Expand Down
6 changes: 5 additions & 1 deletion src/entrypoints/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@ import { ImportedComponent } from '../ui/Component';
import { ImportedComponent as ComponentLoader } from '../ui/Component';
import { ImportedStream } from '../ui/context';
import imported, { lazy } from '../ui/HOC';
import LazyBoundary from '../ui/LazyBoundary';
import { ImportedController } from '../ui/ImportedController';
import { LazyBoundary } from '../ui/LazyBoundary';
import { ImportedModule, importedModule } from '../ui/Module';
import { useImported, useLazy, useLoadable } from '../ui/useImported';
import { remapImports } from '../utils/helpers';
import { useIsClientPhase } from '../utils/useClientPhase';

export {
printDrainHydrateMarks,
Expand All @@ -36,6 +38,8 @@ export {
importedModule,
lazy,
LazyBoundary,
ImportedController,
useIsClientPhase,
remapImports,
useLoadable,
useImported,
Expand Down
2 changes: 2 additions & 0 deletions src/entrypoints/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { drainHydrateMarks, printDrainHydrateMarks } from '../loadable/marks';
import { createLoadableStream } from '../loadable/stream';
import { getLoadableTrackerCallback } from '../trackers/globalTracker';
import { createLoadableTransformer } from '../transformers/loadableTransformer';
import { Stream } from '../types';
import { ImportedStream } from '../ui/context';

export {
Expand All @@ -16,4 +17,5 @@ export {
getLoadableTrackerCallback,
getMarkedChunks,
getMarkedFileNames,
Stream,
};
7 changes: 6 additions & 1 deletion src/loadable/assignImportedComponents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,16 @@ export const assignImportedComponents = (set: ImportedDefinition[]) => {
assignMetaData(loadable.mark, loadable, imported[1], imported[2]);
});

if (countBefore === LOADABLE_SIGNATURE.size) {
if (set.length === 0) {
// tslint:disable-next-line:no-console
console.error('react-imported-component: no import-marks found, please check babel plugin');
}

if (countBefore === LOADABLE_SIGNATURE.size) {
// tslint:disable-next-line:no-console
console.error('react-imported-component: no new imports found');
}

done();

return set;
Expand Down
2 changes: 1 addition & 1 deletion src/loadable/stream.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Stream } from '../types';

export const createLoadableStream = () => ({ marks: {} });
export const createLoadableStream = (): Stream => ({ marks: {} });
export const clearStream = (stream?: Stream) => {
if (stream) {
stream.marks = {};
Expand Down
46 changes: 46 additions & 0 deletions src/ui/ImportedController.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import React, { createContext, useCallback, useLayoutEffect, useState } from 'react';

interface ImportedState {
usesHydration: boolean;
pastHydration: boolean;
}

export const importedState = createContext<ImportedState | undefined>(undefined);

export const HydrationState: React.FC<{ state: ImportedState }> = ({ state, children }) => (
<importedState.Provider value={state}>{children}</importedState.Provider>
);

/**
* this component just creates a "the first-most" effect in the system
*/
const HydrationEffect = ({ loopCallback }: { loopCallback(): void }): null => {
useLayoutEffect(loopCallback, []);
return null;
};

/**
* @see [LazyBoundary]{@link LazyBoundary} - HydrationController is required for LazyBoundary to properly work with React>16.10
* Established a control over LazyBoundary suppressing fallback during the initial hydration
* @param props
* @param [props.usesHydration=true] determines of Application is rendered using hydrate
*/
export const ImportedController: React.FC<{
/**
* determines of Application is rendered using hydrate
*/
usesHydration?: boolean;
}> = ({ children, usesHydration = true }) => {
const [state, setState] = useState<ImportedState>({
usesHydration,
pastHydration: false,
});

const onFirstHydration = useCallback(() => setState(oldState => ({ ...oldState, pastHydration: true })), []);
return (
<>
<HydrationEffect loopCallback={onFirstHydration} />
<HydrationState state={state}>{children}</HydrationState>
</>
);
};
22 changes: 17 additions & 5 deletions src/ui/LazyBoundary.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
import * as React from 'react';
import { isBackend } from '../utils/detectBackend';
import { useIsClientPhase } from '../utils/useClientPhase';

const LazyBoundary: React.FC<{
const LazyServerBoundary: React.FC<{
fallback: NonNullable<React.ReactNode> | null;
}> = ({ children }) => <React.Fragment>{children}</React.Fragment>;

const LazyClientBoundary: React.FC<{
fallback: NonNullable<React.ReactNode> | null;
}> = ({ children, fallback }) => (
<React.Suspense
// we keep fallback null during hydration as it is expected behavior for "ssr-ed" Suspense blocks - they should not "fallback"
fallback={useIsClientPhase() ? fallback : null}
>
{children}
</React.Suspense>
);

/**
* React.Suspense "as-is" replacement
* React.Suspense "as-is" replacement. Automatically "removed" during SSR and "patched" to work accordingly on the clientside
*
* @see {@link HydrationController} has to wrap entire application in order to provide required information
*/
const Boundary = isBackend ? LazyBoundary : React.Suspense;

export default Boundary;
export const LazyBoundary = isBackend ? LazyServerBoundary : LazyClientBoundary;
18 changes: 18 additions & 0 deletions src/utils/useClientPhase.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { useContext } from 'react';
import { importedState } from '../ui/ImportedController';

/**
* returns "true" if currently is a "client" phase and all features should be active
* @see {@link HydrationController}
*/
export const useIsClientPhase = (): boolean => {
const value = useContext(importedState);
if (!value) {
if (process.env.NODE_ENV !== 'production') {
// tslint:disable-next-line:no-console
console.warn('react-imported-component: please wrap your entire application with ImportedController');
}
return true;
}
return value.pastHydration;
};

0 comments on commit d67a211

Please sign in to comment.