Most optimal way of importing external libraries in ReactJS - reactjs

The example is I have an external library such as Materialize.js, the components I need to render depend on it, what is the best way to include this library? The documentation of ReactJS refers to "Code Splitting" which I have done with my own JavaScript but cannot do with an external minimized script. What approach yields the highest performance?
I have tried the following
componentDidMount() {
const script = document.createElement("script");
script.src = "https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0-beta/js/materialize.min.js";
script.async = true;
script.onload = () => this.scriptLoaded();
document.body.appendChild(script);
}
scriptLoaded = async () => {
this.setState({materializeJsLoaded: true});
}
I have also then also tried including it in the index.html page at the bottom of the body tag.
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0-beta/js/materialize.min.js"></script>

Here is an article that discusses creating a custom css build and importing javascript on a per-component basis:
https://medium.com/#mattdlockyer/youre-using-materialize-css-wrong-470b593e78e9

Related

Dynamically load React component library from URL?

I am working on documentation tool for Typescript library. The idea is to leverage parcel's watch mode to continuously build the library, and use the same in a pre-built documentation app.
For the same I need to load a module library (built in another project) dynamically via URL.
<script type="module">
const libraryModule = "http://localhost:8080/lib.module.js";
const promise = import(libraryModule);
promise.then(library => {
// do something with library
window.ComponentLibrary = library;
});
</script>
However, parcel replaces the above import with require and the load fails. Using System.import throws System is not defined error.
I tried to use dynamic-import-polyfill and then initialize it as under and the use as below:
dynamicImportPolyfill.initialize({
modulePath: 'http://localhost:13090', // Defaults to '.'
importFunctionName: '$$import' // Defaults to '__import__'
const promise = $$import(libPath);
});
This throws the following error:
TypeError: Failed to resolve module specifier "react/jsx-dev-runtime". Relative references must start with either "/", "./", or "../"
I have also tried using script type as text/javascript but doesn't work either.
Looking for guidance on the best way here to get the component library loaded?
Figured it out: yes, we can load a component library as a module dynamically.
The issue was that React UMD module is not a pure ES/Javascript module. Also, with React 17, JSX components are picked from react/jsx-runtime. So, first I had to convert the React UMD module into an ES module - it's just a thin wrapper. Similarly, added a wrapper for jsx-runtime. To make things work had to use importmaps which are currently not supported in all browsers - see caniuse.com to check latest support.
This completes your setup and now your library compiled as ES module will work just fine. Below is what I used to get working:
<script type="importmap">
{
"imports": {
"react/jsx-runtime": "/react-jsx-runtime.js",
"react": "/react-as-es-module.js"
}
}
</script>
<script type="module" src="/component-library.js"></script>
<script type="module">
import * as MyComponentLib from "/component-library.js";
window.ComponentLibrary = { ...MyComponentLib };
</script>
Code for react-jsx-runtime.js looks as under:
import * as React from 'react';
export const jsx = React.createElement;
export const jsxs = React.createElement;
Code for react-as-es-module.js goes as:
import 'https://unpkg.com/react#17.0.2/umd/react.production.min.js';
const {
Children,
Component,
Fragment,
// and all other exports
} = React || {};
export {
Children,
Component,
Fragment,
// and all other exports
}
export default React;
I compiled component-library.js using ParcelJS using the type: "module" in package.json file. I would detail this in blog post and demo Github repo soon.
Hope this helps.

refactoring JS files in React

I am repeating this code is a few components and I find it repetitive:
componentDidMount(){
let scripts = [
{src:"/lib/jquery/jquery.min.js"},
{src:"/lib/jquery/jquery-migrate.min.js"},
{src:"/lib/bootstrap/js/bootstrap.bundle.min.js"},
{src:"/lib/easing/easing.min.js"},
{src:"/lib/superfish/hoverIntent.js"},
{src:"/lib/superfish/superfish.min.js"},
{src:"/lib/wow/wow.min.js"},
{src:"/lib/waypoints/waypoints.min.js"},
{src:"/lib/counterup/counterup.min.js"},
{src:"/lib/owlcarousel/owl.carousel.min.js"},
{src:"/lib/isotope/isotope.pkgd.min.js"},
{src:"/lib/lightbox/js/lightbox.min.js"},
{src:"/lib/touchSwipe/jquery.touchSwipe.min.js"},
{src:"/lib/main.js"},
{src:"/contactform/contactform.js"}
]
//Append the script element on each iteration
scripts.map(item => {
const script = document.createElement("script")
script.src = item.src
script.async = false
script.defer = false
document.body.appendChild(script)
})
}
I am not sure how I can put all this into one JS file so that I could just use the import statement.
Many thanks in advance and greatly appreciated,
Put these scripts in the root of your app. Use react-inline-script to avoid manually manipulating the DOM yourself.
Or
Install the npm packages for the scripts you need (when available) and import the module you need using ES6 imports.

Unable to Inject 3rd Party Scripts in Gatsby

