Installations
npm install react-imported-component
Developer Guide
Typescript
Yes
Module System
CommonJS
Min. Node Version
>=10
Node Version
16.20.2
NPM Version
8.19.4
Releases
Contributors
Unable to fetch Contributors
Languages
TypeScript (94.02%)
JavaScript (5.81%)
HTML (0.17%)
Love this project? Help keep it running — sponsor us today! 🚀
Developer
theKashey
Download Statistics
Total Downloads
2,843,879
Last Day
29
Last Week
29
Last Month
13,071
Last Year
200,107
GitHub Statistics
666 Stars
466 Commits
40 Forks
12 Watching
585 Branches
14 Contributors
Bundle Size
12.93 kB
Minified
4.23 kB
Minified + Gzipped
Package Meta Information
Latest Version
6.5.4
Package Id
react-imported-component@6.5.4
Unpacked Size
315.89 kB
Size
52.76 kB
File Count
268
NPM Version
8.19.4
Node Version
16.20.2
Publised On
20 Mar 2024
Total Downloads
Cumulative downloads
Total Downloads
2,843,879
Last day
0%
29
Compared to previous day
Last week
-98.2%
29
Compared to previous week
Last month
23.7%
13,071
Compared to previous month
Last year
-34.2%
200,107
Compared to previous year
Daily Downloads
Weekly Downloads
Monthly Downloads
Yearly Downloads
Peer Dependencies
2
IMPORTED COMPONENT ✂
Code splitting which always works*
![imported components](./assets/imported-logo.png)
SSR-friendly code splitting compatible with any platform.
Deliver a better experience within a single import.
* It's really will never let you down. All credits to your bundler.
👉 Usage | API | Setup | SSR | CCS Concurrent loading | Webpack/Parcel
Library | Suspense | SSR | Hooks | Library | Non-modules | import(./${value} ) | babel-macro | webpack only |
---|---|---|---|---|---|---|---|---|
React.lazy | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | 😹 | no-ssr |
react-loadable | ✅ | ✅ | ❌ | ❌ | ✅ | ❌ | ❌ | 😿 |
@loadable/component | ✅ | ✅ | ❌ | ✅ | ❌ | ✅ | ❌ | 😿 |
imported-component | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ✅ | 😸 |
Read more about what this table displays
Key features:
- 1️⃣ Single source of truth - your bundler drives everything
- 📖 library level code splitting
- 🧙️ Hybrid and Prerendering compatible
- 💡 TypeScript bindings
- ⚛️ React.Lazy underneath (if hot module updates are disabled)
- 🌟 Async on client, sync on server. Supports Suspense (even on server side)
- 📦 could work with any bundler - webpack, rollup, parcel or puppeteer - it does not matter
- 🤹♂️ working as well with any
import
you may provide
Other features:
- 🔥 Hot-Module-Replacement/React-Hot-Loader friendly
- ⛓️ support forwardRef
- ⚛️ React 16/Async/Hooks ready
- 🛠 HOC, Component, Hooks API
- 🐳 stream rendering support
- 👥 partial hydration out of the box
- 📦 and yes - this is the only parcel-bundler compatible SSR-friendly React code splitting library, as well as a perfect solution for Create React App
👍 Better than React.Lazy:
- It IS Lazy, just with some stuff around*
- SSR, Prerendering and Preloading support
- With or without Suspense, and easier Error cases support
👍 Better than others:
- Not bound to webpack
- Easy way to use per-browser(modern/legacy) bundles - you down have to mess with actual browser support
- Strong typing
- Working with any imports, even native, external or derived ones.
👌 Client-side module resolution
- Loads chunks only after the
main one
, as long as loader code is bundled inside the main chunk, so it should be loaded first. - Not an issue with the
progressive hydration
, and might provide a better UX via feature detection. - Provides 👨🔬 technological workaround - see here
📦 Optional bundler integration for the best experience
- prefetching backed by webpack
stat.json
andasset.json
parcel-manifest.json
support
👯♀️Works better in pair
- react-prerendered-component for prerendering, partial hydration and react fragment caching
- used-style for CSS and critical CSS extraction
- devolution for shipping legacy/modern bundles
- webpack-imported for deep
webpack
integration, the only bundler dependent tool in this list.
Usage
Server side
Just a proper setup and a bit of magic
Client side
Component
imported
provides 2 common ways to define a component, which are more different inside than outside
- using
pre-lazy
API.
1import importedComponent from 'react-imported-component'; 2const Component = importedComponent( () => import('./Component')); 3 4const Component = importedComponent( () => import('./Component'), { 5 LoadingComponent: Spinner, // what to display during the loading 6 ErrorComponent: FatalError // what to display in case of error 7}); 8 9Component.preload(); // force preload 10 11// render it 12<Component... />
- using
lazy
API. It's almost the sameReact.lazy
outside, and exactly the same inside.
1import { lazy, LazyBoundary } from 'react-imported-component'; 2const Component = lazy(() => import('./Component')); 3 4const ClientSideOnly = () => ( 5 <Suspense> 6 <Component /> 7 </Suspense> 8); 9 10// or let's make it SSR friendly 11const ServerSideFriendly = () => ( 12 <LazyBoundary> 13 {' '} 14 // LazyBoundary is Suspense* on the client, and "nothing" on the server 15 <Component /> 16 </LazyBoundary> 17);
LazyBoundary
is a Suspense
on Client Side, and React.Fragment
on Server Side. Don't forget - "dynamic" imports are sync on a server.
Example: React.lazy vs Imported-component
Hook
However, you may not load only components - you may load anything
1import {useImported} from 'react-imported-component' 2 3const MyCalendarComponent = () => { 4 const { 5 imported: moment, 6 loading 7 } = useImported(() => import("moment")); 8 9 return loading ? "..." : <span>today is {moment(Date.now).format()}</span> 10} 11 12// or we could make it a bit more interesting... 13 14const MyCalendarComponent = () => { 15 const { 16 imported: format = x => "---", // default value is used while importing library 17 } = useImported( 18 () => import("moment"), 19 moment => x => moment(x).format // masking everything behind 20 ); 21 22 return <span>today is {format(Date.now())</span> 23}
What you could load using useImported
? Everything - imported
itself is using it to import components.
useImported
is an excellent example for loading translations, which are usually a simple json, in a trackable way.
💡 did you know that there is another hook based solution to load "something might might need"? The use-sidecar pattern.
🤔 Keep in mind - everything here is using useImported
, and you can build whatever you need using just it.
Module
A slim helper to help handle modules
, you might require using useImported
in a component way
1import { importedModule, ImportedModule } from 'react-imported-component'; 2 3const Moment = importedModule(() => import('moment')); 4 5<Moment fallback="long time ago"> 6 {(momentjs /* default imports are auto-imported*/) => momentjs(date).fromNow()} 7</Moment>;
Yes, this example was taken from loadable.lib
Can I also use a ref, populated when the library is loaded? No, you cant. Use useImported
for any special case like this.
Plus, there is a Component helper:
1<ImportedModule 2 // import is just a _trackable_ promise - do what ever you want 3 import={() => import('moment').then(({momentDefault})=> momentDefault(date).fromNow()} 4 fallback="long time ago" 5> 6 {(fromNow) => fromNow()} 7</ImportedModule>
ImportedModule will throw a promise to the nearest Suspense boundary if no
fallback
provided.
Babel macro
If you could not use babel plugin, but do have babel-plugin-macro
(like CRA) - consider using macro API:
1import { imported, lazy, useImported } from 'react-imported-component/macro'; 2// notice - there is no default import here
Indirect usage
Just importing react-imported-component/macro
would enable babel transformation for the current file.
If you have imported
definition in one file, and use it from another - just import "react-imported-component/macro"
in that another file. See #142
API
Don't forget - there are TS typings provided.
Code splitting components
import {*} from 'react-imported-component';
importedComponent
-
importedComponent(importFunction, [options]): ComponentLoader
- main API, default export, HOC to create imported component.-
importFunction
- function which resolves with Component to be imported. -
options
- optional settings -
options.async
- activates react suspense support. Will throw a Promise in a Loading State - use it with Suspense in a same way you use React.lazy. See working with Suspense -
options.LoadingComponent
- component to be shown in Loading state -
options.ErrorComponent
- component to be shown in Error state. Will re-throw error if ErrorComponent is not set. Use ErrorBoundary to catch it. -
options.onError
- function to consume the error, if one will thrown. Will rethrow a real error if not set. -
options.exportPicker
- function to picknot default
export from aimportFunction
-
options.render(Component, state, props)
- function to render the result. Could be used to tune the rendering. -
[static]
.preload
- static method to preload components.
-
lazy
lazy(importFunction)
- helper to mimic React.lazy behavior
useImported
-
useImported(importFunction, [exportPicker], [options])
- code splitting hook-
importFunction
- a function which resolves todefault
orwildcard
import(T | {default:T}) -
[exportPicker]
- function to pick "T" from the import -
[options]
- options to the hook[options.import]
- controls import. Hooks would be executed only if this is not false[options.track]
- ability to disable server-side usage tracking.
-
useImported
returns complex object(ImportedShape):
imported
- the imported resourceerror
- error (if present)loading
- is it loading right now?loadable
- the underlyingLoadable
objectretry
- retry action (in case of error)
Hints:
- use
options.import=false
to perform conditional import -importFunction
would not be used if this option set to `false. - use
options.track=true
to perform SSR only import - to usage would be tracked if this option set to `false.
ImportedController
<ImportedController>
- a controller for Suspense Hydration. Compulsory for async/lazy usecases
Misc
There is also API method, unique for imported-component, which could be useful on the client side
addPreloader(fn):fn
- adds a function, result of which would be awaited when any component is loaded. Returns cancel method.
Server side API
import {*} from 'react-imported-component/server';
whenComponentsReady():Promise
- will be resolved, when all components are loaded. Usually on the next "Promise" tick.drainHydrateMarks([stream])
- returns the currently used marks, and clears the list.printDrainHydrateMarks([stream])
- print our thedrainHydrateMarks
.
Stream API
createLoadableStream
- creates a steamImportedStream
- wraps another component with import usage tracker.createLoadableTransformer
- creates nodejs StreamTransformergetLoadableTrackerCallback
- helper factory for the stream transformer
Client side API
import {*} from 'react-imported-component/boot';
whenComponentsReady():Promise
, will be resolved, when all (loading right now) marks are loaded.rehydrateMarks([marks]):Promise
, loads marked async chunks.injectLoadableTracker
- helper factory for the stream transformer
Types
Loadable
All imports inside library are converted into Loadable
object, and it's often accessible from outside via
useImported().loadable
, useLoadable
(not documented), getLoadable
(not documented). Even if it's documented from TS point of view -
let's keep all fields in a secret, except one:
resolution
- promise reflecting resolution of this loadable object
Setup
In short
- Add
babel
plugin - Run
yarn imported-components src src/imported.js
to extract all your imports into arun time chunk
(aka async-requires). - Replace
React.lazy
with ourlazy
, andReact.Suspense
with ourLazyBoundary
. Literraly monkey-patch React to do so - Add
printDrainHydrateMarks
to the server code. - Add
rehydrateMarks
to the client code - Done. Just read the rest of readme for details.
There are examples for webpack, parcel, and react-snap. Just follow them.
1. Configure babel plugin
On the server:
1{ 2 "plugins": ["react-imported-component/babel", "babel-plugin-dynamic-import-node" /* might be optional for babel 7*/] 3}
On the client:
1{ 2 "plugins": ["react-imported-component/babel"] 3}
Imported-Component will hook into dynamic imports, providing extra information about files you want to load.
2. Add one more command into package.json
CLI command imported-components [sources ROOT] [targetFile.js]
(use .ts for TypeScript)
1 "generate-imported-component": "imported-components src src/imported.js"
When you will execute this command - all imports
among your codebase would be found and extracted to a file provided.
This will gave ability to orchestrate code-splitting later.
If you need to search inside more that one top-level directory - just define more command, saving information into more than one target file.
The current implementation will discover and use all
imports
, even // commented ones
💡 Feel free to .gitignore these autogenerated files
3. Start using imported
, lazy
or useImported
Without you using API provided nothing would work.
4. Add server side tracking
There are two ways to do it - in a single threaded way, and async
Single threaded
1import { printDrainHydrateMarks, drainHydrateMarks } from 'react-imported-component'; 2// this action will "drain" all currently used(by any reason) marks 3// AND print a script tag 4const html = renderToString(<YourApp />) + printDrainHydrateMarks(); 5 6// OR return list of usedmarks, and yet again CLEAR the marks list. 7const html = renderToString(<YourApp />) + '<script>const marks=' + JSON.stringify(drainHydrateMarks()) + '</script>';
renderToStream or async render
1import {createLoadableStream} from 'react-imported-component/server'; 2 3let importedStream = createLoadableStream(); 4// ImportedStream is a async rendering "provider" 5const stream = renderToStream( 6 <ImportedStream stream={importedStream}> 7 <YourApp /> 8 </ImportedStream> 9); 10 11// you'd then pipe the stream into the response object until it's done 12stream.pipe(res, { end: false }); 13 14// and finalize the response with closing HTML 15stream.on('end', () => 16 // print marks used in the file 17 res.end(`${printDrainHydrateMarks(importedStream)}</body></html>`), 18)
However, the idea is just to use streams
to separate renders
1const html = 2 renderToString( 3 <ImportedStream stream={importedStream}> 4 <YourApp /> 5 </ImportedStream> 6 ) + printDrainHydrateMarks(importedStream);
5. Add rehydrateMarks
to the client code
Before rendering your application you have to ensure - all parts are loaded.
rehydrateMarks
will load everything you need, and provide a promise to await.
1import { rehydrateMarks, ImportedController } from 'react-imported-component'; 2 3// this will trigger all marked imports, and await for competition. 4rehydrateMarks().then(() => { 5 // better (note ImportedController usage) 6 ReactDOM.hydrate( 7 <ImportedController> 8 <App /> 9 </ImportedController>, 10 document.getElementById('main') 11 ); 12 // or 13 ReactDOM.render(<App />, document.getElementById('main')); 14});
rehydrateMarks
accepts a list of marks
from a server side(drainHydrateMarks
), loads all
necessary chunks and then resolves.
A VERY IMPORTANT MOMENT - Concurrent Loading
All other code splitting libraries are working a bit differently - they amend webpack
building process,
gathering information about how the final chunks are assembled, and injects the real scripts and styles to the server response,
thus all scripts, used to render something on the Server would be loaded in a parallel in on Client.
Literally - they are defined in the HTML.
React-imported-component
is different, it starts "working" when the bundle is loaded, thus
the loading of chunks is deferred.
💡 In the normals conditions
react-imported-component
would be "slower" than a "webpack" library. Refer to bundle integration section.
However, it is not a problem, as long as (for now), script execution is single threaded, and even you if can load multiple scripts simultaneously - you can't run them in parallel*.
And there a way to utilize this limitation - just change your entry point, .
And let's call it - a Scheduler optimization. See loading prediction section for more details.
Scheduler optimization + simply static render
- Split your app into
boot
andmain
parts rehydrate
at the boot
1// index.js (boot) 2import './src/imported'; // the file generated by "generate-imported-component" (.2) 3import { rehydrateMarks } from 'react-imported-component/boot'; 4 5rehydrateMarks(); // just start loading what's needed 6 7// load/execute the rest after letting the browser kick off chunk loading 8// for example wrapping it in two Promises (1ms timeout or setImmediate) 9Promise.resolve().then(() => 10 Promise.resolve().then(() => { 11 // load the rest 12 require('./main'); // <--- your main scripts 13 // ! and don't forget to `await rehydrateMarks()` before render 14 }) 15); 16 17// main.js 18rehydrateMarks().then(() => { 19 ReactDOM.hydrate(<App />, document.getElementById('root')); 20});
This will just start loading extra chunks before the main bundle got completely parsed and executed.
Defer till DOMReady
💡 Another perfect option would be to wait till DomReady event.
1// index.js (boot) 2import './src/imported'; // the file generated by "generate-imported-component" (.2) 3import { rehydrateMarks } from 'react-imported-component/boot'; 4 5rehydrateMarks(); // just start loading what's needed 6 7const startApp = () => require('./main'); // <--- your main scripts 8 9// it's "not safe" to start you application before DOM is "ready" 10if (document.readyState === 'loading') { 11 document.addEventListener('DOMContentLoaded', startApp); 12} else { 13 startApp(); 14}
Scheduler optimization + stream render
See examples/SSR/parcel-react-ssr/server-stream for details
- Add your main bundle to the
head
, using async script tag. Not defer! We have to do it async - Add
loadableTracker
at server side
1import {createLoadableTransformer, getLoadableTrackerCallback} from 'react-imported-component/server';
2const importedTracker = createLoadableTransformer(
3 loadableStream, // stream to observe
4 getLoadableTrackerCallback() // helper factory to create global tracker.
5);
6
7// pipe result of `renderToStream` throught it
8const reactRenderStream = ReactDOM.renderToNodeStream(...).pipe(importedTracker);
- Add
loadableTracker
at client side
1// index.js 2import './src/imported'; // the file generated by "generate-imported-component" (.2) 3import { injectLoadableTracker } from 'react-imported-component/boot'; 4 5injectLoadableTracker(); 6 7// load the rest after letting the browser kick off chunk loading 8// for example wrapping it in two Promises (1ms timeout or setImmediate) 9Promise.resolve().then(() => 10 Promise.resolve().then(() => { 11 require('./main'); 12 }) 13);
This "hack", will first introduce all possible imports
to the imported-component
, then gave it a "tick"
to start loading required once, and only then execute the rest of the bundle.
While the rest(99%) of the bundle would make CPU busy - chunks would be loaded over the network.
💡This is utilizing the differences between
parse
(unenviable) phase of script, and execute(more expensive) one.
Cooking receipts
Replace React.lazy by lazy
1import React from 'react'; 2import { lazy, LazyBoundary } from 'react-imported-component'; 3React.lazy = lazy; 4React.Suspense = LazyBoundary;
That's all the work required to get it working.
Partial hydration
Just wrap "partial hydrated" component with another ImportedStream
so everything needed for it would be not automatically loaded with the main stream.
Hybrid render (CSR with prerendering)
This library could support hybrid rendering (aka pre-rendering) compatible in two cases:
- pre-render supports
state hydration
, likegetState
in react-snap. See our example. - for rendertron or https://prerender.io follow
react-snap
example, just dumpstate
usingsetTimeout
. - You may use
react-prerendered-component
to maintain a component state until async chunk is not loaded. See example below.
Works better in pair (boiled-place-less code splitting)
You might not need to wait for all the chunks to be loaded before you can render you app - just use react-prerendered-component.
1import imported from 'react-imported-component'; 2import { PrerenderedComponent } from 'react-prerendered-component'; 3 4const AsyncComponent = imported(() => import('./myComponent.js')); 5 6<PrerenderedComponent 7 // component will "go live" when chunk loading would be done 8 live={AsyncComponent.preload()} 9> 10 // until component is not "live" prerendered HTML code would be used // that's why you need to `preload` 11 <AsyncComponent /> 12</PrerenderedComponent>;
React-prerendered-component
is another way to work with code splitting, which makes everything far better.
Timeout to display "spinners"
There is no build in timeouts to display Error or Loading states. You could control everything by yourself
- use react-delay, p-delay, p-timeout, or
Suspense
:P.
Component loader
You may use component api if you need it by any reason.
1import { ComponentLoader } from 'react-imported-component'; 2 3const MyPage = () => ( 4 <ComponentLoader 5 loadable={() => import('./Page.js')} 6 // all fields are optional, and matches the same field of importedComponent. 7 LoadingComponent={Loading} 8 ErrorComponent={Error} 9 onError 10 exportPicker 11 render 12 async 13 /> 14);
CSS Support
CSS-in-JS Support
Out-of-the-box. Literally. CSS-in-JS library, like styled-component
will do it by themselves, and there is nothing
to be managed by this library.
Static CSS Files Support
imported
could knew only about JS you've used, not the CSS that js've used...
This library does not support CSS as CSS, as long it's bundler independent and such deep integration is not possible.
Even if deep bundler integration is next following this section - the recomended solution is to skip css
part of it, and use
a more bundler independent way to support CSS:
- Configure you bundler, and server side rendering to emit the right
classNames
(just removestyle-loader
from webpack configuration) - Use
used-styles
to inject used css files to the resulting HTML.
In short (streamed example is NOT short)
1const lookup = discoverProjectStyles('./dist'); 2// .... 3const markup = ReactDOM.renderToString(<App />); 4const usedStylesAsCSSFiles = getUsedStyles(markup, lookup); 5// generate `link` (better rel='preload') to load CSS files 6 7const usedStylesAsStyles = getCriticalStyles(markup, lookup); 8// extract critical CSS and inline in to the server response
If you need stream render example with reduced TTFB - please refer to used-styles documentation, or our parcel-bundler stream server example.
Critical style extraction and Preloader
With the critical style extracting you might not need the "real" and "full" styles on the page load -
only js
is really required for hydration.
Thus - you might skip loading styles for the initial render, however still need them for the next render.
However - your bundler might think that you have loaded them, this is not true.
To handle this case you need addPreloader
method
1// load initial bundle 2// await dom ready 3// -> HYDRATE APP <- 4// add preloader 5 6import { addPreloader } from 'react-imported-component/boot'; 7 8addPreloader(() => { 9 // check that styles are loaded 10 // or return Promise if they are not 11}); 12 13// any not yet loaded ImportedComponent 14// will await for it's own `import` as well as for 15// promise returned from preloaders
See critical css example for details
Create React App
Use react-imported-component/macro
for CRA compatible SSR code splitting without ejecting.
It is safe to always use
react-imported-component/macro
withoutbabel-plugin-macros
, BUT withreact-hot-loader/babel
enabled, as long as it will remove allmacros
.
Bundler integration
Keep in mind - you dont "need" this. It will just make integration slightly better in terms of prefetching (which affects network recourse priority) and thus startup time.
Webpack integration
You might preload/prefetch used styles and scripts, which were defined with webpackChunkName
1// get mark somehow (drainHydrateMarks(importedStream)) 2import { getMarkedChunks } from 'react-imported-component/server'; 3 4const chunkNames = getMarkedChunks(marks);
Via webpack-imported
webpack-imported - provides webpack
plugin to get data from the build, as well as to use it.
Supports prefetching and critical style guidance.
1import { WebpackImport } from 'webpack-imported/react'; 2import importedStat from 'build/imported.json'; 3 4<WebpackImport stats={importedStat} chunks={getMarkedChunks(drainHydrateMarks())} />;
Via stat.json
If you do have only stat.json
- it could be converted into "importedStat" by webpack-imported
without adding plugin.
Alternatively - you can discover all resources you have to preload using flush-webpack-chunks
1const { js, styles } = flushChunks(webpackStats, { 2 chunkNames, 3}); 4 5const prefetch = (targets, as) => targets.map(url => `<link as="${as}" rel="preload" href="${url}" />`).join(''); 6 7res.send(prefetch(scripts, 'script')); 8res.send(prefetch(stylesheets, 'style'));
DO NOT actually load reported resources - only preload them, and let webpack do rest.
Via assets.json
You you are using assets-webpack-plugin then you have only list of assets, without dependencies between. That's enought.
1const prefetchChunks = (chunks, assets) => 2 chunks 3 .map(chunk => 4 [ 5 assets[chunk].js && `<link rel="preload" as="script" href="${assets[chunk].js}" />`, 6 assets[chunk].css && `<link rel="preload" as="style" href="${assets[chunk].css}" />`, 7 ].join('') 8 ) 9 .join(''); 10 11res.send(prefetchChunks(chunkNames, assets));
Preloading
Proper preloading is available only with bundler integration. Calling component.preload
will not
only preload
it, but will execute
as well.
.preload
is equal do loading script as usual.
If you seek the best experience you might want to prefetch or preload only (network only), not load (network and CPU).
In order to prefetch(or preload) scripts - use webpack-imported
, as seen in examples above.
You need SSR step in order to use preloading!
Step 1 - expose known chunks
In order to prefetch or preload you should know scripts locations. This information is stored inside webpack, and you cannot access it from user code. As a result we have to duplicate this information:
1import { importAssets } from 'webpack-imported'; 2// react-imported-component data file 3import applicationImports from '../async-requires'; 4// webpack-imported data file 5import importedChunks from '../build/imported.json'; 6// 👆 this file is generated during the build, you cannot use it "IN" the build 7// that's why this is Server Side only component 8 9export const ScriptLocations = () => ( 10 <script 11 dangerouslySetInnerHTML={{ 12 __html: ` 13 window.KNOWN_SCRIPT_MARKS = ${JSON.stringify( 14 applicationImports.reduce((acc, [, chunkName]) => { 15 if (chunkName) { 16 acc[chunkName] = importAssets(importedChunks, chunkName).raw.load; 17 } 18 return acc; 19 }, {}) 20 )}; 21 `, 22 }} 23 /> 24);
Then add <ScriptLocations/>
somewhere in your SSR-ed head
.
Step 2 - preload
Then you will be able to prefetch(() => import('./home')
.
1import { getMarkedChunks, loadableResource } from 'react-imported-component'; 2 3// this function is partially duplicating webpack internals 4export const prefetch = importCallback => { 5 // get a "lodable" attached for a given import 6 const loadable = loadableResource(importCallback); 7 if (typeof document !== 'undefined') { 8 const prefix = __webpack_public_path__; 9 if (loadable) { 10 // get chunks used in loadable 11 const chunks = getMarkedChunks(loadable.mark); 12 chunks.forEach(chunk => { 13 // note the usage of KNOWN_SCRIPT_MARKS 14 const { js = [], css = [] } = window.KNOWN_SCRIPT_MARKS[chunk]; 15 js.forEach(script => { 16 const link = document.createElement('link'); 17 18 link.rel = 'prefetch'; 19 link.as = 'script'; 20 21 link.href = prefix + script; 22 document.head.appendChild(link); 23 }); 24 css.forEach(style => { 25 const link = document.createElement('link'); 26 27 link.rel = 'prefetch'; 28 link.as = 'style'; 29 30 link.href = prefix + style; 31 document.head.appendChild(link); 32 }); 33 }); 34 } 35 } 36};
Parcel integration
Use parcel-manifest
and getMarkedFileNames
(instead of getMarkedChunks
) to find which files were required and has to be imported.
Keep in mind - the base path would be different and you have to resolve
the right files in to the right files (/app/index
to index.js
).
CRA integration
Consider using concurrent-loading technique only.
React-snap
react-imported-component
is compatible with react-snap out of the box.
Works even better with react-prerendered-component
.
Webpack-external-import (or native import)
react-imported-component
is compatible with webpack-external-import,
as long as it executes imports
, thus executes custom logic
useImported
and Suspense
useImported
is not supposed to be used with Suspense (by design), while it could
1const MyComponent = () => { 2 const { loading, error, loadable, imported } = useImported(() => import('...')); 3 4 if (loading) throw loadable.resolution; // throw to the nearest Suspense boundary 5 if (error) throw error; // throw to the nearest Error boundary 6 7 // do something with `imported` value 8};
SSR (Server side rendering)
It was usually a headache - async components and SSR, which is currently sync. React-imported-component break this cycle, making ServerSide rendering sync, and providing comprehensive ways to rehydrate rendered tree on client. It will detect server-side environment and precache all used components.
Server Side Auto Import
On the server side imported
would auto-import any found import. As long as not all imports could be executed at Server Side you might
pop out this feature using a "magic comment".
1import(/* client-side */ './file');
Or file filtering
1import { setConfiguration } from 'react-imported-component';
2
3setConfiguration({
4 fileFilter: fileName => file.indexOf('/client') !== 0,
5});
.imported.js
There is possibility to finely control both with files are scanned, which imports are added and which chunks would be generated(webpackonly)
via .imported.js
at the root directory
💩 .js, not .ts
1// 👉 use provided helper for documentation and type safety 2const { configure } = require('react-imported-component'); 3 4modules.export = configure({ 5 testFile: fileName => true | false, 6 testImport: (targetFile, sourceFile) => true | false, 7 clientSideOnly: (targetFile, sourceFile, sourceComments) => true | false, 8 shouldPrefetch: (targetFile, sourceFile, sourceComments) => true | false, 9 shouldPreload: (targetFile, sourceFile, sourceComments) => true | false, 10 chunkName: (targetFile, sourceFile, sourceComments) => string | null | undefined, 11});
None of those methods are required.
.imported
could be used to:
- remove some files or imports
- autogenerate chunk names or prefetch/preload
Bundler independent SSR
It does not matter how do you bundle your application - it could be even browser. The secrect sause is a cli command, to extract all your imports into imports map, and use it later to load chunks by request.
- You might even dont have any separated chunk on the server side - it would still works.
- You might even ship module/nomodule scripts, using, for example, devolution - no additional configuration would be required.
Why you need SSR
In case of imported component SSR is a "dry run" of your application - an easy way to discover required pieces powered by zero latency(you are already on the server) and super fast speed connection (all scripts are in memory).
However - you dont need SSR to get the same benefits on pure ClientSideRendered solutions - prediction would be enought. The common approach is to
- load first part of components, including Providers, which would load something they need. Like translations.
- then hit, and load the current route
- then do the same with the sub route
This causes effect known as loading waves
, the effect SSR could mitigate almost in full.
However, nothing stops you from loading translation data in the parallel to the routes, and loading route and sub route in the same time, not sequentially. You can have backend-for-frontend, why not to have frontend-for-frontend? Just handle route, cookies, and whatever you could handle, outside of React. Redux-first-router and principles behind it are the great example of this idealogy.
Not using React.Lazy with React-Hot-Loader
There is design limitation with React.lazy support from RHL size, so they could not be reloaded without
state loss if lazy
is created not in the user space. At it would be created inside imported.
If React-Hot-Loader is detected lazy
switches to imported async
mode, this behaves absolutely the same.
Comparison table legend
Library
- the library nameSuspense
- does it support Suspense featureSSR
- does it support SSRHooks
- does it have hooks APILibrary
- does it support library, not Component level splittingNon-modules
- could it "import" generic promise, not a real dynamic module importimport('./${value}')
- does it support a full dynamic import - ability to import any file.babel macro
- ability to work with babel-plugin-macroswebpack only
- is this solution hard bould to webpack
Featured in
- https://medium.com/hackernoon/react-and-code-splitting-made-easy-f118befb5168
- https://dev.to/thekashey/react-imported-component-v6-4304
Other loaders
Another loaders exist, and the only difference is in API, and how they manage (or not manage) SSR.
-
(no SSR) React.Lazy
-
(webpack only) With react-loadable
-
(not compatible with hooks) react-async-component
-
(webpack only) loadable-components
-
(webpack only) react-universal-component
-
(not a component loader) use-sidecar
Licence
MIT
![Empty State](/_next/static/media/empty.e5fae2e5.png)
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 2/22 approved changesets -- score normalized to 0
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
project is not fuzzed
Details
- Warn: no fuzzer integrations found
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
branch protection not enabled on development/release branches
Details
- Warn: branch protection not enabled for branch 'master'
Reason
SAST tool is not run on all commits -- score normalized to 0
Details
- Warn: 0 commits out of 13 are checked with a SAST tool
Reason
148 existing vulnerabilities detected
Details
- Warn: Project is vulnerable to: GHSA-67hx-6x53-jw92
- Warn: Project is vulnerable to: GHSA-6chw-6frg-f759
- Warn: Project is vulnerable to: GHSA-v88g-cgmw-v5xw
- Warn: Project is vulnerable to: GHSA-93q8-gq69-wqmw
- Warn: Project is vulnerable to: GHSA-qwcr-r2fm-qrc7
- Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg
- Warn: Project is vulnerable to: GHSA-x9w5-v3q2-3rhw
- Warn: Project is vulnerable to: GHSA-w8qv-6jwh-64r5
- Warn: Project is vulnerable to: GHSA-257v-vj4p-3w2h
- Warn: Project is vulnerable to: GHSA-pxg6-pf52-xh8x
- Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275
- Warn: Project is vulnerable to: GHSA-gxpj-cx7g-858c
- Warn: Project is vulnerable to: GHSA-w573-4hg7-7wgq
- Warn: Project is vulnerable to: GHSA-vh7m-p724-62c2
- Warn: Project is vulnerable to: GHSA-r9p9-mrjm-926w
- Warn: Project is vulnerable to: GHSA-434g-2637-qmqr
- Warn: Project is vulnerable to: GHSA-49q7-c7j4-3p7m
- Warn: Project is vulnerable to: GHSA-977x-g7h5-7qgw
- Warn: Project is vulnerable to: GHSA-f7q4-pwc6-w24p
- Warn: Project is vulnerable to: GHSA-fc9h-whq2-v747
- Warn: Project is vulnerable to: GHSA-rv95-896h-c2vc
- Warn: Project is vulnerable to: GHSA-qw6h-vgh9-j6wx
- Warn: Project is vulnerable to: GHSA-43f8-2h32-f4cj
- Warn: Project is vulnerable to: GHSA-qqgx-2p2h-9c37
- Warn: Project is vulnerable to: GHSA-7r28-3m3f-r2pr
- Warn: Project is vulnerable to: GHSA-r8j5-h5cx-65gg
- Warn: Project is vulnerable to: GHSA-896r-f27r-55mw
- Warn: Project is vulnerable to: GHSA-9c47-m6qq-7p4h
- Warn: Project is vulnerable to: GHSA-76p3-8jx3-jpfq
- Warn: Project is vulnerable to: GHSA-3rfm-jhwj-7488
- Warn: Project is vulnerable to: GHSA-hhq3-ff78-jv3g
- Warn: Project is vulnerable to: GHSA-p6mc-m468-83gw
- Warn: Project is vulnerable to: GHSA-29mw-wpgm-hmr9
- Warn: Project is vulnerable to: GHSA-35jh-r3h4-6jhm
- Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv
- 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-92xj-mqp7-vmcj
- Warn: Project is vulnerable to: GHSA-wxgw-qj99-44c2
- Warn: Project is vulnerable to: GHSA-5rrq-pxf6-6jx5
- Warn: Project is vulnerable to: GHSA-8fr3-hfg3-gpgp
- Warn: Project is vulnerable to: GHSA-gf8q-jrpm-jvxq
- Warn: Project is vulnerable to: GHSA-2r2c-g63r-vccr
- Warn: Project is vulnerable to: GHSA-cfm4-qjh2-4765
- Warn: Project is vulnerable to: GHSA-x4jg-mjrx-434g
- Warn: Project is vulnerable to: GHSA-r8f7-9pfq-mjmv
- Warn: Project is vulnerable to: GHSA-rp65-9cf3-cjxr
- Warn: Project is vulnerable to: GHSA-hj48-42vr-x3v9
- Warn: Project is vulnerable to: GHSA-9wv6-86v2-598j
- Warn: Project is vulnerable to: GHSA-rhx6-c78j-4q9w
- Warn: Project is vulnerable to: GHSA-566m-qj78-rww5
- Warn: Project is vulnerable to: GHSA-7fh5-64p2-3v2j
- Warn: Project is vulnerable to: GHSA-hwj9-h5mp-3pm3
- Warn: Project is vulnerable to: GHSA-hrpp-h998-j3pp
- Warn: Project is vulnerable to: GHSA-p8p7-x288-28g6
- Warn: Project is vulnerable to: GHSA-7mwh-4pqv-wmr8
- Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw
- Warn: Project is vulnerable to: GHSA-m6fv-jmcg-4jfg
- Warn: Project is vulnerable to: GHSA-cm22-4g7w-348p
- 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-r628-mhmh-qjhw
- Warn: Project is vulnerable to: GHSA-9r2w-394v-53qc
- Warn: Project is vulnerable to: GHSA-qq89-hq3f-393p
- Warn: Project is vulnerable to: GHSA-4wf5-vphf-c2xc
- Warn: Project is vulnerable to: GHSA-72xf-g2v4-qvf3
- Warn: Project is vulnerable to: GHSA-7p7h-4mm5-852v
- Warn: Project is vulnerable to: GHSA-j8xg-fqg3-53r7
- Warn: Project is vulnerable to: GHSA-6fc8-4gx4-v693
- Warn: Project is vulnerable to: GHSA-3h5v-q93c-6h6q
- Warn: Project is vulnerable to: GHSA-c4w7-xm78-47vh
- Warn: Project is vulnerable to: GHSA-p9pc-299p-vxgp
- Warn: Project is vulnerable to: GHSA-p28h-cc7q-c4fg
- Warn: Project is vulnerable to: GHSA-ff7x-qrg7-qggm
- Warn: Project is vulnerable to: GHSA-4gmj-3p3h-gm8h
- Warn: Project is vulnerable to: GHSA-8r6j-v8pm-fqw3
- Warn: Project is vulnerable to: MAL-2023-462
- Warn: Project is vulnerable to: GHSA-vvj3-85vf-fgmw
- Warn: Project is vulnerable to: GHSA-pfrx-2q88-qq97
- Warn: Project is vulnerable to: GHSA-pfq8-rq6v-vf5m
- Warn: Project is vulnerable to: GHSA-2pr6-76vf-7546
- Warn: Project is vulnerable to: GHSA-8j8c-7jfh-h6hx
- Warn: Project is vulnerable to: GHSA-6c8f-qphg-qjgp
- Warn: Project is vulnerable to: GHSA-4xc9-xhrj-v574
- Warn: Project is vulnerable to: GHSA-x5rq-j2xg-h7qm
- Warn: Project is vulnerable to: GHSA-jf85-cpcp-j695
- Warn: Project is vulnerable to: GHSA-fhjf-83wg-r2j9
- Warn: Project is vulnerable to: GHSA-r683-j2x4-v87g
- Warn: Project is vulnerable to: GHSA-h9rv-jmmf-4pgx
- Warn: Project is vulnerable to: GHSA-hxcc-f52p-wc94
- Warn: Project is vulnerable to: GHSA-4g88-fppr-53pp
- Warn: Project is vulnerable to: GHSA-4jqc-8m5r-9rpr
- Warn: Project is vulnerable to: GHSA-vx3p-948g-6vhq
- Warn: Project is vulnerable to: GHSA-29xr-v42j-r956
- Warn: Project is vulnerable to: GHSA-662x-fhqg-9p8v
- Warn: Project is vulnerable to: GHSA-394c-5j6w-4xmx
- Warn: Project is vulnerable to: GHSA-78cj-fxph-m83p
- Warn: Project is vulnerable to: GHSA-fhg7-m89q-25r3
- Warn: Project is vulnerable to: GHSA-wr3j-pwj9-hqq6
- Warn: Project is vulnerable to: GHSA-pc5p-h8pf-mvwp
- Warn: Project is vulnerable to: GHSA-876r-hj45-fw7g
- Warn: Project is vulnerable to: GHSA-v63x-xc9j-hhvq
- Warn: Project is vulnerable to: GHSA-w5q7-3pr9-x44w
- Warn: Project is vulnerable to: GHSA-3fjq-93xj-3f3f
- Warn: Project is vulnerable to: GHSA-whgm-jr23-g3j9
- Warn: Project is vulnerable to: GHSA-8w4h-3cm3-2pm2
- Warn: Project is vulnerable to: GHSA-cwfw-4gq5-mrqx
- Warn: Project is vulnerable to: GHSA-g95f-p29q-9xw4
- Warn: Project is vulnerable to: GHSA-c6rq-rjc2-86v2
- Warn: Project is vulnerable to: GHSA-wxhq-pm8v-cw75
- Warn: Project is vulnerable to: GHSA-hr2v-3952-633q
- Warn: Project is vulnerable to: GHSA-3wcq-x3mq-6r9p
- Warn: Project is vulnerable to: GHSA-6h5x-7c5m-7cr7
- Warn: Project is vulnerable to: GHSA-qrmc-fj45-qfc2
- Warn: Project is vulnerable to: GHSA-xf7w-r453-m56c
- 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-6x33-pw7p-hmpq
- Warn: Project is vulnerable to: GHSA-c7qv-q95q-8v27
- Warn: Project is vulnerable to: GHSA-78xj-cgh5-2h22
- Warn: Project is vulnerable to: GHSA-2p57-rm9w-gvfp
- Warn: Project is vulnerable to: GHSA-fvqr-27wr-82fm
- Warn: Project is vulnerable to: GHSA-3mpr-hq3p-49h9
- Warn: Project is vulnerable to: GHSA-hxcm-v35h-mg2x
- Warn: Project is vulnerable to: GHSA-jv35-xqg7-f92r
- Warn: Project is vulnerable to: GHSA-c9g6-9335-x697
- 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-pv4c-p2j5-38j4
- Warn: Project is vulnerable to: GHSA-46c4-8wrp-j99v
- Warn: Project is vulnerable to: GHSA-9m6j-fcg5-2442
- Warn: Project is vulnerable to: GHSA-hh27-ffr2-f2jc
- Warn: Project is vulnerable to: GHSA-rqff-837h-mm52
- Warn: Project is vulnerable to: GHSA-8v38-pw62-9cw2
- Warn: Project is vulnerable to: GHSA-hgjh-723h-mx2j
- Warn: Project is vulnerable to: GHSA-jf5r-8hm2-f872
- Warn: Project is vulnerable to: GHSA-cf66-xwfp-gvc4
- Warn: Project is vulnerable to: GHSA-g78m-2chm-r7qv
- Warn: Project is vulnerable to: GHSA-9vvw-cc9w-f27h
- Warn: Project is vulnerable to: GHSA-phwq-j96m-2c2q
- Warn: Project is vulnerable to: GHSA-ghr5-ch3p-vcr6
- Warn: Project is vulnerable to: GHSA-ww39-953v-wcq6
- Warn: Project is vulnerable to: GHSA-mwcw-c2x4-8c55
- Warn: Project is vulnerable to: GHSA-qrpm-p2h7-hrv2
Score
1.7
/10
Last Scanned on 2025-01-27
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 MoreOther packages similar to react-imported-component
@johnny___nia/react-imported-component
I will import your component, and help to handle it
create-react-ts-component
Create React functional component directory with index file and imported styles
react-dynamic-imported-components
react-dynamic-imported-components
@cycle9898/react-custom-dropdown-component
This library provides a custom drop-down list React component that can be imported into any other React component.