external .js not working after using "parcel index.html" - javascript

So I have this site that im trying to make and I just keep running into the same error over and over again. When I double click on my index.html all the code below works fine but if I use "parcel index.html" in the console it says "Uncaught ReferenceError: test is not defined".
The HTML is:
<!DOCTYPE html>
<html lang="en">
<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">
<title>Learn Ambivalendrish</title>
<link rel="stylesheet" href="/style/index.scss">
<script src="js/script.js"></script>
</head>
<body>
<h1 onclick="test()">This is a header for testing purpose</h1>
</body>
</html>
and my js is:
function test(){
alert('test alert')
}
I already tried doing
export function test(){
alert('test alert')
}
and
let test = () =>{
alert('test alert')
}

Module bundlers expect a script to be an entry point to the program.
Your problem is that you want the script to create a global variable and then read that global externally.
The bundler doesn't expect that so when it rewrites your script it doesn't take care to ensure that it creates a global variable with that name.
Rewrite your code so the script is the entry point.
Don't use intrinsic event attributes, bind the event handlers with addEventListener.
addEventListener('DOMContentLoaded' () => {
const heading = document.querySelector('h1');
heading.addEventListener(test);
});
Aside: Headings aren't designed to be interactive controls. By default: They don't react to the mouse passing over them. They don't look like things you can click on. Screen readers don't announce them as being interactive. You can't tab to them. If you want something to click on to trigger JS with, use a <button>.

Related

The popstate event is not firing even after pushing state using pushState() when the user clicks a button

I have been willing to try implement Client Side Routing, hence this question,
as I was testing the popstate event and the pushState function of the history
object.
Now, here is my html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite App</title>
</head>
<body>
<button id="navigate">
Navigatin Test Button
</button>
<script type="module" src="/main.js"></script>
</body>
</html>
There I added a button which when clicked will push some state to the History.
I know that a browser will not allow non-interactive pushStates initially,
hence I added the button to test it from the perspective of the User.
Here is the javascript:
let NavigationButton = document.getElementById("navigate")
//this part is not working for some reasons.
window.addEventListener("popstate", event => {
console.log(event.url) //must show something when clicked
})
NavigationButton.addEventListener("click", () => {
console.log("Clicked!") //this is working as expected
window.history.pushState({ url: "/url"}, "", "/url")
})
I created this project using Vite, and I have used the vanillaJS template
with default settings and no modifications whatsoever.
I have searched through the internet but this exact problem does not exists anywhere.
If you want to recreate the problem, simply create a vite project using
VanillaJS and nothing, and replace the index.html with the html I have gotten
and replace the main.js with the javascript mentioned above

How to remove a script tag reliably before it is loaded?

