Installations
npm install react-snap-loadable-components
Developer Guide
Typescript
No
Module System
CommonJS
Node Version
8.6.0
NPM Version
5.5.1
Score
70.2
Supply Chain
98.5
Quality
74.7
Maintenance
100
Vulnerability
100
License
Releases
Unable to fetch releases
Contributors
Unable to fetch Contributors
Languages
JavaScript (100%)
Love this project? Help keep it running — sponsor us today! 🚀
Developer
stereobooster
Download Statistics
Total Downloads
1,541
Last Day
1
Last Week
2
Last Month
20
Last Year
138
GitHub Statistics
MIT License
1 Stars
39 Commits
3 Watchers
4 Branches
1 Contributors
Updated on Dec 06, 2019
Bundle Size
3.97 kB
Minified
1.41 kB
Minified + Gzipped
Package Meta Information
Latest Version
0.3.6
Package Id
react-snap-loadable-components@0.3.6
Size
11.92 kB
NPM Version
5.5.1
Node Version
8.6.0
Total Downloads
Cumulative downloads
Total Downloads
1,541
Last Day
0%
1
Compared to previous day
Last Week
-60%
2
Compared to previous week
Last Month
150%
20
Compared to previous month
Last Year
-8%
138
Compared to previous year
Daily Downloads
Weekly Downloads
Monthly Downloads
Yearly Downloads
Peer Dependencies
1
Dev Dependencies
26

