How to remove __NEXT_DATA__ from dom in NextJs? - next.js

Because of NEXT_DATA element dom size is getting very high and it is affecting to the performance. Can anyone plz help me to remove NEXT_DATA from dom?
I am using full server-side rendering with dynamic routes in next Js.

TLDR: If you would(/could) remove the __NEXT_DATA__ script tag, React wouldn't be able to hydrate. You either hardcode the data in the page or try to reduce your pageProps payload, returned from getServerSideProps.
I came upon this issue also recently, where I asked myself, why would there be a need for the content to be included in the HTML 2 times.
As the content itself - when your NextJS renders the appropriate HTML and sends it to the client
As JSON in <script> tag - This is because of the need for rehydration on the client side.
"Solutions"
Returning only necessary data from data-fetching method - I can recommend reading up on this article Reducing HTML payload with NextJS, in which they talk about formatting / aggravating the necessary data and returning only the needed fields.
Not using the data-fetching method and hardcoding static content - The idea behind using static data fetching, if not using revalidate option, is that the content shouldn't be changing (maybe ever). So in that case, why couldn't we hardcode the data in the page itself. Althought downside of this of course is, having to write it all out manually / download the required content to some JSON / object and then use it in the page like so.
Reading
Here's a github link with related discussion in next in which you might be interested.
Blog post about reducing the size of __NEXT_DATA__ - by Liran Cohen.

To remove the rehydration data regex: <script id="__NEXT_DATA__((.|n)*)script> from all pages of the static website run the following command after the build has finished:
find out -name '*.html' | xargs perl -0777 -pi -e 's/<script id="__NEXT_DATA__.*?script>//sg;'

If you come across this issue, make sure you don't have any conditional rendering. This is how I solved this issue myself !

You can do this to not show __NEXT_DATA__:
export const config = {
unstable_runtimeJS: false,
};
But all JavaScript functionality will not work in frontend.

Sometimes you might not require some of the __NEXT_DATA__ props during client side rendering.
To drop those props, you can mutate the NextScript.getInlineScriptSource function in the _document.tsx file. Here is an example:
// _document.tsx
const nextInlineScriptSource = NextScript.getInlineScriptSource;
NextScript.getInlineScriptSource = (props) => {
if (props?.__NEXT_DATA__?.foo) {
props.__NEXT_DATA__.foo = 'bar';
}
return nextInlineScriptSource(props);
};

Related

Loading local file inside an iframe in Electron

I've tried different approaches but all are problematic.
So first of all I was using webview, but as per electron documentation, this tag is undergoing major architectural changes and it's recommended to use iframe or other alternatives. Furthermore, the webview tag gives me a warning while used alongside VueJS that the component is not registered. I understand this component doesn't exist within HTML standards and is something specific to electron, so I am not sure how to tell Vue to ignore or recognize it in the use case of an electron app.
Coming to the iframe problem, approach one of loading the file directly via src, gives me the obvious error Not allowed to load local resource:. Turning off webSecurity though allows the file to load but I read it's not recommended to turn it off. I am not sure if there are specific use case where it's safe to turn it off or shouldn't be at all.
I decided to try via file protocol as I already have it in place. The protocol code:
protocol.registerFileProtocol('downloads', (request, callback) => {
const url = request.url.substring('downloads:///'.length)
const location = path.normalize(paths.downloads(url))
callback({ path: location })
})
Though when I load the file this way, the renderer process crash without errors. Is there something in addition to the above which would help loading local files via iframe?
Edit 1
My use case is the following: I have a typical entry point to an index.html which contains code for a VueJS app.
if (app.isPackaged) {
window.loadFile(join(__dirname, '../renderer/index.html'))
} else {
// 🚧 Use ['ENV_NAME'] avoid vite:define plugin
const url = `http://${process.env['VITE_DEV_SERVER_HOST']}:${process.env['VITE_DEV_SERVER_PORT']}`
window.loadURL(url)
window.webContents.openDevTools()
}
Inside that VueJS app, I require to list html files from a directory. I am able to achieve so via webview but I have tried to move away from it for the reason mentioned above. I tried using iframe but encountered issues as well. If there's a setting that doesn't turn off all security and allows me to load the file via iframe, that would be ideal.
This is kind of the reverse of this question where they're using an iframe, running into the "not allowed to load local resource" and being told to use a <webview> instead.
The <webview> docs list BrowserView as another alternative which is what I would recommend here. That should be much easier to work with than an iframe.
const { app, BrowserView, BrowserWindow } = require('electron')
app.whenReady().then(() => {
const win = new BrowserWindow()
const view = new BrowserView()
win.setBrowserView(view)
view.setBounds({ x: 0, y: 0, width: 300, height: 300 })
view.webContents.loadFile('<yourFile>')
})
Even though it is not recommended to use webview tag, I decided to go forward as it's the only thing that works for me. The only issue then was this error where Vue does not recognize the tag. To work around that error/warning, I had to update my vite.js config:
plugins: [
vue({
template: {
compilerOptions: {
isCustomElement: (tag) => tag === 'webview'
}
}
}),
// ...

Next JS Version 12+: Static Site Generation

I'm using Next.js version 12.0.4 on a new project, having used Next.js version 10 on a prior one.
Has something changed with Static Site Rendering at build time? It's rendering all my output pages when I do an npm run build (which in turn executes "next build and next export") with html files that include a ton of .js files and no native text "content" which I'd expect.
That is, the output doesn't have any of the standard HTML <h1>, <h2> etc. in it, just a bunch of javascript for the client to hydrate.
Prior versions of Next.js (or perhaps it was my configuration?) seemed to render pure, finalized HTML just fine.
I'm trying to render a simple About page (no dynamic routes, no dynamic props for this route) and, while it properly renders a page in the "/about/index.html" output location, that page has a bunch of .js files and a JSON payload. That page does indeed display properly, but I'd really like the output in the "out" directory to be actual .html files with HTML pre-rendered, for SEO and other reasons.
In my next.config.js, I've specified:
module.exports = {
exportPathMap: function () {
return {
"/": { page: "/" },
"/about": { page: "/about" },
};
},
};
I've also specified getStaticProps on the about page conponent (about.tsx). (I'm using typescript if that matters.)
The rendered /about/index.html file has a ton of .js includes and no real HTML "content".
Have I missed a configuration setting? What can I do to make it render pure HTML where I'd like?
AHA! Ok, so this error was of course a coding error on my side.
In _app.tsx, I had a wrapper for Authentication that I had written. By (bad) design, it was deliberately NOT rendering children for it if the user wasn't authenticated. Therefore, the pre-renderer wouldn't render the "regular" html elements, because the pre-renderer of course does not sign in.
If this same problem happens to you, make sure you're not wrapping all views up in some provider element which conditionally renders children.

jquery mobile 1.4.5 single-page template href querystring ajax