I've created a mutation observer to remove (block) scripts under certain conditions.
There are several SO solutions which suggest it can work. Eg: https://stackoverflow.com/a/65453574/4688612
But it doesn't work in my case for <script src="https://www.googletagmanager.com/gtag/js?id=UA-12345678-9"></script>
For some reason the network call to googletagmanager.com still happens on every page load.
Google Chrome and Firefox both load the script.
Now I'm not sure if using the mutation observer method is simply not reliable or buggy, or if it is a bug in my code.
Is there a reliable solution for this?
Here's my code.
<!DOCTYPE html>
<html lang="en">
<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">
<title>Document</title>
<link rel="shortcut icon" href="#">
<script src="https://code.jquery.com/jquery-3.6.0.min.js"
integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous">
</script>
<script>
const observer = new MutationObserver( (mutations) =>{
mutations.forEach(({addedNodes}) => {
[...addedNodes]
.forEach(node => {
$(node).remove()
});
});
})
observer.observe(document.head, { childList: true });
</script>
<script src="https://www.googletagmanager.com/gtag/js?id=UA-12345678-9"></script>
</head>
<body></body>
</html>
```
The script should be added instead
As discussed in the comments, it is unreliable to remove the script with an observer.
The browser can prefetch the file as soon as the src URL is known, independently of the HTML tag being rendered
The browser does not have to be honest or perfect. It may prefetch the file without listing it (yet) in the developer tools.
Not all versions of all browsers implement mutation observers: see caniuse MutationObserver. This may attract people using older browsers on purpose and complaining. So not a reliable way for legal requirements.
Instead the script should be added when needed:
(function(p,a,n,t,s){
t=p.createElement(a),s=p.getElementsByTagName(a)[0];
t.async=1;t.src=n;s.parentNode.insertBefore(t,s)
})(document,'script','https://www.googletagmanager.com/gtag/js?id=UA-12345678-9');
Testing your observer locally
The following will illustrate what may be the issue here.
I have created an index.html just as yours but with a locally loaded script test.js. I also added console.log(node); in your observer.
index.html
<!DOCTYPE html>
<html lang="en">
<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">
<title>MutationObserver test</title>
<link rel="shortcut icon" href="#">
<script src="https://code.jquery.com/jquery-3.6.0.min.js"
integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
<script>
const observer = new MutationObserver( (mutations) =>{
mutations.forEach(({addedNodes}) => {
[...addedNodes]
.forEach(node => {
console.log(node);
$(node).remove()
});
});
});
observer.observe(document.head, { childList: true });
</script>
<script src="test.js"></script>
</head>
<body></body>
</html>
test.js
console.log("I got loaded before you could remove me.");
This results in the following console log:
index.html:21 " "
index.html:21 <script src=​"test.js">​</script>​
index.html:21 " "
So the observer is working, as it also catches empty nodes with just whitespace characters.
However in the Network tab the test.js is still listed as loaded:
Name Status Type Initiator Size Time
index.html Finished document Other 972 B 1 ms
test.js Finished script index.html 56 B 3 ms
jquery-3... 200 script index.html 31.0 kB 10 ms
index.html Finished text/html Other 972 B 1 ms
It seems as though the HTML node was removed, the browser is prefetching the code. This likely happens because the HTML document itself will transfer regardless. Then the browser parses the HTML and sees all files to be requested. As soon as the HTML document is turned into a DOM the browser runs the observer, removes the node and just in time will not execute the JavaScript from the nodes after the observer.
See this counterexample where I comment out the observing part:
// observer.observe(document.head, { childList: true });
In this case the console output will read:
test.js:1 I got loaded before you could remove me.
The network panel will look nothing different. So it seems as I'm using Chrome, it tries to perfect speed and will load and cache the JavaScript but it will not execute it since its node got removed.
Possible TagManager / Google Anyltics insights
If you have access to alter the TagManager's tags you might just add <script>console.log("TagManager code executed");</script> and confirm this way code execution is correctly suppressed for the removed tag. So confirming the same as my example with a local JS file but in TagManager directly.
Another way is Google TagManager's excellent Debug mode.
If Google Analytics is used here as well you might see your requests (or lack thereof) in the GA Real-Time view (well... bad documentation with no screenshots. Just look for real-time in Analytics you will find it).
Try with following solution
Add defer or async to google tag manager script tag. this make google tag manager script after page load.
<script src="https://www.googletagmanager.com/gtag/js?id=UA-12345678-9"></script>
Changed to
<script defer src="https://www.googletagmanager.com/gtag/js?id=UA-12345678-9"></script>
or
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-12345678-9"></script>
Also call your removing script for the google tag manager code, this will make sure you script will load before google tag manager script load.
Learn more about deferand async Click Here
Following code is working fine for me
<!DOCTYPE html>
<html lang="en">
<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">
<title>Document</title>
<link rel="shortcut icon" href="#">
<script src="https://code.jquery.com/jquery-3.6.0.min.js"
integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous">
</script>
<script>
const observer = new MutationObserver( (mutations) =>{
mutations.forEach(({addedNodes}) => {
[...addedNodes]
.forEach(node => {
$(node).remove()
});
});
})
observer.observe(document.head, { childList: true });
</script>
<script defer src="https://www.googletagmanager.com/gtag/js?id=UA-12345678-9"></script>
</head>
<body></body>
</html>

external js file loaded but the code don't working

when I write js code internally in the html file It's work well.
hre is the html code
<!DOCTYPE html>
<html lang="en">
<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 href="./cs.css" rel="stylesheet">
<title>Document</title>
</head>
<body>
<div id="root" onload="App">
</div>
<script src="js/App.js" type="module" />
</body>
</html>
and here is App.js file
import Insert from './Insert.js';
function App(){
document.getElementById("root").insertAdjacentHTML("afterbegin",'<h1>hello Javascript</h1>');
};
onload is not an attribute supported by div elements, generally if you use it you would apply it to the body element, but it should be avoided in favour of addEventListener
The value of the onload attribute is the body of a JS function. Just mentioning the name of another function doesn't do anything. If you want to call a function you would usually follow the name with ().
type="module" loads a JS module, which (among other things) means the outer scope is the module and not the global scope so you can't access App anyway. Again, use addEventListener.
The </script> end tag for the script element is mandatory and you omitted it. (Since it was that last thing in the document it probably won't break anything, but you are opening yourself up for future problems).

Javascript button runs the click event itself once when the page is loaded and doesnt work when clicked

The answer to this might be quite easy but I couldn't find a solution since everything seems ok. I'm trying to create a google chrome extension and it has a button like this,
document.getElementById("autof").addEventListener("click", autofill());
function autofill() {
console.log("ENTER");
document.getElementsByName("session[username_or_email]").value = "sylent";
document.getElementsByName("session[password]").value = "abcdefg";
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>TWITTER</h1>
<button id="autof">Fill</button>
<script src="twt.js"></script>
</body>
</html>
When you add the event listener to the button, you should pass in the function without actually calling it.
document.getElementById("autof").addEventListener("click", autofill);
Using parenthesis with autofill(), you are assigning the result of calling your function to the click handler:
document.getElementById("autof").addEventListener("click", autofill());
Try this:
document.getElementById("autof").addEventListener("click", autofill);

How can I link multiple p5 JS projects to the same index.html?

I have a p5 JavaScript project folder containing many JavaScript documents/projects. In order to view my code in a browser obviously I just run the linked HTML document.
My problem is that if I were to link multiple p5 JavaScript projects in my index.html I only get the last linked JavaScript project.
I could simply make a separate HTML document for each project however that would double the number of documents in my project folder and potentially create a lot of unnecessary work for myself.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>JS learnings</title>
</head>
<body>
<script language="javascript" type="text/javascript" src="node_modules/p5/lib/p5.js"></script>
<script language="javascript" type="text/javascript" src="node_modules/p5/lib/addons/p5.dom.js"></script>
<script language="javascript" type="text/javascript" src="node_modules/p5/lib/addons/p5.sound.js"></script>
<script src="./classes.js"></script>;
<script src="./function-picture.js"></script>;
<script src="./ifs-within-ifs.js"></script>;
<script src="./while-and-for-loops.js"></script>;
<script src="./Boolean.js"></script>;
<script src="./object-var.js"></script>;
<script src="./move.js"></script>;
</body>
</html>
This code simply displays ./move.js in browser.
If you want to support multiple sketches in one window, you're going to need to use instance mode.
By default, P5.js uses the global namespace for its variables and functions. So every time you define a setup() or draw() function, you're overwriting any previous values. That's why you only see the last sketch you load.
To get around this, you can use instance mode to encapsulate each sketch in a non-global scope. You can read more about instance mode here, but here's an example:
var s = function( sketch ) {
var x = 100;
var y = 100;
sketch.setup = function() {
sketch.createCanvas(200, 200);
};
sketch.draw = function() {
sketch.background(0);
sketch.fill(255);
sketch.rect(x,y,50,50);
};
};
var myp5 = new p5(s);
You would want to create a new p5 instance for each sketch.

Categories