javascript stream wrapper, intercept JS file contents - javascript

In PHP there's a function called stream_wrapper_register. With that i can get the file contents of every PHP file that is about to be included. So that basically gives me control over the 'code' that will get parsed.
I was wondering if there's something like this in javascript too? So suppose i include my file:
<script type="text/javascript" src="js/myfile.js"></script>
My code in that file then sets up the stream wrapper (suppose this is available in JS too). Now i want to be able to get the file contents of every other javascript file that will be included:
<script type="text/javascript" src="js/somefile.js"></script>
<script type="text/javascript" src="js/someotherfile.js"></script>
But this ofcourse must happen before before the browser actually executes those files.
So is there a way to intercept that somehow?

$.ajax("/path/to/javascript.js").done(function(source) {
eval(transmogrifySourceCode(source));
});
I used the jQuery syntax because AJAX-style gets are much easier that way, and you'll have to provide your own transmogrifySourceCode function to edit the source before you load it.
I do wonder why you'd want to do, that, though. You should be in full control over your input source, so why not just excise the code you don't want on the server?

No, you can't. Alone for security reasons you won't be allowed to get every script's content.
For Opera, there is a special BeforeScript event which can be listened to from local user scripts.
So there is no (good) way to detect (dynamically added) <script> elements in a page and prevent them from loading and executing a script. Yet you could load the script files by ajax, respecting the same-origin-policy (!), and evaling their modified contents as #DavidEllis suggested.
Elsewise, you need to proxy all script inclusions over your server and modify them there.

Related

What is ?v=something mean in a JavaScript file name?

I've noticed on many sites the JavaScript file has it's regular name then ?v=something The something can be alphanumeric, or just random numbers.
For example:
<script src="./bundle.js?v=21knfa"></scrip>
I have a few questions about this:
The purpose:
What is the purpose of adding ?v=something on the file name. For example, does it allow the developers to have multiple versions of their code?
Server or Client
Is this done by the server or the client?
How would this be done
How would you add the version automatically to your JavaScript filename, does it involve a software like Docker to do this? Or is this done in another way.
Any help would be appreciated.
The Purpose
It is for client-side caching.
If you have a JS file script.js, the users browser will cache it. When you change script.js, the browser will still have the old cached version.
So, you add a ?v=... to it so when you make changes, the browser will load the new one.
Since it is in the HTML file, it is the server that sets the ?v=...
To do this yourself, simply add the ?v=...
<script src="javascript.js?v=1.0.1" type="text/javascipt"></script>
Example
Say you make a script for your site and name it "script.js".
In your code you put:
<script src="script.js?v=1" type="text/javascipt"></script>
Now when you change "script.js", you change your code as follows:
<script src="script.js?v=2" type="text/javascipt"></script>
Now your visitor's browsers will get the new "version" of your script file.
Also
You could use ?foo=... or really any other string.

Obtain content of <script src="..."> tag in HTML