The following code is required to be injected into the head for Sovrn display ads:
<script type="application/javascript">var googletag=googletag||{};googletag.cmd=googletag.cmd||[];googletag.cmd.push(function(){googletag.pubads().disableInitialLoad()});</script><script type="application/javascript" src="//ap.lijit.com/www/headerauction/headersuite.min.js?configId=XXXX"></script>
It looks for a div with ID="21728840" to display an ad for that div. I'm using Netlify so injecting this script into the head is not an issue, but Netlify does this post-process. Therefore, by the time, the script loads, it is not able to find the ID since the element is not defined, and returns a 403 error. I looked at many suggestions, and tried to use useEffect in the file where the ad is like so:
export const BlogIndexTemplate = ({ posts, title...
...
useEffect(() => {
var googletag = googletag || {}
googletag.cmd = googletag.cmd || []
googletag.cmd.push(function() {
googletag.pubads().disableInitialLoad()
})
const script = document.createElement('script')
script.async = true
script.src =
'//ap.lijit.com/www/headerauction/headersuite.min.js?configId=XXXX'
document.head.appendChild(script)
}, [])
...
{!!posts.length && (
<section className="section">
<div className="container">
<PostSection posts={filteredPosts} />
</div>
</section>
)}
The ad container is located in PostSection like so:
class PostSection extends React.Component {
...
<div className="sidebar-sticky-container">
<div className="ad-skyscraper-container sticky-widget">
<div id="21728840"></div>
I'm not sure what other approach I could try to get the script injected, and manipulate the div with ID 21728840 to display the ad.
After a lot of research, I discovered that using useEffect and most of the suggestions online are unnecessary for Gatsby. To inject a 3rd party script, one needs to create a gatsby-ssr.js file in the root directory. Inside this file, one should have the following for a basic set up:
const React = require('react')
exports.onRenderBody = function({
setHeadComponents,
setPreBodyComponents
}) {
setHeadComponents([
<script
dangerouslySetInnerHTML={{whateveryouneedtoset}}>
])
setPreBodyComponents([
<script
dangerouslySetInnerHTML={{whateveryouneedtoset}}>
])
}
All options for using the gatsby-ssr.js file can be found here: Gatsby SSR

Not able to connect AdSense to Gatsby blog

I've been trying to connect my AdSense account with my Gatsby blog and it seems impossible. AdSense is asking me to place this code between the head tag of my html
<script data-ad-client="ca-pub-XXXXXXXXXXXXXXXX" async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script>
I've tried gatsby adsense plugins and other things and AdSense keeps telling me the code is not in the website. Since the website is hosted in S3, I downloaded the generated index.html and changed the code and re uploaded it. I think the problem is due to an added attribute called data-checked-head to the script tag, so even though I add the code above, what I see in the browser is this:
<script data-ad-client="ca-pub-XXXXXXXXXXXXXXXX" async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js" data-checked-head="true"></script>
If this code is what AdSense sees, then of course he doesn't recognize it. Does anyone know what can I do in this case?? Or why is this attribute even there?? Thanks
I can't answer about the details of AdSense but I have had problems with meta tags in the head of HTML myself. Here's two possibilites to debug your code in regards to Gatsby:
Many plugins are disabled by default in development mode. Try gatsby build and gatsby serve and then check if it works with plugins.
Use react-helmet to place your script tag in the head of HTML. Use gatsby build and gatsby serve for testing this as well.
You can use gatsby-plugin-google-adsense for displaying ads on your site.
The best way I found is from this article, which suggest a simple React implementation of Google AdSense.
In your gatsby-ssr.js file:
const React = require('react')
const HeadComponents = [
<script
src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-XXXX"
crossOrigin="anonymous"
async
/>,
]
exports.onRenderBody = ({ setHeadComponents }, pluginOptions) => {
setHeadComponents(HeadComponents)
}
Then you create a Banner component to include in your Gatsby.js pages:
const Banner: React.FC<BannerProps> = ({
className,
style,
layout,
format,
client = 'ca-pub-XXXX',
slot,
responsive,
layoutKey,
}) => {
useEffect(() => {
try {
const adsbygoogle = window.adsbygoogle || []
adsbygoogle.push({})
} catch (e) {
console.error(e)
}
}, [])
return (
<div className="banner-container">
<ins
className="adsbygoogle"
style={style}
data-ad-layout={layout}
data-ad-format={format}
data-ad-client={client}
data-ad-slot={slot}
data-ad-layout-key={layoutKey}
data-full-width-responsive={responsive}
/>
</div>
)
}
Full article here.

How to use CDN Imports in a React-Project

My project is based on create-react-app and now I want to use Here Maps. Their documentation recommends loading the modules with CDN and I cant find any NPM packages for it. My question now is: how can I load the CDN properly?
I know there is the possibility to just put the CDN link inside my index.html file but this seems not to be the right solution I think.
After trying some things out, I found a solution for this use case.
I installed this package "html-webpack-externals-plugin".
All you have to do is read the documentation for your use case. The "CDN-Use-Case" is also described.
For accessing the functions from the external JS-API you have to put a "window." in front of the function for example like this:
const map = new window.H.Map();
Hope this helps somebody!
You can programmatically add JS script tags. Here's an example
function loadScript( {src, id, callback} ) {
if(id && document.getElementById(id)){
return; // don't accidentally re-add
}
const script = document.createElement( 'script' );
if(callback){
script.onload = callback;
}
if(id){
script.setAttribute( 'id', id );
}
script.setAttribute( 'src', src );
document.body.appendChild( script );
}
Usage example
componentDidMount(){
loadScript({
src: 'http://js.api.here.com/v3/3.0/mapsjs-core.js',
id: 'script-mapsjs-core',
callback: () => this.setState({mapsjsCoreLoaded: true})
});
}

Resources