React lazy loading javascript file - reactjs

I am trying to make my application more performant with React.lazy. As the Ethereum lightwallet is a huge file, I would like to put it into a separate bundle. The currently working import is the following:
import lightwallet from 'eth-lightwallet/dist/lightwallet.min.js';
When I try to import using the lazy syntax
const lightwallet = React.lazy(() => import('eth-lightwallet/dist/lightwallet.min.js'));
Only a React.lazy object ($$typeof: Symbol(react.lazy)) is returned instead of the lightwallet object. I think this is due to the fact that lightwallet doesn't have a default export. How could I get around this problem? Thanks!

I suggest following the example here:
https://reacttraining.com/react-router/web/guides/code-splitting
react-loadable is an npm package that makes code-splitting (a.k.a lazy loading) quite easy and also provides you the ability to render a loading component until the lazy load has finished.
The only gotcha is that if you're using Babel to transpile your code bundles, you'll have to add support for the Dynamic Import syntax, webpack already has this by default, but Babel doesn't.
The Babel Plugin:
#babel/plugin-syntax-dynamic-import
will make this possible by adding support for the syntax.
I recommend react-loadable over React.lazy as it makes displaying a loading component while the lazy-load happens VERY easy, and provides you hooks to display an error component and retry the import in the case that it fails.
Read more about react-loadable here:
https://github.com/jamiebuilds/react-loadable
Your code would look something like this:
import Loadable from 'react-loadable';
import Loading from './YOUR-LOADING-COMPONENT';
const LoadableWallet = Loadable({
loader: () => import('eth-lightwallet/dist/lightwallet.min.js'),
loading: Loading,
});
export default class Wallet extends React.Component {
render() {
return <LoadableWallet/>;
}
}

Make sure that your react version is up to date in React v16.6.0. And also the core idea behind the React. lazy is React.lazy takes a function that must call a dynamic import(). This must return a Promise which resolves to a module with a default export containing a React component. But is this scenario min.js won't give any promise. Most probably That didn't work.

Related

Can't Lazy Load Firebase v9's "useAuthState" & "auth" in React