React code splitting made easy. Reduce your bundle size without stress ✂️✨.
Read the intro blogpost
1npm install loadable-components
Webpack allows modern code splitting via the dynamic import
syntax.
loadable-components
makes it possible to use that awesome feature with React components. It is compatible with react-router
and server side rendering. The API is designed to be as simple as possible to avoid useless complexity and boilerplate.
We use it in production on our website, it's open source https://github.com/smooth-code/website.
Motivation
Splitting your React application and rendering it server-side is complicated. Several have tried, react-router gave up, today only next.js is doing it right. First I decided to not do it (afraid by react-router 😱) on my website. But then I think "Fuck code splitting shouldn't be a problem today, let's do it.".
I tried several solutions, react-async-components, react-loadable and for each of them server-side rendering is very complicated. I decided to create loadable-components
with for main goal: reducing API in order to make it as easier as possible for the developer. I inspired from styled-components
and Apollo for the API and loadable-components
was born.
Getting started
1// Routes.js 2export const Home = loadable(() => import('./Home')) 3export const About = loadable(() => import('./About')) 4export const Contact = loadable(() => import('./Contact'))
1// App.js 2import React from 'react' 3import { Route } from 'react-router' 4import * as Routes from './Routes' 5 6export default () => 7 <div> 8 <Route exact path="/" component={Routes.Home} /> 9 <Route path="/about" component={Routes.About} /> 10 <Route path="/contact" component={Routes.Contact} /> 11 </div>
Custom loading
It is possible to add a custom loading component, by default it will render nothing:
1export const Home = loadable(() => import('./Home'), { 2 LoadingComponent: (props) => <div>Loading...</div>, 3})
Error handling
You can configure the component rendered when an error occurs during loading, by default it will render nothing:
1export const Home = loadable(() => import('./Home'), { 2 ErrorComponent: ({ error, props }) => <div>Oups an error occurs.</div>, 3})
Delay
To avoid flashing a loader if the loading is very fast, you could implement a minimum delay. There is no built-in API in loadable-components
but you could do it using p-min-delay
.
1import loadable from 'loadable-components' 2import pMinDelay from 'p-min-delay' 3 4// Wait a minimum of 200ms before loading home. 5export const Home = loadable(pMinDelay(() => import('./Home'), 200))
If you want to avoid these delay server-side:
1import loadable from 'loadable-components' 2import pMinDelay from 'p-min-delay' 3 4const delay = (promise) => { 5 if (typeof window === 'undefined') return promise 6 return pMinDelay(promise, 200) 7} 8 9export const Home = loadable(delay(() => import('./Home')))
Timeout
Infinite loading is not good for user experience, to avoid it implementing a timeout is a good workaround. You can do it using a third party module like promise-timeout
:
1import loadable from 'loadable-components' 2import { timeout } from 'promise-timeout' 3 4// Wait a maximum of 2s before sending an error. 5export const Home = loadable(timeout(() => import('./Home'), 2000))
Prefetching
To enhance user experience you can fetch routes before they are requested by the user.
Prefetch on route loading
1import React from 'react' 2import { Contact } from './Routes' 3 4Contact.load() 5 6export default () => <div>Hello</div>
Prefetch on hover
1import React from 'react' 2import { Contact } from './Routes' 3 4export default () => 5 <div> 6 <Link 7 <Link to="/contact" onHover={Contact.load}>Contact</Link> 8 </div>
Server-side rendering
First create a Routes.js
containing all your loadable routes:
1// Routes.js 2import loadable from 'loadable-components' 3 4export const Home = loadable(() => import('client/Home'))
You can use them in your application:
1// App.js 2import React from 'react' 3import { Home } from './Routes' 4 5const App = () => 6 <div> 7 <Route exact path="/" component={Home} /> 8 </div>
Then bootstrap your application client-side using loadComponents
:
1// main.js 2import React from 'react' 3import ReactDOM from 'react-dom' 4import { BrowserRouter } from 'react-router-dom' 5import { loadComponents } from 'loadable-components' 6import App from './App' 7 8// Load all components needed before starting rendering 9loadComponents().then(() => { 10 ReactDOM.render( 11 <BrowserRouter> 12 <App /> 13 </BrowserRouter>, 14 document.getElementById('main'), 15 ) 16})
The only thing you have to do on the server is calling getLoadableState()
and inserting the loadable state in your html:
1// server.js 2import React from 'react' 3import { renderToString } from 'react-dom/server' 4import { StaticRouter } from 'react-router' 5import { getLoadableState } from 'loadable-components/server' 6import App from './App' 7 8let context = {} 9 10const app = ( 11 <StaticRouter location={...} context={context}> 12 <App /> 13 </StaticRouter> 14) 15 16// Extract loadable state from application tree 17getLoadableState(app).then(loadableState => { 18 const html = renderToString(<YourApp />) 19 // Insert style tag into page 20 const page = ` 21 <!doctype html> 22 <html> 23 <head></head> 24 <body> 25 <div id="main">${html}</div> 26 ${loadableState.getScriptTag()} 27 </body> 28 </html> 29 ` 30})
Configuring Babel
Dynamic import
syntax is natively supported by Webpack but not by node. That's why you have to configure Babel differently for server and client:
- Use babel-plugin-syntax-dynamic-import on the client.
- Use babel-plugin-dynamic-import-node on the server.
To have a different configuration for client and server, you can use Babel env option.
API Reference
loadable
This is the default export. It's a factory used to create a loadable component. Props are passed to the loaded component.
Arguments
getComponent
(Function): Function to load component asynchronously.options
(Object): Facultative options to configure component behavior.
options
ErrorComponent
(ReactComponent): Component rendered when an error occurs, take two props:error
andprops
.LoadingComponent
(ReactComponent): Component rendered during loading, take the same props from loadable component.
1import loadable from 'loadable-components' 2 3const MyLoadableComponent = loadable(() => import('./MyComponent'), { 4 ErrorComponent: ({ error }) => <div>{error.message}</div>, 5 LoadingComponent: () => <div>Loading...</div>, 6})
loadComponents
This method is only required if you use server-side rendering. It loads components used in the page that has been rendered server-side.
1import React from 'react' 2import ReactDOM from 'react-dom' 3import { BrowserRouter } from 'react-router-dom' 4import { loadComponents } from 'loadable-components' 5import App from './App' 6 7// Load all components needed before starting rendering 8loadComponents().then(() => { 9 ReactDOM.render( 10 <BrowserRouter> 11 <App /> 12 </BrowserRouter>, 13 document.getElementById('main'), 14 ) 15})
getLoadableState
This method is only required if you use server-side rendering. It loads components recursively and extract a loadable state from a React tree.
1import React from 'react' 2import { renderToString } from 'react-dom/server' 3import { StaticRouter } from 'react-router' 4import { getLoadableState } from 'loadable-components/server' 5import App from './App' 6 7const app = ( 8 <StaticRouter> 9 <App /> 10 </StaticRouter> 11) 12 13// Extract loadable state from application tree 14getLoadableState(app).then(loadableState => { 15 const html = renderToString(<YourApp />) 16 // Insert style tag into page 17 const page = ` 18 <!doctype html> 19 <html> 20 <head></head> 21 <body> 22 <div id="main">${html}</div> 23 ${loadableState.getScriptTag()} 24 </body> 25 </html> 26 ` 27})
A loadable state has two methods to extract state:
loadableState.getScriptTag()
: Returns a string representing a script tag.loadableState.getScriptElement()
: Returns a React element.
Interoperability
You can implement a loadable component by your own. To do it you have to add LOADABLE
Symbol to your component:
1import React from 'react' 2import { LOADABLE } from 'loadable-components' 3 4class ComponentWithTranslations extends React.Component { 5 // Required 6 static componentId = 'custom-loadable' 7 static async load = () => { 8 const response = await fetch('/translations.json') 9 const translations = await response.json() 10 ComponentWithTranslations.translations = translations 11 return translations 12 } 13 14 state = { translations: ComponentWithTranslations.translations } 15 16 componentWillMount() { 17 ComponentWithTranslations[LOADABLE].load() 18 .then(translations => this.setState({ translations })) 19 } 20 21 render() { 22 const { translations = { hello = 'hello' } } = this.props; 23 24 return <div>{hello}</div> 25 } 26} 27 28ComponentWithTranslations[LOADABLE] = () => ({ 29 componentId: 'custom-loadable', 30 load: async () => { 31 const response = await fetch('/translations.json') 32 const translations = await response.json() 33 ComponentWithTranslations.translations = translations 34 } 35})
Other solutions
react-loadable
offers an elegant API to load a component and enhance it. It supports a lot of features like delay and timeout. I chose to not implement it because it delay can be done in LoadingComponent
and timeout can be done in getComponent
function.
react-async-component
offers a simple API, very similar to loadable-components
API.
react-code-splitting
is the basic approach of an async component, it doesn't support LoadingComponent, ErrorComponent and server-side rendering.
The main difference between these two libraries is the server-side rendering approach:
react-loadable
requires a babel plugin. I think it's too complicated and we should not rely on it.react-async-component
has a better approach, analyzing tree + context, it also rely on another library. I like the idea but not the API.
loadable-components
has a simpler approach, it relies on dynamic-import-specification and assumes that it is working for node and Webpack. Then it analyzes the tree server-side and waiting for every modules to be loaded. Client-side it loads modules before rendering the application. The API is as simple as possible, no context, no babel plugin, no magic variable.
Inspirations
- API inspired by styled-components
- React tree traversing from react-apollo
MIT

No vulnerabilities found.
Reason
no binaries found in the repo
Reason
license file detected
Details
- Info: project has a license file: LICENSE:0
- Info: FSF or OSI recognized license: MIT License: LICENSE:0
Reason
Found 0/30 approved changesets -- score normalized to 0
Reason
no SAST tool detected
Details
- Warn: no pull requests merged into dev branch
Reason
0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
security policy file not detected
Details
- Warn: no security policy file detected
- Warn: no security file to analyze
- Warn: no security file to analyze
- Warn: no security file to analyze
Reason
project is not fuzzed
Details
- Warn: no fuzzer integrations found
Reason
branch protection not enabled on development/release branches
Details
- Warn: branch protection not enabled for branch 'master'
Reason
95 existing vulnerabilities detected
Details
- Warn: Project is vulnerable to: GHSA-v88g-cgmw-v5xw
- Warn: Project is vulnerable to: GHSA-93q8-gq69-wqmw
- Warn: Project is vulnerable to: GHSA-fwr7-v2mv-hh25
- Warn: Project is vulnerable to: GHSA-67hx-6x53-jw92
- Warn: Project is vulnerable to: GHSA-cwfw-4gq5-mrqx
- Warn: Project is vulnerable to: GHSA-g95f-p29q-9xw4
- Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg
- Warn: Project is vulnerable to: GHSA-mh2h-6j8q-x246
- Warn: Project is vulnerable to: GHSA-5q88-cjfq-g2mh
- Warn: Project is vulnerable to: GHSA-xp63-6vf5-xf3v
- Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275
- Warn: Project is vulnerable to: GHSA-p28h-cc7q-c4fg
- Warn: Project is vulnerable to: GHSA-9vvw-cc9w-f27h
- Warn: Project is vulnerable to: GHSA-gxpj-cx7g-858c
- Warn: Project is vulnerable to: GHSA-hr2v-3952-633q
- Warn: Project is vulnerable to: GHSA-h6ch-v84p-w6p9
- Warn: Project is vulnerable to: GHSA-ff7x-qrg7-qggm
- Warn: Project is vulnerable to: GHSA-qrmc-fj45-qfc2
- Warn: Project is vulnerable to: GHSA-8r6j-v8pm-fqw3
- Warn: Project is vulnerable to: MAL-2023-462
- Warn: Project is vulnerable to: GHSA-xf7w-r453-m56c
- Warn: Project is vulnerable to: GHSA-pfrx-2q88-qq97
- Warn: Project is vulnerable to: GHSA-q42p-pg8m-cqh6
- Warn: Project is vulnerable to: GHSA-w457-6q6x-cgp9
- Warn: Project is vulnerable to: GHSA-62gr-4qp9-h98f
- Warn: Project is vulnerable to: GHSA-f52g-6jhx-586p
- Warn: Project is vulnerable to: GHSA-2cf5-4w76-r9qv
- Warn: Project is vulnerable to: GHSA-3cqr-58rm-57f8
- Warn: Project is vulnerable to: GHSA-g9r4-xpmj-mj65
- Warn: Project is vulnerable to: GHSA-q2c6-c6pm-g3gh
- Warn: Project is vulnerable to: GHSA-765h-qjxv-5f44
- Warn: Project is vulnerable to: GHSA-f2jv-r9rf-7988
- Warn: Project is vulnerable to: GHSA-44pw-h2cw-w3vq
- Warn: Project is vulnerable to: GHSA-jp4x-w63m-7wgm
- Warn: Project is vulnerable to: GHSA-c429-5p7v-vgjp
- Warn: Project is vulnerable to: GHSA-43f8-2h32-f4cj
- Warn: Project is vulnerable to: GHSA-qqgx-2p2h-9c37
- Warn: Project is vulnerable to: GHSA-2pr6-76vf-7546
- Warn: Project is vulnerable to: GHSA-8j8c-7jfh-h6hx
- Warn: Project is vulnerable to: GHSA-896r-f27r-55mw
- Warn: Project is vulnerable to: GHSA-9c47-m6qq-7p4h
- Warn: Project is vulnerable to: GHSA-jf85-cpcp-j695
- Warn: Project is vulnerable to: GHSA-fvqr-27wr-82fm
- Warn: Project is vulnerable to: GHSA-4xc9-xhrj-v574
- Warn: Project is vulnerable to: GHSA-x5rq-j2xg-h7qm
- Warn: Project is vulnerable to: GHSA-29mw-wpgm-hmr9
- Warn: Project is vulnerable to: GHSA-35jh-r3h4-6jhm
- Warn: Project is vulnerable to: GHSA-p6mc-m468-83gw
- Warn: Project is vulnerable to: GHSA-2m96-9w4j-wgv7
- Warn: Project is vulnerable to: GHSA-h726-x36v-rx45
- Warn: Project is vulnerable to: GHSA-7px7-7xjx-hxm8
- Warn: Project is vulnerable to: GHSA-x5pg-88wf-qq4p
- Warn: Project is vulnerable to: GHSA-5v2h-r2cx-5xgj
- Warn: Project is vulnerable to: GHSA-rrrm-qjm4-v8hf
- Warn: Project is vulnerable to: GHSA-4xcv-9jjx-gfj3
- Warn: Project is vulnerable to: GHSA-f9cm-qmx5-m98h
- Warn: Project is vulnerable to: GHSA-7wpw-2hjm-89gp
- Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv
- Warn: Project is vulnerable to: GHSA-wrvr-8mpx-r7pp
- Warn: Project is vulnerable to: GHSA-hxm2-r34f-qmc5
- Warn: Project is vulnerable to: GHSA-f8q6-p94x-37v3
- Warn: Project is vulnerable to: GHSA-vh95-rmgr-6w4m
- Warn: Project is vulnerable to: GHSA-xvch-5gv4-984h
- Warn: Project is vulnerable to: GHSA-qjg4-w4c6-f6c6
- Warn: Project is vulnerable to: GHSA-6m8p-4fxj-pgc2
- Warn: Project is vulnerable to: GHSA-r683-j2x4-v87g
- Warn: Project is vulnerable to: GHSA-5fw9-fq32-wv5p
- Warn: Project is vulnerable to: GHSA-rp65-9cf3-cjxr
- Warn: Project is vulnerable to: GHSA-6394-6h9h-cfjg
- Warn: Project is vulnerable to: GHSA-hj48-42vr-x3v9
- Warn: Project is vulnerable to: GHSA-9wv6-86v2-598j
- Warn: Project is vulnerable to: GHSA-hrpp-h998-j3pp
- Warn: Project is vulnerable to: GHSA-6g33-f262-xjp4
- Warn: Project is vulnerable to: GHSA-mvjj-gqq2-p4hw
- Warn: Project is vulnerable to: GHSA-p8p7-x288-28g6
- Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw
- Warn: Project is vulnerable to: GHSA-44c6-4v22-4mhx
- Warn: Project is vulnerable to: GHSA-4x5v-gmq8-25ch
- Warn: Project is vulnerable to: GHSA-2m39-62fm-q8r3
- Warn: Project is vulnerable to: GHSA-mf6x-7mm4-x2g7
- Warn: Project is vulnerable to: GHSA-j44m-qm6p-hp7m
- Warn: Project is vulnerable to: GHSA-3jfq-g458-7qm9
- Warn: Project is vulnerable to: GHSA-5955-9wpr-37jh
- Warn: Project is vulnerable to: GHSA-f5x3-32g6-xq36
- Warn: Project is vulnerable to: GHSA-jgrx-mgxx-jf9v
- Warn: Project is vulnerable to: GHSA-g7q5-pjjr-gqvp
- Warn: Project is vulnerable to: GHSA-72xf-g2v4-qvf3
- Warn: Project is vulnerable to: GHSA-7p7h-4mm5-852v
- Warn: Project is vulnerable to: GHSA-38fc-wpqx-33j7
- Warn: Project is vulnerable to: GHSA-662x-fhqg-9p8v
- Warn: Project is vulnerable to: GHSA-394c-5j6w-4xmx
- Warn: Project is vulnerable to: GHSA-fhg7-m89q-25r3
- Warn: Project is vulnerable to: GHSA-cf4h-3jhx-xvhq
- Warn: Project is vulnerable to: GHSA-c4w7-xm78-47vh
- Warn: Project is vulnerable to: GHSA-p9pc-299p-vxgp
Score
1.7
/10
Last Scanned on 2025-02-03
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn More