NextJS looses global vars from script on deep link / page refresh - next.js

In Pages/_document.tsx I have a script that loads some global public configuration like below.
The script just sets some global variable on the window object.
If I visit the home route of the app, the page loads everything is fine, but if I refresh the page on a nested route, (or deep link) it throws an error saying ReferenceError: window is not defined.
I'm guessing this is the server complaining, but I only need this config on the client, and I don't want to package the config vars up during build time, as I want to promote the built app down a pipeline and just update a few variables. Is this the right approach?
import Script from 'next/script'
...
...
render() {
return (
<Html lang='en'>
<Head>
<meta charSet='UTF-8' />
<meta httpEquiv='X-UA-Compatible' content='IE=edge' />
</Head>
<body>
<Main />
<NextScript />
<Script src='/scripts/public-config.js' strategy='beforeInteractive' />
</body>
</Html>
)
}

Maybe there's a better way, but I ended up checking if window exists anywhere I use it, so in my public-config.js file I did this:
if (typeof window !== 'undefined') {
window.MY_PUBLIC_CONFIG = {
MY_VAR: 'HELLO WORLD'
}
}
and anywhere referencing it needs to do the same:
export const config = (typeof window !== 'undefined')
? window.MY_PUBLIC_CONFIG
: {}

Related

Cannot load static css

started coding a couple of months ago and run into a problem I didn't find anything online. I have the following http requests
app.get("/courses", async (req, res) => {
const courses = await Course.find({});
res.render("courses/index", { courses, topic: "Μαθήματα" });
});
app.get("/about", (req, res) => {
res.render("courses/about", { topic: "Πληροφορίες" });
});
app.get("/courses/:id", async (req, res) => {
const { id } = req.params;
const course = await Course.findById(id);
return res.render("courses/show", { course, topic: course.title });
});
All of the rendered templates are in the same folder but when I try to render something from /courses/:id it can't find the appropriate css and js files. The problem appears only when I use /courses/something else. If I try the same thing with just /:id it loads fine, else I get these errors.
The paths I have in my include files are:
<link rel="stylesheet" href="static/stylesheets/footer.css" />
<link rel="stylesheet" href="static/stylesheets/navbar.css" />
<link rel="stylesheet" href="static/stylesheets/coursesIndex.css" />
I tried a ton of different possible paths by didn't have any luck. Thank you for your time
Try prefixing a / before the static paths, as follows:
<link rel="stylesheet" href="/static/stylesheets/footer.css" />
<link rel="stylesheet" href="/static/stylesheets/navbar.css" />
<link rel="stylesheet" href="/static/stylesheets/coursesIndex.css" />
It might work, because, the other 2 routes are root level routes. So, when rendered, browser would look for static/stylesheets/... in the root directory. So, it worked.
But, when you rendered the same on /courses/:id path, the browser would look for static/stylesheets/... inside /courses/:id(actual would be like /courses/1, for example). That directory(1 in the example) does not exists in your root directory.
So, if you use absolute paths(these are the paths that starts with /), browser would look for them from the root of your website always. So, this would work.

Google sign-in sends multiple requests on redirect

I'm trying to implement Google sign-in on my web application, as an add-on to normal server-side authentication. The problem is,I'm not able to redirect the page to a Servlet to go to the user homepage. Instead, whenever I try to redirect ONCE,I get continuous requests to the next Servlet(I used print statements on the Servlet to check this).It seems as if the page reloads after every request sent to the Servlet. I also tried using form data to fix this, but that doesn't work either.
How do I stop this from happening? I'm a newbie, so any dumbing down will be much appreciated. In case this is a duplicate, please do send the link. I have tried to find a similar question, but have had no luck so far.
Note: I have removed all irrelevant lines of code.
<!DOCTYPE html>
<html>
<head>
<meta http-equiv='Content-Type' content='text/html; charset=UTF-8'>
<script src="https://apis.google.com/js/platform.js" async defer></script>
<meta name="google-signin-scope" content="profile email">
<meta name="google-signin-client_id"
content="CLIENT_ID_HERE">
<script>
function onSignIn(googleUser) {
var profile = googleUser.getBasicProfile();
//document.cookie = "emailId=" + profile.getEmail();
redirectPost(profile.getEmail());
//window.location = "http://localhost:8080/auth/gmailhome";
}
function redirectPost(data) {
var inputElement = document.getElementById('emailId');
var form = document.getElementById("gmailLoginForm");
inputElement.value = data;
form.submit();
}
</script>
</head>
<body>
<form method="post" action="gmaillogin" id="gmailLoginForm">
<input type="hidden" id="emailId" name="emailId">
</form>
<div class="g-signin2" data-onsuccess="onSignIn"></div>
</body>
</html>
I figured out how to solve this issue, and it just occurred to me that I can leave this here in case someone needs it in the future.
The problem we have is that onSignin() gets called as long as the user is signed in, and the status of the user doesn't reflect that they are signed in. I'm not sure why the state isn't changed automatically-perhaps there is some other purpose to this, or this is just low-priority right now.
So, what we do is add a listener that monitors whether or not the user is signed-in.
Something like this
function onLoad() {
gapi.load('auth2', function () {
gapi.auth2.init();
gapi.auth2.isSignedIn.listen(function (isSignedIn) {
this.setState({ status: isSignedIn })
})
})
}

Error when loading an external URL in an iframe with Electron

I am trying to create a desktop application using Electron but I am unable to load an external URL like google.com in an iframe.
The code below, inside index.html, triggers an error.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
</head>
<body>
<h1>Hello World!</h1>
<!-- All of the Node.js APIs are available in this renderer process. -->
<iframe src="http://www.w3schools.com"></iframe>
<script>
// You can also require other files to run in this process
require('./renderer.js')
</script>
</body>
</html>
The error :
index.html:1 Refused to display 'https://www.w3schools.com/' in a frame because it set 'X-Frame-Options' to 'sameorigin'.
www.w3schools.com/ Failed to load resource: net::ERR_BLOCKED_BY_RESPONSE
What is causing this issue and how can I resolve it?
Adding to what has already been answered by Sjoerd Dal.
Adding External URL using IFRAME : Sites block adding their web pages to any other web page, for avoiding click-jacking. This is usually done by :
a. Adding a response in the header. This stops pages which are not whitelisted/not from same-origin to be included in iframes
b. Checking if top window is same as current window.
Now to answer your question, there is actually a very easy way to do that:
const urls = [
"https://www.google.com"
]
const createWindow = () =>{
win = new BrowserWindow({
center: true,
resizable: true,
webPreferences:{
nodeIntegration: false,
show: false
}
});
win.maximize();
win.webContents.openDevTools();
//win.webContents.
console.log(urls[0]);
win.loadURL(urls[0]);
// win.loadURL(url.format({
// pathname: path.join(__dirname,"index.html"),
// protocol: 'file',
// slashes: true
// }));
win.once('ready-to-show',()=>{
win.show()
});
win.on('closed',()=>{
win = null;
});
}
app.on('ready', createWindow);
Most sites these days block other people from iframing them. As you can see with this error, the site only allows iframes coming from the same domain. As an alternative you can use Electron's webview tag which starts the website on a separate thread, sandboxed in its own BrowserWindow. https://electronjs.org/docs/api/webview-tag

asp.net core <environment> equivalent in angular2?

In asp.net core, I can conditionally include css/js in my layout html page using <environment> tags:
<environment names="Development,Staging">
<script type="text/javascript" href="js/debug.js"></script>
<link rel="stylesheet" type="text/css" href="css/style.css" />
</environment>
<environment names="Production">
<link rel="stylesheet" type="text/css" href="css/style.min.css" />
</environment>
How can I achieve this in angular 2? The css/js files that I'm talking about are site-wide, not component-specific
(PS. I'm new to angular 2)
If you are using angular2 CLI then you could use enironment.ts.
Properties specified in this file will be available throughout entire application.
You can create multiple environments like this-
In components import default environment file like this-
import { environment } from '../../environments/environment';
Import DOCUMENT from platform-browser like this-
import { DOCUMENT } from '#angular/platform-browser';
Inject into component (e.g. main AppComponent),
constructor (#Inject(DOCUMENT) private document) { }
Use environment condition and apply dynamic style-sheet like this-
if(environment.EnvName === 'prod') {
this.document.getElementById('theme').setAttribute('href', 'prod.css');
}
else {
this.document.getElementById('theme').setAttribute('href', 'dev.css');
}
Angular CLI takes care of which file to use for each environment during build process.
This is how you can specify environment at a time build-
ng build --env=prod
Hope this helps in your use case.

how to apply css and js dynamically

i have One xml file which contain some css and script links i want to apply this dynamically on page load i want to do this on page load please help?
xml File---
<template>
<theme id="1" name="default">
<css>
<name>css/style.css</name>
<name>css/normalize.css</name>
<name>css/grid.css</name>
<name>css/prettyPhoto.css</name>
</css>
<js>
<name>js/jquery.easing.1.3.js</name>
<name>js/jquery.prettyPhoto.js</name>
<name>js/js.js</name>
<name>js/jquery.stellar.min.js</name>
<name>js/waypoints.min.js</name>
</js>
</theme>
</template>
i have done this using jquery but the problem is when i adding debugger between
script and execute code step by step using firebug css and js applying and
without debugger loading in head but not applying can anyOne suggest
Xml File---
jquery Code implemented in aspx file
<script src="templates/1/jquery.xml2json.js"></script>
<script type="text/javascript">
//debugger
$.get('templates/1/SettingBasic2.xml', function (xml) {
var newTemplate = $.xml2json(xml);
$(newTemplate).each(function (key, data) {
$(window).load(function () {
switch (data.theme['name']) {
default:
$(data.theme['css']['name']).each(function (key_css, css) {
$('head').append('<link rel="stylesheet" href="' + css + '" type="text/css" media="all" />');
});
val = '';
$(data.theme['js']['name']).each(function (key_js, js) {
val += '<script type="text/javascript" src="' + js + '"></\script>';
});
$('head').append(val);
break;
}
});
});
</script>
i would like to say that you should use JS instead use, loadCSS.js for loading dynamic css, with control where to put what and also you can listen for when it gets loaded.
For scripts use $script.js which is smallest lib you can find or use require js which is the best for these stuff, but overkill for just loading scripts.

Resources