I am a newbie to JQM (I use 1.4.5) and my webapp (asp.net C# apache Cordova) contains many separate pages of .cshtml (single-page template) only. I am testing my webapp on a Samsung Galaxy Grand using Android 4.2.2
A.
I am not sure about my understanding of 'linking pages', even after reading all the JQM docs on this and also after reading up many, many posts on this topic about passing querystring values to another page; mainly because I find that ALMOST ALL the examples are directed towards providing answers for internal pages (Multi-Page template) within a single html page.
So I request some of you JQM experts to confirm or correct the following understanding of mine....
From the JQM docs I understood that
I could use in any link (e.g button), href="page2.cshtml?par1=1&par2=2"; and JQM will automatically use Ajax for this link to work.
I also understood that use of querystring is always allowed in such cases of different html pages of the same domain and it will work via Ajax automatically ; so long as the attr such as rel="external", data-ajax="false" etc. are not used in the same link.
but querystrings are not allowed in case of the internal pages (multi-page template) only....;
and if I need to use the above href to link to a page in another domain e.g. www.anotherdomain.com/page2.cshtml?par1=1&par2=2, then I need to use rel="external".
Are all my above points (that reflect my understanding) CORRECT? KIndly confirm ro please correct me ...
B.
In my app, I find that most of the links work according to my understanding as above, to connect to different pages in the same domain; and I assume it happens via Ajax. Is it correct? I am also able to use the querystring params in page2 ( i.e. To-Page).
But in one case, though it works, in the To-Page the Panel features do not operate correctly, unless I introduce rel="external' in the href link !!! I suppose it means it IS NOT AJAX anymore? Also I am unable to find the reason..
Further independent of the above topic, I face another issue. The loading time (i.e. Time taken to display the To-Page) varies.
Mostly it is OK, but at times the loading-circle goes on forever.... and I presume it has crashed....??? then If I go back using the back button and come forward again, many times it loads immediately...!!!!!
Any thoughts or suggestions.....?
Thanks in anticipation...
Ratna
Before you can worry about how to pass attributes from one page to another you need to understand the difference between multi-page and multi-HTML templates.
Multi HTML page template
Smaller and lighter, each data-role=”page” is inside a separate HTML file and page structure is much more modular.
Can become even smaller if every subsequent HTML page is stripped from HEAD content, or anything that isn’t data-role=”page” div. Unfortunately in this case fallback if JavaScript is not supported is out of question.
DOM size is relatively small, only first page is permanently loaded into the DOM, any other page will also be loaded into the DOM but at the same time it will also be removed when not used actively, basically each time you move from it.
Better fallback if JavaScript is not supported. Works great in desktop browsers after a page refresh, mainly because every HTML page has an existing HEAD content. This also allows your app to behave like normal web app mainly because AJAX can be turned off.
Multipage template
Since all pages are already loaded, no additional requests are generated for navigating between pages.
First load is slower as the file size is larger, but subsequent page navigation is fast, thus making transitions much more smooth. Almost native-like smooth, emphasize on almost.
Suitable for relatively smaller applications and situations where you know the capabilities of your target platforms including presence of JavaScript support, thus making it a great solution for a hybrid app. It works much better as a Phonegap app then multi HTML template.
The “page” data-role element is required.
More about this topic can be found here: Multipage template vs Multi HTML template in jQuery Mobile
Now let's talk about how to properly pass data between jQuery Mobile pages.
jQuery Mobile uses AJAX by default
You can turn off AJAX using rel="external"
If you turn off AJAX you will lose almost everything good about jQuery Mobile, including animations. So if you don't want AJAX page handling better find some other responsive framework like Bootstrap or Foundation.
If you don't want to use AJAX you can still use querystrings but inside a href or via changePage function.
Better querystrings alternatives:
Global object.
If you're using AJAX you can simply use a global object(s) to store all of your data.
Something like this:
// Store object
var storeObject = {
parameter1: null,
parameter2 : null
}
Access data from the previous page
Again if you're using AJAX you don't need to pass any data because all that data is till in the DOM.
// Store object
$(document).on('pagebeforeshow', '#second', function(e, data){
alert("My name is " + data.prevPage.find('#test-input').val());
});
Localstorage or Sessionstorage
This solution will work no matter if you use AJAX or not.
$(document).on('pagebeforeshow', '#index', function(){
$(document).on('click', '#change-page-button', function(){
// store some data
if(typeof(Storage)!=="undefined") {
localStorage.firstname="Dragan";
localStorage.lastname="Gaic";
}
// Change page
$.mobile.changePage("#second");
});
});
$(document).on('pagebeforeshow', '#second', function(){
alert('My name is ' + localStorage.firstname + ' ' + localStorage.lastname);
// Lets change localStorage data before we go to the next page
localStorage.firstname="NewFirstNeme";
localStorage.lastname="NewLastName";
});
$(document).on('pagebeforeshow', '#third', function(){
alert('My name is ' + localStorage.firstname + ' ' + localStorage.lastname);
});
Send data through changePage function or via href
// Send
$.mobile.changePage('page2.html', { dataUrl : "page2.html?paremeter=123", data : { 'paremeter' : '123' }, reloadPage : true, changeHash : true});
or
Send parameter
receive that same data:
$(document).on('pagebeforeshow', "#index", function (event, data) {
var parameters = $(this).data("url").split("?")[1];;
parameter = parameters.replace("parameter=","");
alert(parameter);
});
If you need more information about this solutions including working examples find them here: Passing data between jQuery Mobile pages
Several methods mentioned here are deprecated (still usable) in the version 1.4. Though you don't need to worry about that, almost everything here will be unusable in version 1.5. This new version will overhaul jQuery Mobile from the bottom to the top.
Update
Yes, you can use any such link and jQuery Mobile will use AJAX. If you take a look at my previous examples you will find a working one.
If you want AJAX you CAN'T use rel="external", data-ajax="false" though stringquerys will work in bot cases.
Correct they will only work in multi-HTML template. Though there used to be a 3rd party plugin that allowed this to work with multi-page template but I don't think it works with newer jQuery Mobile versions.
Correct, if you want to link external page you need to use rel="external".

Efficiently reusing (poorly designed) JSON template for additional sites?

My supervisor just handed me a pile of JSON files from a freelancer which we are going to use to make multiple (similar) websites. Lucky me, I'll get to be the one updating the content and css for the different versions.
This is my first time working with JSON, so while I can't be sure that this is a poorly designed template, the fact that the css is very messy (in order to change the color of buttons throughout the site from yellow to orange, at least 15 different classes need to be adjusted, which seems to me to defeat the whole purpose of css...) doesn't give me hope.
I've brute-forced my way through the first two different sites, but since it looks like we'll be doing a lot more of them, I'm looking for ways to streamline the process (in particular making sure to change the content in all the places the content needs changing, which is a lot of files, with different content for different versions).
I'm personally old-school enough to like awk (well, that, and it's what I'm most used to programming in), so my backup plan is to just set up an awk/batch script or two which will take in a "these are the bits of info that go in these specific places" file and update all the relevant files. However, I'm sure there's a better way to do this, which is why I'm turning to y'all.
Is there anything that already exists for streamlining processes like these? Or a coding system/language that's well-suited to this project? A GUI which I can connect to bits of text that need changing?
Ideally, I'd like to set up something that even a monkey (or a non-caffeinated me) could use as often as needed. I'm already going to have to dive into the source code to clean it up (because, gasp, we might need to be able to have more than 5 people on the "our team" page, for example - without bad css/html workarounds), so making other tweaks that'll help with the content update process can happen en route.
I have recently used underscore to render templates from JSON. this is a front end tool, but you could automate it with some backend tools (a simple cURL or file_get_content in php will do).
Here is a link to a tutorial
your template will be a JavaScript template in your html file:
<div id="rendered"></div>
<script type="text/template" class="template">
<%- rc.listTitle %>
</script>
and in your JavaScript code you load:
<script type="text/javascript">
// When rending an underscore template, we want top-level
// variables to be referenced as part of an object. For
// technical reasons (scope-chain search), this speeds up
// rendering; however, more importantly, this also allows our
// templates to look / feel more like our server-side
// templates that use the rc (Request Context / Colletion) in
// order to render their markup.
_.templateSettings.variable = "rc";
// Grab the HTML out of our template tag and pre-compile it.
var template = _.template(
$( "script.template" ).html()
);
// Define our render data (to be put into the "rc" variable).
var templateData = {
listTitle: "Olympic Volleyball Players",
};
// Render the underscore template and inject it after the div rendered
// in our current DOM.
$( "#rendered" ).after(
template( templateData )
);
</script>

Upgrading to new asynchrous Google Analytics code - should you do it?

I had read somewhere and have now forgotten that upgrading to the new asynchronous code will not enable one to track actual clicks for downloading items when user stays on the same page and that for tracking that you need to use the old version of GA code.
My question is, is that still the case and does anyone have any other reasons for not upgrading to use the newer asynchronous tracking?
thanks
Hmm...are you sure the "old" version of GA automatically tracked downloads? AFAIK GA never automatically tracked download links, that you always had to attach GA code (like a _trackEvent call) to your links yourself. But in any case, it's pretty easy to do it yourself, so it's really not a big deal. Plus, you get lots of benefits upgrading, and one day it may not even be an option to stick with the old version...
If you have jQuery you can for example do this:
// file types you want to consider a download
var downloadFileTypes = ['pdf','doc','docx','mp4'];
$(document).ready(function() {
$('a').filter(function() {
var ext = $(this).attr('href').split('.').pop().toLowerCase();
return ( $.inArray(ext, downloadFileTypes )>-1 );
})
.click(function() {
_gaq.push(['_trackEvent', 'Downloads', $(this).attr('href')]);
});
});
If you do not have a framework like jQuery, you can still do this easy enough with .getElementsByTagName() and using regular loops and conditions instead of the jQuery conveniences like .filter and .inArray
edit: Some things to note about that example:
the jQuery code was an example to hook the GA code to standard links pointing to the file types you specify in downloadFiletypes. It will only apply to links that exist at the time the code is executed. If you have links that may be dynamically generated on the page later, consider looking into .on() instead of .click()
you will need to make tweaks to matching links you want to consider downloads if they do not point to regular files with extensions. For instance, some websites have a controller script that expects a parameter with an ID and it dynamically serves up a pdf or whatever..if your files are like this, you will have to alter the logic to look for that instead.

Resources