A while ago I made a relatively massive app for a single developer for my own personal use - a "social media" of sorts. I wrote it in React.js
I have recently decided to revisit the app and revamp it - primarily make it server-side rendered using Next.js.
The key problem is loading the themes. I had a feature where I would programmatically add an external script tag to the end of the body which would manipulate the canvas and show some animations.
I had no issues when I worked with React, as everything got loaded the way I expected it to, but when it comes to Next, that simply isn't the case. The script tag loads, but the code doesn't get executed.
The most important files I have issues with are:
- My
_document.jsxfile:
import Document, { Html, Head, Main, NextScript } from 'next/document'
import { BASE_URL as base } from '../config'
class MyDocument extends Document {
static async getInitialProps(ctx) {
const initialProps = await Document.getInitialProps(ctx)
return { ...initialProps }
}
render() {
return (
<Html lang={"en"}>
<Head>
<link rel={"icon"} href={`${base}/short.png`} />
<link
rel={"apple-touch-icon"}
href={`${base}/apple-icon-180x180-dunplab-manifest-34821.png`}
/>
<link
href="https://fonts.googleapis.com/css?family=Roboto&display=swap"
rel={"stylesheet"}
/>
<link
rel={"stylesheet"}
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.10.2/css/all.min.css"
integrity={"sha256-zmfNZmXoNWBMemUOo1XUGFfc0ihGGLYdgtJS3KCr/l0="}
crossOrigin={"anonymous"}
/>
<link
rel={"stylesheet"}
href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
integrity={"sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh"}
crossOrigin={"anonymous"}
/>
<script
defer
src={`${base}/Vector2.js`}
charSet={"utf-8"}
></script>
<link rel={"manifest"} href={`${base}/manifest.json`} />
</Head>
<body>
<div className="canvas-wrapper">
<canvas id="canvas" className="canvas-bg"></canvas>
<NextScript />
</div>
<Main>
<script
defer
src="https://code.jquery.com/jquery-3.4.1.slim.min.js"
integrity={"sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n"}
crossOrigin={"anonymous"}
></script>
<script
defer
src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"
integrity={"sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo"}
crossOrigin={"anonymous"}
></script>
<script
defer
src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"
integrity={"sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6"}
crossOrigin={"anonymous"}
></script>
</Main>
</body>
</Html>
)
}
}
export default MyDocument
- My
_app.jsxfile:
import '../styles/globals.css'
import 'bootstrap/dist/css/bootstrap.min.css'
import { ThemeProvider } from "../contexts/ThemeContext";
import { FontProvider } from "../contexts/FontContext";
import { DevProvider } from "../contexts/DevContext";
import { LanguageProvider } from "../contexts/LanguageContext";
// import { SocketProvider } from "../contexts/SocketContext";
import { ColourProvider } from "../contexts/ColourContext";
import PageContent from '../components/layout/PageContent/PageContent';
import { useStore } from '../store';
import { useEffect } from "react"
import { Provider } from 'react-redux';
import Head from 'next/head';
import { BASE_URL as base } from '../config';
import Nav from "../components/layout/Nav/Nav"
import setAuthToken from '../utils/setAuthToken';
import { getUser } from '../actions/auth';
function MyApp({ Component, pageProps }) {
const store = useStore(pageProps.initialReduxState);
useEffect(() => {
if (localStorage.getItem('token')) {
setAuthToken(localStorage.getItem('token'))
}
store.dispatch(getUser())
})
return (
<>
<Head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta property="og:title" content="Impulse" />
<meta property="og:description" content="Make an impact. Change minds." />
<meta
property="og:image"
content={`${base}/favicon-96x96-dunplab-manifest-34821.png`}
/>
<meta
name="description"
content="Welcome to Impulse - make an impact, change minds. Impulse is dedicated to your enjoyment and pleasure!"
/>
<script defer src={`${base}/scripts/initlog.js`}></script>
<script defer src={`${base}/scripts/blurfocus.js`}></script>
<title>Impulse</title>
</Head>
<ColourProvider>
<DevProvider>
<FontProvider>
{/* <SocketProvider> */}
<ThemeProvider>
<LanguageProvider>
<Provider store={store}>
<PageContent>
<Nav />
<Component {...pageProps} />
</PageContent>
</Provider>
</LanguageProvider>
</ThemeProvider>
{/* </SocketProvider> */}
</FontProvider>
</DevProvider>
</ColourProvider>
</>
)
}
export default MyApp
- My
useScript.jshook
import { useRef } from "react"
import { BASE_URL as base } from "../config"
// actually, it's supposed to load a single script, not more of them
const useScripts = (script) => {
const scriptLoaded = useRef(false);
if (typeof window !== "undefined" && !scriptLoaded.current && script) {
const element = document.createElement("script");
element.src = `${base}/static/canvasThemes/${script}.js`;
element.type = "text/javascript";
const position = document.querySelector("head");
position.appendChild(element);
scriptLoaded.current = true;
}
};
export default useScripts
- My
PageContent.jsxfile, which was previously referenced in the_app.jsxfile:
import React, { useContext, useEffect, useState } from "react";
import { ThemeContext } from "../../../contexts/ThemeContext";
import { FontContext } from "../../../contexts/FontContext";
import { ColourContext } from "../../../contexts/ColourContext";
import StyledPageContent from '../../../styled/StyledPageContent';
import useScripts from "../../../hooks/useScript";
import cookie from 'cookie-cutter'
function PageContent(props) {
const { isDarkTheme, toggleTheme } = useContext(ThemeContext);
const { isLegacyFont } = useContext(FontContext);
const { colour } = useContext(ColourContext)
const [theme, setTheme] = useState("")
useEffect(() => {
const newOne = cookie.get("isDarkTheme")
console.log("NJUUAN _APP", newOne);
setTheme(() => newOne)
}, [])
useScripts(theme)
return (
<StyledPageContent
isDarkTheme={isDarkTheme}
isLegacyFont={isLegacyFont}
colour={colour}
>
{props.children}
</StyledPageContent>
);
}
export default PageContent;
I'm looking for a way to add a script programmatically and immediately execute it.
Important: ALL script tags I want to add are considered "themes", which would grab the canvas from the _document and manipulate its background colour/fill/add text etc.
I have been trying a million different things for a month now and am starting to lose hope.
Not sure if I'll get any help, but thanks in advance all the same!