How to add external Javascript in gatsby? - javascript

I want to know how to add external javascript file to gatsby, where should i put
these tag in which file ? And also how to import the file properly to the DOM.
Thanks

You can add this part of code in you gatsby-ssr.js, this add code in your balise .
export const onRenderBody = ({ setHeadComponents }) => {
setHeadComponents([
<link
rel="stylesheet"
href="/style.css"
/>
])
}
You Have the same for the body
export const onRenderBody = ({ setHeadComponents, setPostBodyComponents }) => {
setHeadComponents([
<link
rel="stylesheet"
href="/style.css"
/>
]),
setPostBodyComponents([
<script></script>,
]),
}

You can choose any one way as follows:
a. Use Plugin
You can use gatsby-plugins to add external scripts such as Google Tracking Code, Google Tag Manager, Hubspot code, etc.
In order to use gatsby plugin on your website, search for the plugin in gatsby org website https://www.gatsbyjs.org/plugins/ and follow the steps to add it in your site.
b. Use gatsby-ssr.js
Suppose you want to add scripts or a list of scripts but there is no plugin in gatsbyjs. Still, you can add external scripts.
For it, you need to use gatsby SSR API https://www.gatsbyjs.org/docs/ssr-apis/.

You can always use html.js to add HTML tags, but better use npm packages to add the libs.
Here are the docs on how to do it with html.js:
https://www.gatsbyjs.org/docs/custom-html/

Related

Next Js fails to load third party script in _document.js [duplicate]

