I can't include a script in helmet gatsby.
The script I want to include is this:
<script src = "assets / vendor / jquery / jquery.min.js"> </script>
I tried doing this and the console gives me an error:
import Helmet from "react-helmet";
import {withPrefix} from "gatsby";
<Helmet>
<script src = {withPrefix ('masonry.js')} />
</Helmet>
with this syntax I also tried and it gives me an error:
<Helmet>
<script src = "http://netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js" type = "text / javascript" />
</Helmet>
How would it be solved?
You are mixing a lot of stuff there. If your assets are internal, like the one you have in the first and second snippet, add it in your /static folder and import it like:
import { withPrefix } from "gatsby"
// ...
<Helmet>
<script src={withPrefix('jquery.min.js')} type="text/javascript" />
</Helmet>
Note the white spaces in the code, you should trail them.
If your assets are external third-party assets you can also import them in your <Helmet>, but without using withPrefix inner function. Just:
<Helmet>
<script src="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js" type = "text / javascript" />
</Helmet>
Like any other component in React, your <Helmet> tag must be wrapped with something to avoid parsing issues, use it always like:
const IndexPage = () => (
<Layout>
<Helmet>
<script src="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js" type="text/javascript" />
</Helmet>
</Layout>
)
Related
I have a NextJS application where a third party script is only needed on certain pages. Currently it is firing on all pages, but this is causing some issues.
It's currently added after the closing body tag via a custom _document.js file. As the script has to go in the body, I can't use the head option in NextJS.
What would be the best way to only have this fire on a specific page template?
import { Html, Head, Main, NextScript } from 'next/document';
import Script from 'next/script';
export default function Document() {
return (
<Html>
<Head></Head>
<body>
<Main />
<NextScript />
{/** Below script only needed on certain pages */}
<script
src="xxx"
id="widget"
/>
</body>
</Html>
)
}
You should probably do this in _app.js instead:
import Script from 'next/script'
const allowedPages = new Set([...]);
export default function MyApp({ Component, pageProps }) {
const { asPath } = useRouter();
const enableScript = allowedPages.has(asPath);
return (
<>
<Component {...pageProps} />
{enableScript && <Script id="widget" src="xxx" />}
</>
)
}
Because you'll have access to useRouter and it will update on every page navigation. _document.js is only used on the first SSR
I am going to use a theme of themeforest on Next.js
I tried to load jquery core and some plugins, but Nextjs can't load it.
import { useEffect } from "react"
import { SessionProvider } from "next-auth/react"
import Script from 'next/script'
import '../public/plugin/datatables/responsive.dataTables.min.css'
import '../public/plugin/datatables/dataTables.bootstrap5.min.css'
import '../public/css/cryptoon.style.min.css'
// import "./styles.css"
export default function App({ Component, pageProps }) {
return (
<div>
<SessionProvider session={pageProps.session}>
<Component {...pageProps} />
</SessionProvider>
<Script type="text/javascript" src="/bundles/libscripts.bundle.js" strategy="lazyOnload" />
<Script type="text/javascript" src="/bundles/apexcharts.bundle.js" strategy="lazyOnload" />
<Script type="text/javascript" src="/js/template.js" strategy="lazyOnload" />
<Script type="text/javascript" src="/js/page/index.js" strategy="lazyOnload" />
</div>
)
}
But a bunch of errors have occurred:
Unhandled Runtime Error
TypeError: Cannot read properties of null (reading 'addEventListener')
Call Stack
HTMLDocument.<anonymous>
/js/template.js (185:18)
e
/bundles/libscripts.bundle.js (1:29754)
t
/bundles/libscripts.bundle.js (1:30078)
....
How to load template(HTML/CSS/JAVASCRIPT) to Nextjs component?
I would recommend you to use next/head I normally use this to put my scripts but it depends on your case, remember that using different strategies (like lazyOnload) and the order in some cases is important, but if you require to use next/script as the docs says then, check your strategies try with other ones like beforeInteractive and double check the order in which your scripts should be loaded and if you continue getting those errors probably the error is related with the content of your scripts, open your network tab and inspect what happened.
I am using html.js to load custom script. I have created a js file in static folder custom.js but when I am running my project it loads the script only once on first time page load but when I am navigation to other page it not loading the script.
My custom.js file
$(document).ready(function () {
console.log("in ready");
});
My html.js file
import React from "react";
import PropTypes from "prop-types";
import { withPrefix } from "gatsby";
export default function HTML(props) {
return (
<html {...props.htmlAttributes}>
<head>
<meta charSet="utf-8" />
<meta httpEquiv="x-ua-compatible" content="ie=edge" />
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no"
/>
<script
type="text/javascript"
src="https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis.min.js"
></script>
<link
href="https://cdnjs.cloudflare.com/ajax/libs/vis/4.21.0/vis.min.css"
rel="stylesheet"
type="text/css"
/>
{props.headComponents}
</head>
<body {...props.bodyAttributes}>
{props.preBodyComponents}
<div
key={`body`}
id="___gatsby"
dangerouslySetInnerHTML={{ __html: props.body }}
/>
{props.postBodyComponents}
<link
rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css"
/>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
<script
type="text/javascript"
src={withPrefix("js/custom.js")}
></script>
</body>
</html>
);
}
HTML.propTypes = {
htmlAttributes: PropTypes.object,
headComponents: PropTypes.array,
bodyAttributes: PropTypes.object,
preBodyComponents: PropTypes.array,
body: PropTypes.string,
postBodyComponents: PropTypes.array,
};
What I am doing here wrong ? Why it's loading script only once ? What I have to do load custom.js script on every page navigation?
I have also tried to include custom.js inside my Layout file in <Helmet></Helmet> but same issue.
Thanks
What I am doing here wrong ? Why it's loading script only once ? What
I have to do load custom.js script on every page navigation?
I think that there is a misunderstanding and a mix of context on how React and old-fashioned scripting like jQuery works. In the end, Gatsby is a React-based application.
Among saying that Reacts manipulates a virtual DOM (vDOM) and jQuery points directly to the DOM, which has an extremely high-cost impact on performance. If you mix both approaches outside the scope of React, you can block React's hydration, potentially breaking your application.
You can simply create a useEffect hook with empty dependencies ([]), which will be triggered once the DOM tree is loaded for each page it's included. React's lifecycle should work for your use-case without overkilling the customization of the HTML generated by Gatsby.
Your custom.js file must have something exported. As simply as:
const customJS =()=> console.log("I'm ready");
export default customJS;
Then, on any page:
import React, {useEffect} from "react";
import customJS from "../path/to/custom.js";
const AnyPage =(props)=>{
useEffect(()=>{
customJS()
}, [])
return <div>Some content for AnyPage()<div>
}
export default AnyPage;
customJS() will be triggered only one time per page, once the DOM is loaded.
Please, don't use jQuery along with React, it's not needed.
I'm trying to embed a tlk.io chat widget on my Gatsby site since no similar plugins seem to exist. I'm using the react-helmet plugin to embed that script, but nothing shows up on my page. My code you can find below.
I think it has to do with the fact that the script relies on this data-channel attribute in the div tag, but I have no idea what to do with regards to that.
import React from "react"
import Helmet from "react-helmet"
import Layout from "../components/layout"
import SEO from "../components/seo"
const LivePage = () => (
<Layout>
<SEO title="Live" />
<Helmet>
<div id="tlkio"
data-channel="hey"
style={{width:'auto',
height:400}}></div>
<script src="http://tlk.io/embed.js" type="text/javascript"></script>
</Helmet>
</Layout>
)
export default LivePage
According to Gatsby documentation about Helmet, and React Helmet <Helmet> component allows you to insert a few code that will be placed after compilation inside the <head> tag.
So, in your code, you need to remove the <div> tag and it will work like a charm.
import React from "react"
import Helmet from "react-helmet"
import Layout from "../components/layout"
import SEO from "../components/seo"
const LivePage = () => (
<Layout>
<SEO title="Live" />
<Helmet>
<script src="https://tlk.io/embed.js" type="text/javascript"/>
</Helmet>
</Layout>
)
export default LivePage
I've tested in my local machine and it works perfectly as it is shown in the following screenshot:
React Helmet is a plugin that adds its children to head tag of your webpage. You cannot add div element to head, but instead inside body of the website. Just put that div somewhere outside Helmet and you should be fine.
I'm integrating an existing React app into Next.js for mainly SEO features.
i pasted the css files links inside the <Header> tag in Next.js and they seem to work just fine. when i tried to do the same with the javascript files using the <script> tag, it doesn't execute the code inside those scripts. but i can see them loaded with http 200 in the chrome dev tools.
I tried using a library called Loadjs from npm to load the scripts inside componentDidMount but i got the exact same result as using <script> tag.
is there a proper way to do such simple thing in Next.js that i'm not aware of ?
Here's the code included in the pages/index.js file.
import React from "react"
import Head from 'next/head'
import MyAwesomeComponent from "../components/mycomponent.js"
export default () => (
<div>
<Head>
<link type="text/css" rel="stylesheet" href="static/css/chatwidget.css" />
<link type="text/css" rel="stylesheet" href="static/css/download.css" />
<script type="text/javascript" src="static/libs/jquery.min.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/malihu-custom-scrollbar-plugin#3.1.5/jquery.mCustomScrollbar.concat.min.js"></script>
<script type="text/javascript" src="static/libs/bootstrap.min.js"></script>
<script type="text/javascript" src="static/libs/owl.carousel.min.js"></script>
<script type="text/javascript" src="static/scripts/chatHead.js"></script>
<script type="text/javascript" src="static/libs/jquery.magnific-popup.js"></script>
</Head>
<MyAwesomeComponent /> {/* a simple React component that returns : <p>Hello World </p>*/}
</div>
)
Sorry for the late answer.
it turned out that all the scripts i linked missed one script that would actually run the functions for each action.
This works to me:
Create a folder for your static files:
<root>/public/static/script.js
in your index.js at <root>/pages/index.js
import Head from 'next/head';
import MyAwesomeComponent from '../components/mycomponent';
export default () => (
<div>
<Head>
<script type="text/javascript" src="/static/script.js"></script>
</Head>
<MyAwesomeComponent />
</div>
)
Note that static is the name I used in this example, it's not a requirement, it would work with any other folder name.
With the below approach you can easily put a script file's raw script text into a generated Next.js HTML page's <head> without screwing around with character escaping, formatting and general pretending that we aren't actually just building an HTML page in the end anyways.
There are many use cases you may want a script to run without going to network. Ex: 3rd party scripts, monitoring / analytics scripts that expect to be in the <head> without a separate network load. Many of these come minified, mangled, you-name-it and are just supposed to be copy, paste, move on with life.
Next.js makes this very hard pretending that everything with web development is magically React and Webpack all the time now (I wish right?)
The best developer experience way I've found is to do this:
_document.js
...
<Head>
<script type="text/javascript" dangerouslySetInnerHTML={{ __html: process.env.rawJsFromFile }}></script>
</Head>
...
next.config.js
https://github.com/vercel/next.js/blob/canary/packages/next/next-server/server/config.ts#L33
module.exports = {
env: {
rawJsFromFile: fs.readFileSync('./rawJsFromFile.js').toString()
}
}
rawJsFromFile.js
alert('Freedom!!!!!!!!!!!!!!!');
// and other 3rd party script junk, heck even minified JS is fine too if you need
Hope this saves someone from hours of frustration that I endured coming up with this... ðŸ˜
You can also run js code this
<script
dangerouslySetInnerHTML={{
__html: `
let a = 1;
functionCall();
`,
}}
></script>
With Next.js v11 and onward, you can use the Next component Script
https://nextjs.org/blog/next-11#script-optimization
<Script
src="..."
strategy="beforeInteractive"
/>
May this helps you Nextjs public folder
Move your static folder into public folder in your root directory
export default () => (
<div>
<Head>
<link type="text/css" rel="stylesheet" href="/static/css/chatwidget.css" />
<link type="text/css" rel="stylesheet" href="/static/css/download.css" />
<script type="text/javascript" src="/static/libs/jquery.min.js"></script>
...
</Head>
<MyAwesomeComponent />
</div>
)
This is what I tried and it worked for me.
I used two files entry-script.js and main-script.js. I put these like this
<root>/static/entry-script.js and <root>/static/main-script.js
The content of entry-script.js is below.
(function (d, t) {
t = d.createElement("script");
t.setAttribute("src", "/static/main-script.js");
d.getElementsByTagName("head")[0].appendChild(t);
})(document);
and the main logic is in the file main-script.js.
In the file _doucment.js of NextJS I included my file entry-script.js in body like below
class MyDocument extends Document {
render() {
return (
<Html>
<Head>
<link
rel="stylesheet"
href="https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&display=swap"
/>
</Head>
<body>
<script
type="text/javascript"
src="/static/entry-script.js"
></script>
<Main />
<NextScript />
</body>
</Html>
);
}
}
export default MyDocument;
MyDocument.getInitialProps = async (ctx) => {
// Resolution order
//
// On the server:
// 1. app.getInitialProps
// 2. page.getInitialProps
// 3. document.getInitialProps
// 4. app.render
// 5. page.render
// 6. document.render
//
// On the server with error:
// 1. document.getInitialProps
// 2. app.render
// 3. page.render
// 4. document.render
//
// On the client
// 1. app.getInitialProps
// 2. page.getInitialProps
// 3. app.render
// 4. page.render
// Render app and page and get the context of the page with collected side effects.
const sheets = new ServerStyleSheets();
const originalRenderPage = ctx.renderPage;
ctx.renderPage = () =>
originalRenderPage({
enhanceApp: (App) => (props) => sheets.collect(<App {...props} />),
});
const initialProps = await Document.getInitialProps(ctx);
return {
...initialProps,
// Styles fragment is rendered after the app and page rendering finish.
styles: [
...React.Children.toArray(initialProps.styles),
sheets.getStyleElement(),
],
};
};
I wrote an article elaborating on this question, hopefully it comes in handy:
https://www.devtwins.com/blog/how-to-add-a-third-party-script-to-a-nextjs-website
Or if you want to try another way to import Js file like I did
import { useEffect } from "react";
function MyApp({ Component, pageProps }) {
useEffect(() => {
import("../styles/bootstrap.bundle.min.js");
}, []);
return <></>
};