How to load theme javascript files in nextjs - javascript

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.

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>

Using <script> tags in React.js

I am trying to convert an html/css/js template into a React.js application. However, the template uses 2 files inside script tags.
<script class="u-script" type="text/javascript" src="jquery.js" defer=""></script>
<script class="u-script" type="text/javascript" src="nicepage.js" defer=""></script>
I tried using Helmet and ScriptTag to add these files into my React.js code, but it doesn't seem to work.
I tried:
function App() {
return (
<div>
<ScriptTag type="text/javascript" src="jquery.js" />
<ScriptTag type="text/javascript" src="nicepage.js" />
....
I get:
Uncaught SyntaxError: Unexpected token '<'
Am I doing something wrong? Is there a better way to go about it?
It's bad idea to use jQuery in ReactJS.
import React, { useEffect } from 'react';
const MyComponent = () => {
useEffect(() => {
document.body.appendChild(document.createElement("script")).src = "https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js";
}, [])
return (
<b>Your code</b>
)
}
export default MyComponent;
You should not use jQuery with react because JQuery modifies the DOM and react handles all DOM modifications. anyway if you want to get tons of bugs you could add JQuery to index.html in the public folder of your react app.

Include gatsby helmet script

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>
)

Embedding third party chat widget using Helmet

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.

Adding Bootstrap to Gatsby produces "Uncaught TypeError: Cannot read property 'fn' of undefined"

I'm using Gatsby 2.13.50 (CLI: 2.7.14). I'm trying to add Bootstrap 4 to my base template at /src/components/layout.js. It's used by /src/pages/index.js. Basically the directory structure as taught by most beginner tutorials.
I keep getting this error:
Uncaught TypeError: Cannot read property 'fn' of undefined
at bootstrap.js:6
at bootstrap.js:6
at bootstrap.js:6
Several solutions online say that it's because bootstrap.js is loading before jquery.js and popper.js. They say placing jquery.js and popper.js first and bootstrap.js last would solve it. My results vary depending on how I bring them into the file.
First, the code in layout.js:
import React from "react"
import Header from '../components/header'
import '../styles/bootstrap-4.3.1-dist/css/bootstrap.css'
import { withPrefix } from "gatsby"
// If I import them like this, Gatsby cannot find the files.
// import '../styles/site_js/jquery.js'
// import '../styles/site_js/popper.js'
// import '../styles/site_js/bootstrap.js'
import { Helmet } from "react-helmet"
const Layout = (props) => {
return (
<div>
<Header />
<main role="main" className="container">
{props.children}
</main>
// If I do this, the error happens all the time.
{/* <Helmet>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
</Helmet> */}
// If I do this, the error happens once every handful of times.
<Helmet>
<script src={withPrefix('site_js/jquery.js')} type="text/javascript" />
<script src={withPrefix('site_js/popper.js')} type="text/javascript" />
<script src={withPrefix('site_js/bootstrap.js')} type="text/javascript" />
</Helmet>
</div>
)
}
export default Layout
I found three ways to bring the JavaScript files into layout.js.
The first one imports the files like this:
import '../styles/site_js/jquery.js'
import '../styles/site_js/popper.js'
import '../styles/site_js/bootstrap.js'
With the above, Gatsby fails to compile. It gives this error for all three files:
Module not found: Error: Can't resolve 'popper.js' in '/home/testjs/hayatdemo/src/styles/site_js'
I double-checked and the files exist at that file path. So, I don't know what's wrong.
The second loads the three files from external sources:
<Helmet>
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
</Helmet>
With this, Gatsby compiles, but the error appears every time I reload the page.
Finally, this solution says to add the files to /static in the root directory and call them with the help of withPrefix(). Like so:
<Helmet>
<script src={withPrefix('site_js/jquery.js')} type="text/javascript" />
<script src={withPrefix('site_js/popper.js')} type="text/javascript" />
<script src={withPrefix('site_js/bootstrap.js')} type="text/javascript" />
</Helmet>
This works for the most part but the error returns once every handful of reloads.
How do I solve this problem?
I know JS files load in the order they are placed. But, just to make extra sure that they really, really, really do that, I decided to override Gatsby's default-html.js so that I could add jquery.js and popper.js to the <head> tag.
I don't know what default-html.js does. I just have a feeling it loads first and acts as some sort of basis for the whole project.
So, following Gatsby's docs on default-html.js, I first ran cp .cache/default-html.js src/html.js.
Now that it's named html.js in /src, I opened it up and added the two JS files to the <head> section:
import { withPrefix } from "gatsby"
<head>
...
<script async src={withPrefix('site_js/jquery.js')} type="text/javascript" />
<script async src={withPrefix('site_js/popper.js')} type="text/javascript" />
</head>
To make things load just a bit fast, I added async to their <script> tags following this wee article.
Now, it works perfectly.
However, I think the trade-off is, because the JS files load first, it might affect loading time. The files are not big and it's not critical for my project so I think it's ok. Maybe if loading time is more critical in future I might try npm install bootstrap or some other solution.
Best way to add Bootstrap and related dependency with gatsby is adding them in gatsby-browser.js like following:
Step 1: Run npm i bootstrap jquery popper.js
Step 2: In gatsby-browser.js add following imports
import "bootstrap/dist/css/bootstrap.min.css";
import "jquery/dist/jquery.min.js";
import "popper.js/dist/popper.min";
import "bootstrap/dist/js/bootstrap.min.js";
Note: if gatsby-browser.js is already present and contains ES5 code, then that needs to converted to ES6 first
Script tags should be placed at the end of page.
Whereas Helmet and gatsby-plugin-load-script try to append script into the head (see link).
Basically, you just need a gatsby-ssr.js file like this, no need plugin at all.
Create gatsby-ssr.js
import React from 'react'
export const onRenderBody = ({ setPostBodyComponents }) => {
setPostBodyComponents([
<script
key="https://code.jquery.com/jquery-3.2.1.slim.min.js"
src="https://code.jquery.com/jquery-3.2.1.slim.min.js"
integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN"
crossOrigin="anonymous"
defer
/>,
<script
key="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"
src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"
integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q"
crossOrigin="anonymous"
defer
/>,
<script
key="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"
src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"
integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl"
crossOrigin="anonymous"
defer
/>
])
}

Categories