I try to understand how the next.js Script tag with the strategy beforeInteractive works. For testing i just used lodash. But i keep getting a ReferenceError: _ is not defined. I thought when a script is loaded with beforeInteractive it should be globally available inside my page Component since it get injected into the initial Html from the server and i could use it for example in the useEffect hook to alter a div.
Can someone explain to me why it's not working or what i'm doing wrong?
I don't installed it via npm because im trying to figure out how it works.
I have a simple _document.js and i added a Next.js script tag with the strategy beforeInteractive to this _document.js. The next.js docs says:
This strategy only works inside _document.js and is designed to load scripts that are needed by the entire site (i.e. the script will load when any page in the application has been loaded server-side).
import { Html, Head, Main, NextScript } from 'next/document'
import Script from 'next/script'
export default function Document() {
return (
<Html>
<Head />
<body>
<Main />
<NextScript />
<Script
src="https://unpkg.com/lodash#4.17.20"
strategy="beforeInteractive"
></Script>
</body>
</Html>
)
}
Then i have a simple page Component inside the pages folder. I added the getServerSideProps function to use ServerSideRendering.
If you export a function called getServerSideProps (Server-Side Rendering) from a page, Next.js will pre-render this page on each request using the data returned by getServerSideProps.
import Head from 'next/head';
import {useEffect, useState} from 'react';
const TestComponent = () => {
const [change,setChange] = useState('not changed');
useEffect(()=> {
console.log(_);
setChange(_.join(['one','two'],' - '));
});
return (
<>
<Head>
<title>Test</title>
</Head>
<div>{change}</div>
</>
);
};
export async function getServerSideProps(context) {
return {
props: {},
}
}
export default TestComponent;
Update
Seems like it is indeed a bug which is fixed but not released yet
https://github.com/vercel/next.js/discussions/37098
Putting aside the fact that you should be importing Lodash as a node module, there does seem to be an issue when using next/script in _document (no matter what the external script actually is).
It turns out this is a Next.js bug that has been addressed in this PR in pre-release version v12.1.7-canary.8. To fix the issue in your project simply update Next.js to version >=12.2.0 (npm install next#latest).
As an alternative, you can use the <script> tag directly in the _document's <Head> with the defer property. This closely matches what the next/script would output.
import { Html, Head, Main, NextScript } from 'next/document'
export default function Document() {
return (
<Html>
<Head>
<script
type="text/javascript"
src="https://unpkg.com/lodash#4.17.20/lodash.js"
defer
></script>
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
First and foremost, I'm failing to see virtually any reason you'd want to do this, when you can (and should) simply use install it to node_modules. You're also going to possibly run the risk of the bundle having issues if the library type isn't a module and the next configuration requires a module.
Solution based on the question:
There's two ways.
Firstly, see the docs on this exact thing.
Please use the above method mentioned in the docs.
If that's not an option for whatever reason...
The second is a less than ideal, but working solution.
Create a folder for your static files. Ex: <root>/static/js/hello.js. Then in your _document file,
<script type="text/javascript" src="/static/hello.js"></script>

External script not loading on page change

I am trying to add a Trustpilot widget to my Gatsby.js website. It is required to load an external script from Trustpilot CDN.
<script type="text/javascript" src="//widget.trustpilot.com/bootstrap/v5/tp.widget.bootstrap.min.js" async></script>
I have tried multiple ways to add this script to my component. The first thing I tried was React Helmet. I added using the following code:
<Helmet>
<script type="text/javascript" src="//widget.trustpilot.com/bootstrap/v5/tp.widget.bootstrap.min.js" async></script>
The script seems to load when I initially load a page. Once I navigate to a different page, the styling goes away. As I reload, it comes back.
I tried adding the script inside componentDidMount()
componentDidMount() {
var addScript = document.createElement('script');
addScript.setAttribute('src', '//widget.trustpilot.com/bootstrap/v5/tp.widget.bootstrap.min.js');
document.body.appendChild(addScript);
}
If you want your script (or any other component) to be persistent through your site, you need to use wrapPageElement or wrapRootElement APIs. Both APIs are suggested to be placed in gatsby-browser.js as well as in gatsby-ssr.js
Disclaimer: componentDidMount() will be triggered every time the DOM tree is loaded, it won't work for your use-case.
The issue here is that you are adding a non-React asset, not a component. You can try:
export const wrapPageElement = ({ element, props }) => {
return <SomeWrapper {...props}>{element}</SomeWrapper>;
};
Then, create a component called SomeWrapper and place your <Helmet>:
const SomeWrapper = (props) =>{
return <div>
<Helmet>
<script type="text/javascript" src="//widget.trustpilot.com/bootstrap/v5/tp.widget.bootstrap.min.js" async />
</Helmet>
{props.children}
</div>
}

How to activate Material Design JS?

import {MDCTextField} from '#material/textfield';
const textField = new MDCTextField(document.querySelector('.mdc-text-field'));
#import "#material/textfield/mdc-text-field";
<head>
<link href="https://unpkg.com/material-components-web#latest/dist/material-components-web.min.css" rel="stylesheet">
<script src="https://unpkg.com/material-components-web#latest/dist/material-components-web.min.js"></script>
</head>
<div class="mdc-text-field">
<input type="text" id="my-text-field" class="mdc-text-field__input">
<label class="mdc-floating-label" for="my-text-field">Hint text</label>
<div class="mdc-line-ripple"></div>
</div>
I'm learning to work with Material Design. I thought it worked like bootstrap, meaning there is a CDN and then you just add the classes you need, so I got the CDN from this link:
https://material.io/develop/web/docs/getting-started/
After I added the CDN I got the css working, but not JavaScript. In the instructions it says:
…and instantiate JavaScript:
mdc.ripple.MDCRipple.attachTo(document.querySelector('.foo-button'));
How do I instantiate Javascript?
I tried to put this code between script tags, but that didn't work. I think I'm missing some code here.
Update: The JS CDN seem to work but in each compenente I get an instruction for JavaScript Instantiation for example in this link:
https://material.io/develop/web/components/input-controls/text-field/
import {MDCTextField} from '#material/textfield'; const textField =
new MDCTextField(document.querySelector('.mdc-text-field'))
My question is where do i insert this code for the component to work.
you need to add mdc.{component}.MDC{component} instead if you use cdn
const textField = new mdc.textField.MDCTextField(document.querySelector('.mdc-text-field'));
<head>
<link href="https://unpkg.com/material-components-web#latest/dist/material-components-web.min.css" rel="stylesheet">
<script src="https://unpkg.com/material-components-web#latest/dist/material-components-web.min.js"></script>
</head>
<label class="mdc-text-field mdc-text-field--filled">
<span class="mdc-text-field__ripple"></span>
<span class="mdc-floating-label" id="my-label-id">Hint text</span>
<input class="mdc-text-field__input" type="text" aria-labelledby="my-label-id">
<span class="mdc-line-ripple"></span>
</label>
Please also mention how your code looks like right now.
Based on your question, it seems like you may have missed to mention script tag with material design URL in your HTML head tag. Add following code and see if it helps.
<head>
<link href="https://unpkg.com/material-components-web#latest/dist/material-components-web.min.css" rel="stylesheet">
<script src="https://unpkg.com/material-components-web#latest/dist/material-components-web.min.js"></script>
</head>
Because the browser doesn’t understand ES6 modules just yet, we need tools to make them work today. A JavaScript bundler takes in our Modules and compiles them into a single JavaScript file or multiple bundles for different parts of your application.
There are few popular bundlers like webpack, Browserify, Rollup, JSPM etc.
In your case, you are just starting off on how to use modules, you may face difficulties implementing boilerplate for importing modules ES2015 way.
However, you may want to clone Material Design repo because it gives you boilerplate that enables to you to use import module function right away, this will be straight forward and clear to you
https://codelabs.developers.google.com/codelabs/mdc-101-web/#1
Prior to get started on this, you need to install GIT, Node, and NPM on your machine.
Clone their starter repo and cd into cloned directory
git clone https://github.com/material-components/material-components-web-codelabs
cd material-components-web-codelabs/mdc-101/starter
Now, install all the dependancies listed in package.json with following command
npm install
and then run
npm start
it should start up development server. Now you can change index.html and create or change existing js files according to your requirement
For React users, make sure that you put the instantiate code in the Mounting phase, which means put new MDCTextField(Element) in the componentDidMount() function.
import './textfield.scss';
import React from 'react';
import { MDCTextField } from '#material/textfield';
export default class TextField extends React.Component {
// initialize the component after all DOM elements are well rendered
componentDidMount() {
const textfield = new MDCTextField(document.querySelector('.mdc-text-field'));
}
render() {
return (
<label className="mdc-text-field mdc-text-field--outlined">
<span className="mdc-notched-outline">
<span className="mdc-notched-outline__leading"></span>
<span className="mdc-notched-outline__notch">
<span className="mdc-floating-label" id="my-label-id">Your Name</span>
</span>
<span className="mdc-notched-outline__trailing"></span>
</span>
<input type="text" className="mdc-text-field__input" aria-labelledby="my-label-id"/>
</label>
);
}
}
I think the CDN JavaScript source might rely on jQuery in order to run. If my assumptions are correct, you will need to add a script tag referencing jquery before you load the material.io scripts.
jQuery CDN

why icon not display in angular 5?

I am trying to use image viewer plugin in angular but my icon is not display
here is my code
export class AppComponent {
name = 'Angular';
images=['https://images.pexels.com/photos/144240/goat-lamb-little-grass-144240.jpeg?w=1260&h=750&auto=compress&cs=tinysrgb']
}
https://stackblitz.com/edit/angular-u26jb5?file=src%2Fapp%2Fapp.component.ts
I am using this plugin
https://www.npmjs.com/package/ngx-image-viewer
I already follow all steps .I don't know why it is not showing icons
This happens because your url for image does not get sanitized by angular firewall. So angular is blocking the image from being loaded .
In order to sanititze the url
use safe pipe in code.
In view page:
<img [src]="catPictureUrl | safe: 'url'" alt="A Cat">
in app.component.ts:
public catPictureUrl: string = `https://www.petdrugsonline.co.uk/images/page-headers/cats-master-header`;
I really don't know why is this happening but even font-awesome is installed but the template is not getting the styles.
I tried adding the cdn to index.html and it just works fine.
Try adding cdn to index.html and you are good to go
<link href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">

React - insertion of third party script tag inside render rather than page head causes app failure

I'm writing a React component to use Mozilla's PDF.js project to render a document in HTML. I've gotten it working successfully when the example's Create-React-App project includes
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/1.8.527/pdf.min.js"></script>
in the index.html head block. If I remove it and insert it in the component render method, the application breaks. Is there a way to add a <script> tag to the body of the application
Background
According to the examples, there are two ways you can add a document to a page: render each page with the canvas tag, or use pdfjs-dist/web/pdf-viewer.js
Code
Following the Webpack examples (since this is a React project), I came up with the following code:
import React, {Component} from 'react';
import pdflib from 'pdfjs-dist';
import {PDFJS} from 'pdfjs-dist/web/pdf_viewer'
import 'pdfjs-dist/web/pdf_viewer.css';
export default class PDF extends Component {
constructor(props) {
super(props);
pdflib.PDFJS.workerSrc = require('file-loader!pdfjs-dist/build/pdf.worker');
this.file = props.file;
this.pdfViewer = null;
this._containerId = 'viewer_container';
this.pagesInit = this.pagesInit.bind(this);
}
componentDidMount() {
this._loadDocument();
}
pagesInit(e) {
this.pdfViewer.currentScaleValue = 'page-width';
}
_loadDocument() {
const container = document.getElementById(this._containerId);
this.pdfViewer = new pdflib.PDFJS.PDFViewer({
container: container
});
container.addEventListener('pagesinit', this.pagesInit);
const loadingTask = pdflib.getDocument(this.file);
loadingTask.promise.then((document) => {
this.pdfViewer.setDocument(document);
}).catch((err) => {
console.log(err);
});
}
render() {
return(
<div id={this._containerId}>
<div className="pdfViewer" id="viewer"></div>
</div>
)
}
}
However, for a reason unknown to me, I need to include the build of pdf.js in the head of the index page of the application so it is loaded before the bundle.
<!--
manifest.json provides metadata used when your web app is added to the
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdf.js/1.8.527/pdf.min.js"></script>
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Without it, the document will not render. This seems directly related to script ordering.
Part of the convenience of an external React component is its self-contained, and this script requirement means this component certainly is not self contained.
I've attempted to use react-async-script-loader to wrap the component in a Higher Order Component and retrieve the script, but the same error happens.
Is there another solution I should look at?

Categories