I have a React app that I'm trying to optimise. It's easy enough to Lazy Load components, but where I've found myself stuck is trying to asynchronously load and code-split the firebase dependencies.
They take up 80% of the initial loading js, and I don't need them to do anything until the page loads anyway, but they are bundled with the main.chunk.js.
I've tried to Lazy import:
import { useAuthState } from "react-firebase-hooks/auth";
import { auth } from "./firebase";
function App() {
const [user] = useAuthState(auth);
...
But you're not allowed to import Non-ReactComponent functions.
So I tried to load the useAuthState() in useEffect, but i'm not allowed to set hooks to a hook, which kind of makes sense.
This is the error I get:
React Hook "useAuthState" cannot be called inside a callback.
How can I Lazy Load the firebase components till after the page is initially loaded?
This is what the main.js is compiled with:
…js/main.bbdadee4.js(herospace.app)
../node_modules/#firebase/firestore/dist/index.esm2017.js
../node_modules/react-dom/cjs/react-dom.production.min.js
../node_modules/#firebase/firestore-compat/src/api/database.ts
../node_modules/#firebase/auth/src/core/auth/auth_impl.ts
../node_modules/#firebase/webchannel-wrapper/node_modules/google-closure-library/closure/goog/labs/net/webchannel/webchannelbase.js
But
../node_modules/react-dom/cjs/react-dom.production.min.js
is the only one I need to load the initial state of the page, which is why i'm trying to delay any firebase scripts from being loaded.
Any help is greatly appreciated, thank you!
I found a work-around, that doesn't bundle the firebase packages, or lazy load them, but instead I just extended a route for the authorized part of the app.
Instead of example.com/a-blog-post being on the same route as example.com/editProfile (a route that needs Firebase), I've moved everything to example.com/app/editProfile
I then only load Firebase imports in /app, and Lazy Load the component that renders when /app is reached.
I would still enjoy a lazy load option for firebase, but until then, this solution will do fine. Both mobile & desktop PageSpeed scores are green & 95+/100, so I'm satisfied.
I'm not marking this as the answer, because I still think there's a more proper & valid answer.

How to enable second level imports for my react component library packages?

I have created my own react component library using lerna and I have a package that holds multiple icons. I want to provide the possibility to use path imports, to avoid pulling in unused modules.
So I want to use
import PlusIcon from '#my-lib/icon/plus'
instead of
import { PlusIcon } from '#my-lib/icon'
in my react app, without any additional configuration.
I am struggling to find any documentation/tutorial for this, so I don't even know where to start. I would be grateful for any hint.
Thanks in advance!
Your plus file need to have an default export for the PlusIcon.
For instance
function PlusIcon = () => <p>+</p>;
export default PlusIcon;
As long as you have something like that, you can import it as
import PlusIcon from 'path-to-plus-icon

REACT import css and js files

My application needs to have two pages, one landing page and one admin page. Both pages use different themes. I could not integrate css and js files of these two pages in a single page application.
const jquery = require('mdbootstrap/js/jquery-1.11.3.min.js');
window.jQuery = jquery;
window.$ = jquery;
require('mdbootstrap/css/bootstrap.min.css');
require('template/homePage/js/plugins/owl-carousel/owl.carousel.css');
require('template/homePage/js/plugins/owl-carousel/owl.theme.css');
require('template/homePage/js/plugins/owl-carousel/owl.transitions.css');
require('template/homePage/css/animate.css');
require('template/homePage/js/plugins/YouTube_PopUp-master/YouTubePopUp.css');
require('template/homePage/css/preloader.css');
require('template/homePage/css/style.css');
require('mdbootstrap/js/popper.min.js');
require('mdbootstrap/js/bootstrap.min');
require('template/homePage/js/plugins/vivid-icons');
require('template/homePage/js/plugins/owl-carousel/owl.carousel.js');
require('template/homePage/js/plugins/YouTube_PopUp-master/YouTubePopUp.jquery.js');
require('template/homePage/js/plugins/wow/wow.js');
require('template/homePage/js/plugins/jquery.easing.min.js');
require('template/homePage/js/main');
this sample import not good work. And I need outside link css and js.
I have two problem one of them is $(...).scrollspy is not a function
other WOW is not a function.
None of them work in sequence.
When you want to import resources into your React app, you use imports like this:
// Import with variable assignation
import logo from './logo.png';
// Import without variable assignation
import './css/index.css'
You can read more about this in the create-react-app documentation:
https://create-react-app.dev/docs/adding-images-fonts-and-files/
You can read more about ES7 imports here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import
I see what you're trying to do is to add libraries and resources to your app component, like if were a common html file, you can't do that in React , you need to find an implementation.
It is not recommended to use jQuery with React, because you use jQuery to write code in a simple and fast way to create complex implementations, now those complex implementations can be made with just React and JS, that is what React is designed for.
Now I understand that you might want to use jQuery even do is not that recommendend, so here is a link where you can get jQuery to install it as a plugin for your React app
https://www.npmjs.com/package/jquery
You would be able to import it to your component like this:
import $ from "jquery";
To use Bootstrap in your React app you check out the documentation of an implementation of Bootstrap for React, react-bootstrap:
https://react-bootstrap.github.io/getting-started/introduction

ReactJS: Load .less only when component is used

I am probably missing a verry basic understanding of loading less files in ReactJS, but I am unable to solve the following issue.
I have created components and created less files for each of them, for example:
import * as React from 'react';
import Row from 'antd/lib/row';
import Col from 'antd/lib/col';
import { NavLink } from 'react-router-dom';
import '../styles/how-it-works-styles.less';
import Icon from 'antd/lib/icon';
class HowItWorksComponent extends React.PureComponent<Props> {
public constructor(props: Props) {
super(props);
}
public render() {
return (
<Row className={'steps-row'}>
Now when I load a page where this component is not at all used, the less file is stilling being loaded into the dom. Could someone explain why this is happening and how i can prevent this from happening?
Your problem is not really about less, but a general problem of how to bundle a web app optimally. Since you're not providing your main app component or your webpack config (assuming you're using webpack for bundling), I obviously don't know the details of your setup. In general however, the standard configuration is to bundle all the components and other imports reachable from the entry point file into one big file. The fact that you use react router or similar to split your app into "pages" doesn't change this, as react router only affects which components are rendered when, not the bundling.
If you need to split your app into multiple bundles (which IMO requires a relatively large app to consider) you can use dynamic imports to make some of your components "Loadable". This means they will be placed in a separate bundle which is only loaded as needed. There is a tutorial in the react router documentation on how to set this up: https://reacttraining.com/react-router/web/guides/code-splitting

Handling Browserify externals in Jest

I have a React project which uses Browserify externals. What's the best approach for testing components which reference external dependencies in Jest? For example - I have something like this...
import React from 'react';
import someExternal from 'someExternal';
class MyClass extends React.Component {
methodToTest() {
...
someExternal.doStuff();
...
}
}
This works as expected in the browser, the bundle which exposes someExternal is available, so someExternal's path can be resolved.
However in my unit test, the path to someExternal can't be resolved, because the bundle which contains someExternal is not available.
Sooo what's the best approach here?
OK solved. You can use manual mocks, which Jest loads before it tries to load the actual module.
https://facebook.github.io/jest/docs/manual-mocks.html

Resources