I'm experimenting with Javascript modules both via desktop (latest Chrome) and mobile (Safari with iOS 14.6) and my code works perfectly on the desktop (standard browser or mobile emulation mode) but fails on my iPhone. The imported JS code using <script type="module"> simply doesn't execute despite being supported since Safari iOS 11 onward according to https://caniuse.com/?search=modules
The test code below, adapted from How to serve ES6 modules on Safari? , is hosted on a webserver in my local network reachable by both the mobile & desktop clients. For mobile debugging I'm using a locally copied version of https://www.hnldesign.nl/work/code/mobileconsole-javascript-console-for-mobile-devices/ to render console.log commands on mobile.
test_ios.html
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script>
console.log("Start of test_ios.html...");
</script>
<title>TESTS IOS</title>
<script src="/static/hnl.mobileConsole.1.3.js"></script>
<script nomodule src="/static/fallback.js"></script>
<script type="module">
console.log("Starting the main script.");
// The following line seems to cause an error in Safari only
import { TestClass } from './static/test_module.js';
// The rest is not executed due to the error
let test_class = new TestClass;
console.log("Done.");
</script>
<script>
console.log("End of test_ios.html...");
</script>
<body>
</body>
</html>
/static/test_module.js
export class TestClass {
constructor() {
console.log("Created a test class in test_module.js");
document.body.append("test_module.js");
}
}
/static/fallback.js
console.log("Fallback.js");
document.body.append("Fallback");
Result on the desktop, as expected
Test string test_module.js gets written onto the web page & the following lines are in the console:
--==## Mobile Console v1.3.5 active ##==--
End of test_ios.html...
Starting the main script.
Created a test class in test_module.js
Done.
Result on iOS 14 - neither the module JS nor the fallback get executed
The page is blank (no document.body.append(...) was executed) & only the following lines are in the console:
--==## Mobile Console v1.3.5 active ##==--
End of test_ios.html...
Further checks already done:
I sniffed the network and I see that /static/test_module.js is requested by the mobile device (no request for fallback.js).
The content-type of /static/test_module.js returned by the webserver seems coherent (application/javascript; charset=utf-8).
Renaming test_module.js to test_module.mjs doesn't help (same outcome as above)
I found the issue: the following library broke the JS execution in Mobile Safari as soon as a call was done to console.log:
<script src="/static/hnl.mobileConsole.1.3.js"></script>
Removing this library inclusion or/and replacing all calls to console.log by alert made the code above work as expected. The example code also feature minor errors (e.g. no </head> closing) but this wasn't the root issue.
I checked if jshint would have caught it in ES6 mode, unfortunately without success.
Takeaway for next time in case of issues with Mobile Safari: litter your JS code with alert boxes to see when / where it breaks :(
Related
I've been hacking round for about a week trying to work this out, so finally cracked and asked a question:
My setup is Raspberry Pi 2 running Apache and IBM's Node-Red. I'm using Apache to serve up a simple web page which calls Node-Red to kick off a flow (in this case it's to switch on and off lights via Open Zwave.)
The following solution works on desktop browsers (firefox / IE 11) but not on mobile browsers (IE on WP8.1 and Android browser). However the code triggers the "Alert" from mobile browsers, just not the $.get() Any ideas?
Note that I've used two different methods of calling the target, one proper JSON, the other just a string. Both work on desktop browsers, both fail mobile browsers.
Header:
<meta http-equiv="X-UA-Compatible" content="IE=10; IE=11; IE=edge"/>
<script type="text/javascript" src="./js/jquery-2.1.4.min.js"></script>
Script Section:
<script>
// Wait until the page is loaded so that all the IDs are setup
$(document).ready(function(){
$('img').click(function(){
switch ($(this).attr('id')) {
case 'node-3-on':
$.get("http://node-red:1880/setValueBinary.html", {nodeid:"3", value:"1"});
alert ("node 3 on");
break;
case 'node-3-off':
// alert ("node 3 off");
$.get('http://node-red:1880/setValueBinary.html?nodeid=3&value=0');
break;
// removed further case statements
default:
alert ("You shouldn't see this, some sort of error has happened.");
};
});
});
</script>
HTML:
<p><b>Switch 3:</b></p>
<p> <img src="images/green-tick.png" id="node-3-on" alt="Switch On" height="100" width="100" />
<img src="images/red-cross.png" id="node-3-off" alt="Switch Off" width="100" height="100"/></p>
At the suggestion of a workmate I installed Chrome and set it up to do remote debug on my Android phone.
https://developer.chrome.com/devtools/docs/remote-debugging
It turns out that the problem was that for some reason desktop/laptop/tablet devices can resolve the shortname of the raspberry pi, however mobile phones can't. This is using the same DHCP and DNS servers. I went through the code and added FQDNs to all the URLs and it all works fine now.
I'm sort of glad and sort of livid.
Thanks all for your help.
I'm working through the JS SPA book and noticed I get different results in chrome vs firefox. Here is the code...
<!doctype html>
<html>
<head>
<title>SPA Chapter 1 section 1.2.2</title>
<style type="text/css"></style>
<script type="text/javascript">
var prison = function () {
console.log('made it to prison');
};
prison();
</script>
</head>
<body>
<div id="spa"></div>
</body>
</html>
Nice and simple...no? In chrome I get the expected result of "made it to prison" in the console. However, in FF only get an error that reads...
The character encoding of the HTML document was not declared. The document will render with garbled text in some browser configurations if the document contains characters from outside the US-ASCII range. The character encoding of the page must be declared in the document or in the transfer protocol.
What gives? Is there a setting I'm missing in the FF webdev console?
Firefox shows the expected result in the console log, when you enable console logging in dev tools. It also shows a message, classified as an error message in some versions but not affecting the functionality. It is effectively an informational message that says that the character encoding of the page was not declared in any way; see the W3C page on encodings.
The way to control what is shown in the console log depends on the dev tools you are using. Using the built-in dev tools in the current version of Firefox, called Aurora, which you can invoke with Ctrl Shift K, make sure that “Logging” is enabled (appears in black, not grey) as in this image:
You need to decide on the character encoding. For any modern application, there is seldom need to consider any other option than UTF-8. You can declare it by saving the HTML file as “UTF-8 with BOM” in your text editor and/or by using the tag <meta charset=utf-8> in the head part. If you only use the latter and if the page is ever sent via HTTP, you should make sure that the server does not send conflicting information in the Content-Type HTTP header.
I have this simple Titanium js script.
app.js
var win = Ti.UI.createWindow();
var webview = Ti.UI.createWebView({
url: 'logging.html'
});
webview.addEventListener('help',function(){
alert('help');
});
win.add(webview);
win.open();
logging.html
<html>
<body>
<a onclick="Ti.App.fireEvent('help')">Help</a>
</body>
</html>
when I click on the Help link, the console gives me Reference Error: Ti is not defined.
I also tried changing Ti with Titanium, but same error.
------------- EDIT ----------
this error comes only with web browser. iOS works perfectly. but
when titanium studio compiles the project for web mobile, I can see titanium.js and TI/* folder, so I guess it can't load Ti object. can anyone explain me why?
I found a solution!
simply add to all of your html pages the simple script below
var Ti = window.parent.Ti
have fun!
EDIT:
from sdk version 3.0.2GA on, I guess they fixed it. now it calls Ti sdk without that hack!**
First, change:
webview.addEventListener('help',function(){
alert('help');
});
To:
Ti.App.addEventListener('help',function(){
alert('help');
});
And second: Call "Ti.App.fireEvent()" without the final "s" in your HTML file.
after some tests, I found that the previous code works perfectly on iOS phisical device/simulator and Android.
it doesn't on android web browser emulator and normal mobile browser (Firefox as mobile web app)
so, it seems that Titanium api calls will never work on web browsers because of "normal javascript library doesn't have Titanium.* or Ti.*".
I used this and it worked
window.parent.TiApp.fireEvent
I'm getting a "Resource interpreted as Script but transferred with MIME type text/plain" warning in Google Chrome when including a local script file.
I know the problem appears when loading a file from a server or through ajax which most often depends on wrong headers being set.
The weird thing is that I get this warning even though it is run from a local folder: file:///C:/test/foo.html
This happens only in Chrome with the most basic html there is:
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="bar.js"></script>
</head>
<body>
</body>
</html>
bar.js is also as simple as it can get:
function hello() {}
I've tried adding a meta tag:
<meta http-equiv="content-script-type" content="text/javascript">
and tested with other doctypes but nothing seems to help.
This obviously isn't a real issue since the scripts still work fine, but I'm working on a large project and currently have around 150 scripts included. It therefore makes it difficult to see when an actual warning occurs in between them.
Everything works fine when I run the file on a server, locally or remote.
Any ideas on why chrome is annoying me with this?
I figured it out!
The Visual Studio installer must have added an errant line to the registry.
open up regedit and take a look at this registry key:
See that key? The Content Type key? change its value from text/plain to text/javascript.
Finally chrome can breathe easy again.
I should note that neither Content Type nor PercievedType are there by default on Windows 7, so you could probably safely delete them both, but the minimum you need to do is that edit.
Anyway I hope this fixes it for you too!
I tried fixing this problem using this method but it didn't work for me.
My problem was that IIS manager didn't have MIME types in HTTP Features.
I was able to turn it on by enabling Static Context via...
--> Control Panel
--> Programs
--> Turn Windows features on or off
--> Internet Information Services
--> World Wide Web Services
--> Common HTTP features
--> [X] Static Content.
After this, MIME types appeared and everything started working again.
The accepted answer is a great one! However, just to post an answer for those who encounter problem like me, who use a department/college computer sometimes, where I do not have the permission to change any key value in regedit.
Change
<script type="text/javascript" src="main.js"></script>
to
<script src="main.js"></script>
Although the error message still exist, the page loaded correctly.
i am using requires.js 2.0. I have the following simplified use case:
my HTML file:
<!DOCTYPE HTML>
<html>
<head>
<title></title>
<script type="text/javascript" data-main="apptest.js" src="../_js/libs/require/require.js"></script>
</head>
<body>
</body>
</html>
And then in apptest.js:
requirejs.config({
paths: {
'text': '../_js/libs/require/text'
}
});
requirejs(
['text!boxes.html'],
function (Boxes) {
alert("done");
}
);
Ok, so it doesn't really do much, but enough to make my point. Only in Firefox (14.0.1) i get an exception "uncaught exception: java.security.AccessControlException: access denied (java.io.FilePermission .\boxes.html read)".
So, require.js successfully loaded the text plugin, but fails loading my html file, which i want to use as a template later on. In Google Chrome and even IE9 it works just fine. I am on Windows 7.
I am running this on a local webserver, so no file://... requests here.
I have checked, if i have any special permissions set on the html file, but have not found anything suspicious.
Anyone have an idea?
Update: Running the test in Firefox 13.0.1 does actually work for me without errors. So could it be, that this is a bug, that has been introduced in firefox 14?
I was having the same problem a minute ago. I've fixed it by doing the following in the main.js file (where you setup the config)
Before the
require.config({.....
add the following code:
Packages = undefined;
This should do the trick.
You should have something like this:
Packages = undefined;
require.config({
baseUrl: theAppBaseUrl,
paths: {
Basically the explanation is that it is trying to use Java to get the file instead of an ajax request (for whatever reason). This forces it to use an XHR object to fetch it.
Cheers!