Next 11 and adding Script tags not working. No scripts are rendered - next.js

I added my google tag manager to _app.js file, and its not showing. None of the scripts I am loading via the new "Script" tag are working.
<Head>
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no" />
<Script
src={`https://cdn.somelink.coom/${process.env.COOKIE_KEY}/block.js`}
strategy="beforeInteractive"
/>
<Script
src="https://cdn.somelink.com/scripttemplates/stub.js"
strategy="beforeInteractive"
/>
<Script
src={`https://www.googletagmanager.com/gtag/js?id=${process.env.GOOGLE_KEY}`}
strategy="afterInteractive"
/>
These are not working. Nothing is downloaded in the network tab etc. Nothing shows up on the page. Any thoughts?
Reminder: this is in the _app.js file.
Note: My pages are static generated.

next/script should not be wrapped in next/head
Ref.: Script Component
Do something like this:
import Script from "next/script";
const App = ({ Component, pageProps }) => (
<>
<Script
id="scriptAfterInteractive"
src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js"
/>
{/* eslint-disable-next-line react/jsx-props-no-​spreading */}
<Component {...pageProps} />
</>
);
export default App;

In addition to the requirement that Script (next/script) not be wrapped in Head (next/head), it should also not be placed within a custom _document.tsx unless you are not passing strategy="beforeInteractive" as mentioned in the docs.
I was unable to load a Cloudflare analytics script when placing it in _document.tsx, but it loaded successfully as a sibling to Component in _app.tsx.

Related

Integrating ShareThis with Next.js

Has anyone tried to integrate ShareThis with Next.js?
I'm getting "Hydration failed because the initial UI does not match what was rendered on the server." and this, I have ascertained, is down to the inclusion of the ShareThis script tag.
I'm not sure what I need to do in order to resolve this error.
This is my _document.tsx file, containing the offending script tag:
import { Html, Head, Main, NextScript } from "next/document";
const Document = () => (
<Html>
<Head>
<script
type="text/javascript"
src={`https://platform-api.sharethis.com/js/sharethis.js#property=${process.env.NEXT_PUBLIC_SHARETHIS_PROPERTY_ID}&product=sop`}
async
defer
></script>
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
export default Document;
Of course, the NEXT_PUBLIC_SHARETHIS_PROPERTY_ID variable from my .env file is being correctly populated.
You should be using next/script to load 3rd party scripts like ShareThis. Here's their documentation https://nextjs.org/docs/basic-features/script
Make sure to apply the <Script src="" /> component OUTSIDE of the next/head component, either above of below it.
Hope this helps.

next script does not work inside _document.js file nextjs

I have a nextjs project. I want to load two scripts using next/script inside _document.js.But when I place the Script tags into the body tag in _document.js, my scripts do not execute. I implemented according to the next/script guideline.What may be the issue here?
My code:
import { Html, Head, Main, NextScript } from "next/document";
import Script from "next/script";
export default function Document() {
return (
<Html>
<Head>
<link rel="preconnect" href="https://fonts.googleapis.com" />
</Head>
<body>
<Main />
<NextScript />
<Script
strategy="beforeInteractive"
src="src"
type="text/javascript"
charSet="UTF-8"
data-domain-script="id"
/>
<Script
strategy="beforeInteractive"
type="text/javascript"
dangerouslySetInnerHTML={{
__html: `
some js code
`,
}}
/>
</body>
</Html>
);
}
Initially in next/script api reference section, it was documented to use Script tags in _document.js with beforeInteractive strategy. But now their api reference has been updated and you must use Script tag with beforeInteractive strategy in pages/_app.js.
API Reference Link
Quote from next/script api reference
beforeInteractive scripts must be placed inside pages/_app.js and are 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).

Any nextjs example where I need to use _document over _app