I have an HTML file with Javascript, that is supposed to load and process an XML file. The main obstacle is that the script may also be run locally, without an HTTP server, and also has to support Internet Explorer (11).
In normal case, I would use XMLHttpRequest, but as far as I know, it cannot be used with locally stored files (or at least doesn't work in my test cases for Chrome and IE).
I tried using <script> blocks with set src and type="text/xml" attributes and it successfully loads the content of the xml "somewhere" (the content is loaded and is visible in the network trace), but I cannot find a way, to extract the content of the xml from the <script> node.
Most sources (e.g. Getting content of <script> tag) suggests using XHR, but AFAIK it cannot be done in this case.
Is there a sensible option to implement this, without minimal http server?
I am looking for a clean solution without jQuery.

Are JavaScript files downloaded with the HTML-body

I have a Java Web Application, and I'm wondering if the javascript files are downloaded with the HTML-body, or if the html body is loaded first, then the browser request all the JavaScript files.
The reason for this question is that I want to know if importing files with jQuery.getScript() would result in poorer performance. I want to import all files using that JQuery function to avoid duplication of JavaScript-imports.
The body of the html document is retrieved first. After it's been downloaded, the browser checks what resources need to be retrieved and gets those.
You can actually see this happen if you open Chrome Dev Console, go to network tab (make sure caching is disabled and logs preserved) and just refresh a page.
That first green bar is the page loading and the second chunk are the scripts, a stylesheet, and some image resources
The HTML document is downloaded first, and only when the browser has finished downloading the HTML document can it find out which scripts to fetch
That said, heavy scripts that don't influence the appearance of the HTML body directly should be loaded at the end of the body and not in the head, so that they do not block the rendering unless necessary
I'm wondering if the javascript are downloaded with the html body during a request
If it's part of that body then yes. If it's in a separate resource then no.
For example, suppose your HTML file has this:
<script type="text/javascript">
$(function () {
// some code here
});
</script>
That code, being part of the HTML file, is included in the HTML resource. The web server doesn't differentiate between what kind of code is in the file, it just serves the response regardless of what's there.
On the other hand, if you have this:
<script type="text/javascript" src="someFile.js"></script>
In that case the code isn't in the same file. The HTML is just referencing a separate resource (someFile.js) which contains the code. In that case the browser would make a separate request for that resource. Resulting in two requests total.
The HTML document is downloaded first, or at least it starts to download first. While it is parsed, any script includes that the browser finds are downloaded. That means that some scripts may finish loading before the document is completely loaded.
While the document is being downloaded, the browser parses it and displays as much as it can. When the parsing comes to a script include, the parsing stops and the browser will suspend it until the script has been loaded and executed, then the parsing continues. That means that
If you put a call to getScript instead of a script include, the behaviour will change. The method makes an asynchronous request, so the browser will continue parsing the rest of the page while the script loads.
This has some important effects:
The parsing of the page will be completed earlier.
Scripts will no longer run in a specific order, they run in the order that the loading completes.
If one script is depending on another, you have to check yourself that the first script has actually loaded before using it in the other script.
You can use a combination of script includes and getScript calls to get the best effect. You can use regular scripts includes for scripts that other scripts depend on, and getScript for scripts that are not affected by the effects of that method.

Caching Javascript inlined in HTML

Instead of having an external .js file, we can inline Javascript directly in HTML, i.e.
Externalized version
<html>
<body>
<script type="text/javascript" src="/app.js"></script>
</body>
</html>
Inlined version
<html>
<body>
<script type="text/javascript">
// app.js inlined
</script>
</body>
</html>
However, it's not recommended:
https://developer.yahoo.com/performance/rules.html#external
Put javascript and css inline in a single minified html file to improve performance?
The main reason is caching and pre-compiling - in the externalized version, the browser can download, pre-compile and store the file once for multiple pages, while it cannot do the same for inlined version.
However, is it possible to do something along these lines:
Inlined keyed version
<html>
<body>
<script type="text/javascript" hash="abc">
// app.js inlined
</script>
</body>
</html>
That is, do this:
In the first invocation, send the whole script and somehow tell the browser that the script hash is abc
Later, when the browser loads that or other pages containing the same script, it will send this key as a cookie. The server will only render the contents of the script if the key has been received.
That is, if the browser already knows about the script, the server will render just this:
Inlined keyed version, subsequent fetches (of the same or other pages)
<html>
<body>
<script type="text/javascript" hash="abc">
</script>
</body>
</html>
where notably the script contents are empty.
This would allow for shorter script fetching with a natural fallback.
Is the above possible? If not, is some other alternative to the above possible?
I don't know of a way to do what you asked, so I'll provide an alternative that might still suit your needs.
If you're really after a low latency first page load, you could inline the script, and then after the page loads, load the script via url so that it's in the browser cache for future requests. Set a cookie once you've loaded the script by direct url, so that your server can determine whether to inline the script or provide the external script url.
first page load
<script>
// inlined my-script.js goes here.
</script>
<script>
$(function(){
// load it again, so it's in the browser cache.
// notice I'm not executing the script, just loading it.
$.ajax("my-script.js").then(function(){
// set a cookie marking this script as cached
});
});
</script>
second page load
<script src="my-script.js"></script>
Obviously, this has the drawback that it loads the script twice. It also adds additional complexity for you to take care of when you update your script with new code - you need to make sure you address the cookie being for a old version.
I wouldn't bother with all this unless you really feel the need to optimize the first page. It might be worth it in your case.
The Concept
Here's an interesting approach (after being bugged by notifications :P)
You could have the server render your script this way. Notice the weird type attribute. That's to prevent the script from executing. We'll get to that in a second.
<script type="text/cacheable" data-hash="9182n30912830192c83012983xm019283x">
//inline script
</script>
Then create a library that looks for these scripts with weird types, get the innerHTML of these scripts, and execute them in the global context as if they were normally executing (via eval or new Function). This makes them execute like normal scripts. Here's a demo:
<script type="text/cacheable" data-hash="9182n30912830192c83012983xm019283x">
alert(a);
</script>
<script type="text/cacheable" data-hash="9182n30912830192c83012983xm019283x">
alert(b);
</script>
<script>
// Let's say we have a global
var a = "foo";
var b = "bar"
// Getting the source
var scripts = Array.prototype.slice.call(
document.querySelectorAll('script[type="text/cacheable"]')
);
scripts.forEach(function(script){
// Grabbing
var source = script.innerHTML;
// Create a function (mind security on this one)
var fn = new Function(source);
// Execute in the global scope
fn.call(window);
});
</script>
However...
Since you have the script source (the innerHTML), you can cache them somewhere locally (like in localStorage) and use the hash as its identifier. Then you can store the same hash in the cookie, where future page-requests can tell the server "Hey, I have cached script with [hash]. Don't print the script on the page anymore". Then you'll get this in future requests:
<script type="text/cacheable" data-hash="9182n30912830192c83012983xm019283x"></script>
That covers up the first half. The second phase is when your library sees an empty script. The other thing your library should do is when it sees an empty script, it should look up for that script with that hash in your local storage, get the script's source and execute it like you just did in the first place.
The Catch
Now there's always a trade-off in everything, and I'll highlight what I can think of here:
Pros
You only need one request for everything. Initial pageload contains scripts, subsequent pages become lighter because of the missing code, which is already cached by then.
Instant cache busting. Assuming the hash and code are 1:1, then changing the content should change the hash.
Cons
This assumes that pages are dynamic and are never cached. That's because if you happen to create a new script, with new hash, but had the client cache the page, then it will still be using the old hashes thus old scripts.
Initial page load will be heavy due to inlined scripts. But this can be overcome by compressing the source using a minifier on the server. Overhead of minification can also be overcome by caching minified results on the server.
Security. You'll be using eval or new Function. This poses a big threat when unauthorized code manages to sneak in. In addition, the threat is persistent because of the caching.
Out of sync pages. What happens if you get an empty script, whose hash is not in the cache? Perhaps the user deleted local storage? You'll have to issue a request to the server for it. Since you want the source, you'll have to have AJAX.
Scripts are not "normal". Your script is best put at the end of the page so that all inline scripts will be parsed by then. This means your scripts execute late and never in the time they get parsed by the browser.
Storage limits. localStorage has a size limit of 5-10MB, depending on which browser we're talking about. Cookies are limited to 4KB generally.
Request size. Note that cookies are shipped up to the server on request and down to the browser on response. That additional load might be more of a hassle than it is for good.
Added server-side logic. Because you need to know what needs to be added, you need to program your server to do it. This makes the client-side implementation dependent on the server. Switching servers (say from PHP to Python) wouldn't be as easy, as you need to port over the implementation.
If your <script> is not introduced as type=text/javascript, it will simply not be executed.
So you could have many tags like theses:
<script type="text/hashedjavascript" hash="abc">...</script>
<script type="text/hashedjavascript" hash="efg">...</script>
Then when the DOM is loaded, pick one and evaluate it.
I made an example here: http://codepen.io/anon/pen/RNGQEM
But it smells, real bad. It's definitely better to fetch two different files.
Actually what you should do, is have a single file my-scripts.js that contains the code for each of your script, wrapped in a function
// file: my-scripts.js
function script_abc(){
// what script abc is supposed to do
}
function script_efg(){
// what script efg is supposed to do
}
Then execute whatever your cookie tells you to. This is how AMD builders concatenate multiples files in one.
Also look for an AMD library such as requirejs
Edit: I misunderstood your question, removed the irrelevant part.

Any JavaScript or jQuery Method to Load JS files synchronously?

I'm loading user control through jQuery in my asp.net page.
User control contains JavaScript files, while loading the user control all my js load at one time which are dependent on each other and they tend to give error while all file load at one time. So I want that my JavaScript file to load synchronously one by one , as one file get completely loaded than next file should start loading .
Is there any way to set synchronously mode in JavaScript? or any JavaScript to set this? Any pointer or suggestion would be really helpful.
You should use jQuery.load() to load only a HTML fragment and not a full page with the scripts. jQuery use DOM structure of the loaded document to modify the DOM structure of the corresponding part of your page (controls).
In general you can use jQuery.ajax to load a script, but I recommend you to use the simplified form jQuery.getScript() instead. jQuery.getScript() can be used to load a JavaScript file from the server using a GET HTTP request and then execute it. Using success event handler you can do some action after the script are loaded.
JS files are loaded in the order you put them in your HTML code.
For example,
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/jquery-ui.min.js"></script>
You always need to load jQuery before jQuery UI (or UI will not be recognize since it uses the jQuery $ shortcut) so you must put the line with jQuery before the one with jQuery UI into your HTML.
And when your page is fully loaded, js will start thanks to window.onload, $(document).ready(function(){}); for jQuery or via the first command it will encounter.
JavaScript files always load synchronously. In fact, JavaScript always runs synchronously because it is single threaded.
My guess is that you need to work out which order to include the files so that it runs properly. You can use the window.onload event to run script once all of the JavaScript and images have been loaded.

Categories

Resources