How to load a script synchronously with RequireJS - javascript

I am using RequireJS in ASP.NET. There is a user control that includes a script file, and registers a startup script in order to initialize itself. Here's the generated code:
<script src="script/UserControls/myctrl.js" type="text/javascript"></script>
...
<script type="text/javascript">
function myCtrl1_init() {
// initialize control
// *JS ERROR* because myctrl.js hasn't run yet
Sys.Application.remove_load(myCtrl1_init);
}
Sys.Application.add_load(myCtrl1_init);
</script>
The myctrl.js file looks something like this:
require(['script/dep1', 'script/dep2'], function(dep1, dep2) {
MyCtrl = function () {
};
MyCtrl.init = function(id) {
dep1.doSomething();
}
};
So, the problem is that startup script runs before the myctrl.js file has had a chance to run. Currently, the require call uses a callback function, which obviously doesn't run until later, and this is the problem... the script returns and the browser continues to the startup script before MyCtrl has been created.
I have tried simply calling require(['script/dep1', 'script/dep2']); at the top of the file, but that doesn't block either, and the script fails because the dependencies haven't loaded yet. The dependencies are modules, by the way, e.g. they use define().
Is there a way to load a script file synchronously with RequireJS? The API documentation says that "Using RequireJS in a server-side JavaScript environment that has synchronous loading should be as easy as redefining require.load()", but I have no idea what this means.
Any suggestions?

I assume the script tag for require.js is above the contents you mention. If so, then I would convert myctrl.js to be a module (use "define('myctrl', ....)" instead of "require(.." inside it), then in the inline script tag content do something like:
<script type="text/javascript">
require(["myctrl"], function () {
function myCtrl1_init() {
// initialize control
// *JS ERROR* because myctrl.js hasn't run yet
Sys.Application.remove_load(myCtrl1_init);
}
Sys.Application.add_load(myCtrl1_init);
});
</script>
I am not familiar with ASP.NET, so I am not sure if it is OK to do those Sys.Application calls in a callback that may fire after DOMContentLoaded, but the above is the general idea.
There is no way to synchronously load a script in the browser with RequireJS, a callback method like above needs to be used. The require.load() information was for developers that want to make RequireJS adapters that run in sync environments (basically non-browser JS environments).

Related

Force load JS script on page

I have a third party JS script with class Oreole defined there. This script is located on a CDN server elsewhere. I have this reference in my HTML:
<script src="https://someothercdn.com/oreole.js"/>
Later in my page script code I have
let oreole = new Oreole
Sometimes the CDN fails with 504 or 502 and my code crashes. Usually, page reload helps. But how do I force script reload on my page?
if (typeof(Oreole) == "undefined") {
//Do what exactly?
}
You should probably host oreole.js somewhere else, but if you want to go with unreliable cdn, you can do something like this using jquery
$.getScript("https://someothercdn.com/oreole.js", function() {
// do everything that needs oreole.js here
});
The page will keep running atleast, if oreole.js is not found or something happens only oreole part will crash

How to load javascript that does not block rendering?? How to load after full page has been painted?

I am loading the chat service called drift. I am getting very bad score on PageSpeed mobile because of this only. I want to load it so it does not block rendering and like should start after whole page is painted.
If you want to consider the website here it is:
https://stockarea-application-test.herokuapp.com
I have tried to use async and defer to load the javascript file but both of them are blocking the render. ( I checked that thing over pagespeed insights recommendation).
I also have used jquery $.getScript() after document ready function but still its showing render blocking
Please I really need some help on how I could solve it. Some things on internet says about worker files but they don't have DOM apis on them so can't use them as this drift service do paint somethings on DOM. so please help
I think what you tried is only let the script load asynchronously, but because processing the script must be in the only main thread, the only way not to block your business code is putting the third-party script in a frame if it can be. ( or wait a long timeout and execute the code quietly)
You can use async and defer method with jQuery. But better than async and defer attributes, in this way you can load javascript after the browser has finished loading resources on the page.
When the browser has finished loading resources on the page, it fires the load event. And you can tell the browser to wait to load scripts until that happens.
Here's how to do that with jQuery :
$(window).on("load", function() {
$("body").append("<script type='text/javascript' src='some-javascript.js'>") //Load js after rendered
});
You can also do with native javascript :
window.addEventListener("load", function(){
const script = document.createElement("script")
script.src = "some-javascript.js" //Load js after rendered
document.body.appendChild(script)
});
In this way, it creates the script element after the resources have been loaded.

tabs.executeScript encounters ReferenceError when accessing a function defined in Content Script

Update:
It seems the problem comes from the fact that Webpack executes each module in its own function, meaning that no modules can exist in the global scope. Is there any elegant way to solve this problem, so that I can define a function in a Webpacked content script and access it from a different content script?
Original:
in my primary content script I define a function
function foo() {
console.log("foo")
}
In my background.js, I inject a new content script like so:
browser.tabs.query({currentWindow: true, active: true}).then(res => {
browser.tabs.executeScript(res.id, {code: "foo()"})
})
In my tab's console, I see
VM181:1 Uncaught ReferenceError: foo is not defined
at <anonymous>:1:1
Both content scripts should be in the same execution environment, so I should be able to share functions and variables in both scripts.
I've recently added Webpack for building my Chrome extension, and I'm using Webextension-Polyfill to promisify the chrome.* API as browser.
In the old version of my code this worked fine, but now it's not working. I have a feeling it's because of Webextension-Polyfill but I honest' can't figure it out.
EDIT:
The executeScript code IS being run in the tab. I can console.log and it appears in the console. However, it doesn't seem to have access to the namespace of my existing content script.
EDIT 2:
I added another content script with
function foo() {
console.log("foo")
}
And it's accessible from the injected script. So I guess it's something to do with Webpack.
Is it something to do with scoping in Webpack bundles?

Chrome Extension - How to execute a javascript file with button click function?

i read many documents about this but i couldnt figure out that. I need help about execute another js when button clicked.
test.js is my javascript file to execute. And in that file there is a just one line code like "alert("test.js executed!");
In my javascript file my click function is like that.
$("#src").click(function(){
alert("hi");
});
It's working well, i need to execute my "test.js" script. Like this:
$("#src").click(function(){
alert("hi");
$.getScript("javascript/test.js",function(){
})
.success(function(){
alert("success");
})
.error(function (){
alert("Failed to execute script");
});
});
But nothing happens. No errors aswell. How can i execute that script with click ?
That would fall under the use of eval, since that's exactly what getScript does.
This is not allowed by the default Chrome extension CSP and for a good reason.
You could argue that if the script is included with your extension, the security risk is non-existent,and you can override the CSP to allow that. It's bad and sloppy though.
Ideally, you want to simply include test.js with a <script> tag into the page, and call some function in it instead. Might need some modification on the file, but this is the proper way to do it.
If you absolutely need to execute the whole test.js every time (though there is no reason for it), create and append a <script> element with src appropriately set. This does not violate the CSP.

Uncaught Error: [$injector:modulerr] Failed to instantiate module with LABJS

I keep getting this error when loading my Angular app. In Chrome a couple refreshes and my app will run but IE and FF is a no go.
The error links me to this error page but I don't really understand what it says.
I am loading my app using LabsJS including the controllers and service.
// spAppLoader.js
$LAB
.script("../js/app.js").wait()
.script("../js/controllers/userCtrl.js")
.script("../js/controllers/groupCtrl.js")
.script("../js/controllers/siteCtrl.js")
.script("../js/services/userServices.js")
.script("../js/services/groupServices.js")
.script("../js/services/siteServices.js")
Markup:
<div id="mdContainer" ng-app="spApp" ng-cloak>
...
</div>
<script type="text/javascript" src="../js/spAppLoader.js"></script>
I wanted to post more code but I don't know where to start and with angular everything is in multiple files. I uploaded it through github.
You should manually bootstrap your app because you use an asynchronous script loader:
$LAB
.script("../js/app.js").wait()
.script("../js/controllers/userCtrl.js")
.script("../js/controllers/groupCtrl.js")
.script("../js/controllers/siteCtrl.js")
.script("../js/services/userServices.js")
.script("../js/services/groupServices.js")
.script("../js/services/siteServices.js")
.wait(function(){
var root = document.getElementById('mdContainer')
angular.bootstrap(root ,['spApp']);
})
What is bootstrapping?
angular.bootstrap(root ,['spApp']); is the same as <div id="mdContainer" ng-app="spApp"> only the last one would automatically initialize your app when DOMContentLoaded event occurs.
When using a script loader, DOMContentLoaded event might happen before all scripts are loaded, so you must wait for all your module scripts and then bootstrap your application manually.
In your case, chrome probably cached your scripts so after few refreshes the DOMContentLoaded event happened after all scripts were loaded.
From the docs:
Automatic Initialization
Angular initializes automatically upon DOMContentLoaded event or when the angular.js script is evaluated if at that time document.readyState is set to 'complete'. At this point Angular looks for the ng-app directive which designates your application root...
Manual Initialization
If you need to have more control over the initialization process, you can use a manual bootstrapping method instead. Examples of when you'd need to do this include using script loaders or the need to perform an operation before Angular compiles a page.
This error usually means angular can't find an object you are trying to inject into a controller or some other injectable function. After quickly looking through your code, my guess is that there is a problem with the way the files are being loaded, as you are referencing spApp from multiple files.
What I usually do is move separate files into their own modules, and then require other modules as needed. For example, instead of starting the userService like this:
spApp.factory('userService', function(){
put it into its own module
angular.module('spApp.services.user', [])
.factory('userService', function(){
Then whenever you need to use the userService in another module, add it as a requirement. Eg:
var spApp = angular.module('spApp', ['spApp.services.user']);

Categories

Resources