It seems I can do everything that I need to do in both _app and _document for my application just in _app like
// _app.tsx
import Head from 'next/head';
export default function App({ Component, pageProps }) {
return (
<>
<Head>
<meta
name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no, user-scalable=no"
/>
<title>Payment</title>
</Head>
<Component {...pageProps} />
</>
);
}
Then when should I use _document necessarily? I found _document pointless because:
I shouldn't place viewport meta tags in _document as nextjs compiler warnings about it. (I thought _document is a good place for markups in head because _document gets called only once on server-side and not on client-side) If I can't place everything of a kind like head markup in one place, I'd like to avoid using that way.
You'll need _document if you want to customize a page's <html> and <body> tags. For example...
Adding the global lang attribute:
<Html lang="en">
Adding custom styles:
<body className="bg-white">
_document is where you put third party links and scripts
import Document, { Html, Head, Main, NextScript } from 'next/document'
class MyDocument extends Document {
render() {
return (
<Html>
<Head>
<link
href="https://fonts.googleapis.com/css2?family=Inter&display=optional"
rel="stylesheet"
/>
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
}
export default MyDocument
If you are using styled components you need to configure it in _document.jsx file.
https://github.com/massaaki/nextjs-with-styled-component/blob/main/src/pages/_document.tsx

How do I use PrimeVue in CustomElements?

I have a Vue 3 custom Element in which I want to use PrimeVue & PrimeFlex etc.
So I first create a Component, use the .ce.vue extension for the sfc mode and use the combination of defineCustomElement and customElements.define to compile it to a web component. Finally I use it in the index.html to see if it works in the Browser.
It works to some extent but not completely. For example, I am unsure about how to translate app.use(PrimeVue) for my case.
//customElement.ce.vue
<template>
<div>Test</div>
<AutoComplete field="name" />
</template>
<script lang="ts">
import { defineComponent } from "vue";
import AutoComplete from "primevue/autocomplete";
export default defineComponent({
name: "customElement",
props: {
msg: String,
},
components: { AutoComplete },
setup: () => {
console.log(JSON.stringify(theme));
return { PrimeVue };
},
styles: [],
});
</script>
<style scoped lang="scss"></style>
//main.ts
import { createApp, defineCustomElement } from "vue";
import App from "./App.vue";
//PrimeVue
import PrimeVue from "primevue/config";
import "/node_modules/primeflex/primeflex.css";
import "primevue/resources/primevue.min.css";
import "primevue/resources/themes/saga-blue/theme.css";
//CustomElement
import customElement from "#/components/customElement.ce.vue";
const customElementWC = defineCustomElement(customElement);
customElements.define("custom-element", customElementWC);
//Setup VueApplication for testing/reference, this works as expected.
const app = createApp(App);
app.use(PrimeVue);
app.mount("#app");
//index.html (for testing)
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
<link rel="icon" href="<%= BASE_URL %>favicon.ico" />
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript>
<strong
>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work
properly without JavaScript enabled. Please enable it to
continue.</strong
>
</noscript>
<div id="app"></div> //test app
<custom-element /> //the custom Web Component
<!-- built files will be auto injected -->
</body>
</html>
So I can see that the PrimeVue-Autocomplete is being shown, but the styles are not working.
So the question is:
How can I use all of PrimeVue in a custom Component?
Or in other words: How do I setup a Vue 3 CustomElement with PrimeVue?
So I have found a workaround (not a proper solution).
The way to make most of it work is to import the styles and js/ts modules in the component(s) itself.
The main styles make the most sense to import in the root component of the web component.
The reason why it has to be there is, due to:
https://github.com/vuejs/vue-cli/issues/6033 and
https://github.com/vuejs/core/issues/4662
that web components can't use plugins, or at least I don't know how. In other words there is no app.use() method.
I still couldn't properly import primeflex so I had to use the cdn link. I think it is possible to use an internal import, and I will update the answer when I find out how.
To use a specific PrimeVue component, simply import and register it as the documentation describes.
<template>
<Button />
</template>
<script lang="ts">
import Button from "primevue/button";
import { defineComponent } from "vue";
export default defineComponent({
components: { Button },
});
</script>
<style>
#import url("https://unpkg.com/primeflex#3.1.0/primeflex.css");
</style>
<style lang="scss" src="#/assets/scss/globals.scss"></style>
<style src="primevue/resources/primevue.min.css"></style>
<style src="primevue/resources/themes/tailwind-light/theme.css"></style>
//main.ts
import { defineCustomElement } from "vue";
import App from "./App.ce.vue";
customElements.define("custom-element", defineCustomElement(App));
Limitation:
Due to the missing plugin support (or my lack of knowledge of it) the lines:
import PrimeVue from 'primevue/config';
app.use(PrimeVue);
are not possible. Unfortunately, I can't fully grasp the impact that might have.

next.js _document.js didn't get called

I have a small problem with next.js _document.js. I want to support Arabic, so, I add lang="ar" to Html component. But, in the page rendered there is no lang attribute in HTML. Hope somebody help me.
In order for Next.js to show updates made in _document you must stop and restart Next.js.
You must restart Next.js after making changes in _document, *.env, or any Next.js config files.
pages/_document.{ jsx | tsx }
import NextDocument, { Head, Html, Main, NextScript } from 'next/document';
class Document extends NextDocument {
render = () => (
<Html lang="ar" dir="rtl">
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
export default Document;

Resources