Conflict over require() function between Facebook SDK (xd_arbiter.php) and RequireJS - facebook

Setup / Background
We're trying to load the Facebook SDK through RequireJS:
require.config({
'shim': {
'facebook' : {
'exports': 'FB'
}
},
'paths': {
'facebook': '//connect.facebook.net/en_US/all/vb'
}
});
(/en_US/all/vb.js is basically identical to the usual /en_US/all.js, but also includes FB's experimental Music Bridge feature. However, the problem still exists with either version of the SDK.)
... and the main body of the SDK is loading correctly. However, during initialisation of the Facebook SDK it creates an iframe which makes a request out to:
https://www.facebook.com/connect/ping?client_id=<CLIENT_ID>&domain=<DEVELOPMENT_SERVER>&origin=1&redirect_uri=<...>
... which then redirects to:
http://static.ak.facebook.com/connect/xd_arbiter.php?version=27#
... which in turn returns a minimal HTML document with a script tag that defines a number of additional javascript modules for the Facebook SDK.
The problem
Both the main Facebook SDK vb.js and the xd_arbiter.php script seem to make use of a require() function (defined in each file in their default top-level scope) to load Facebook SDK modules.
While the main Facebook SDK (vb.js) is loaded through a RequireJS shim (and hence - I believe - its scope is limited by RequireJS, so the require() function it defines doesn't interfere with RequireJS's global require() function), because the xd_arbiter.php code is loaded in an iframe it's somehow being executed in the global scope of the browser.
This seems to be causing a conflict with the RequireJS version of the function - every time the page loads we get a RequireJS error in xd_arbiter.php (line 13):
Error: Invalid require call
http://requirejs.org/docs/errors.html#requireargs
... which seems to be caused by the xd_arbiter.php code calling what it thinks is its own require() function, but is actually the RequireJS version of the function... and hence the parameters passed to the function are invalid for RequireJS.
We're currently in the middle of trying to replace an old legacy/custom/hand-rolled module system with a nice, common, relatively-standard library like RequireJS, and this has brought us to a screeching halt.
The question
Can anyone suggest a way to either:
Persuade xd_arbiter.php to define a require() function not in the global scope,
In addition to vb.js, also load the scripts defined in xd_arbiter.php through RequireJS instead of via an iframe, or
Persuade RequireJS to not define a global require() function (for legacy reasons we're actually using a thin wrapper around RequireJS's require() function so our existing module code keeps working for now, so it's no great imposition to change the name of the method we call to define RequireJS modules, as it's only used in one place in the code)
... without doing something gross like hacking/forking RequireJS or the Facebook SDK?
Alternatively, have we missed something really obvious somewhere that we should be doing differently? I'm pretty new to both RequireJS and the Facebook SDK, so I'm fully aware we may have just overlooked something/made a stupid mistake somewhere.

Never mind - it turned out to be a bug in the function we were (for legacy, compatibility reasons) using to wrap calls to RequireJS's require() function, that was legitimately calling require() with incorrect parameters.
For some reason some quirk of our setup was causing Firefox to report any and all JS errors on the page as having occurred in xd_arbiter.php (on a line which - by sheer dumb fluke - happened to have a call to the FB SDK's own require function!), instead of whichever actual file the error occurred in.

Related

Flutter Web Get Chrome Extension info from Polkadot.js web3Enable

I am hoping to confer on a strategy for a flutter web app (as can ignore mobile cases here) to get chrome extension info for a Polkadot.js wallet from the Polkadot browser extension.
My first thought is to use dart's JS library and use the Polkadot extension JS package and then try and pull the info from there. However, I'm not sure how to properly use this in flutter as it is a whole package full of dependencies, not just a single JS file. Also it is in TS not JS. Any thoughts here?
Eg., I need a JS file to be able to call this; and for flutter to in turn call the JS file:
import {
web3Enable,
} from '#polkadot/extension-dapp';
By writing out a "bridging" layer, you can do it easily.
Firstly, create a normal javascript (or typescript) application (nothing related to Flutter). You should be able to happily use the polkadot lib in your js/ts code without any problem. You may need to learn a bit about how to develop js code normally (e.g. you can depend on polkadot using npm, etc).
One small thing is that, you should "expose" some object publicly in your js/ts code. For example, your code may look like window.myFancyFunction = function() { call_some_polkadot_function(); }. Of course you can do more things like exposing other functions/objects/...
Then, you can bundle this normal js/ts application into a .js file. This is still very normal for js/ts developers and should have nothing special to deal with here, and you still do not need to touch Flutter at this stage.
Next, load this single-filed .js file when you are loading your Flutter Web application. You may simply do this by editing your Flutter Web's html file and add <script src="my_single_filed_js_mentioned_above.js" />. Notice that, when loading this script, it simply sets window.myFancyFunction and does not do anything more. Still very trivial here, should have no problem.
Lastly, in your Flutter Web code, i.e. Dart code, call that window.myFancyFunction function. For example, Flutter Web : How to run javascript using dart js says you can do import 'dart:js' as js; js.context.callMethod('myFancyFunction', ['some arguments']);

Facebook is not initialized when using Facebook Login with React in Production

I love React, it has quickly become my favorite development tool. It is a fantastic library that creates the kind of flexibility I've always dreamed about.
That said, I'm having a very hard time getting Facebook login to work with React in production.
I have tried all of the following methods. In all three cases, I implemented the examples exactly as shown in the code using the simplest possible technique:
https://github.com/seeden/react-facebook
https://github.com/keppelen/react-facebook-login
http://jslancer.com/blog/2017/11/27/facebook-google-login-react/
Everything works great in development. :)
When I create the production build using create-react-app and push it live, it breaks and reports: Error: Facebook is not initialized or Uncaught TypeError: Cannot read property 'login' of undefined where undefined is FB.
Basically it seems like the Facebook javascript SDK is not loaded or initialized.
The first two links above are for existing component libraries, but the third is a custom implementation that places the Facebook initialization code in the index.html file and creates an event listener. The results are the same in all three examples.
It is as if something about the create-react-app compression method is obfuscating the variables to the point that Facebook can no longer work, or at least is not available to the react code. This includes all calls to window.FB as recommended in many tutorials.
I've been working at this for a couple of weeks now (off and on) and am now turning to the hive mind. Anyone have any ideas on how to get Facebook to actually work with Facebook's own code library (React)? It seems so painfully odd that it causes this much trouble and I have been unable to find a clear solution that works in production.
Most of the debugging steps are already mentioned in the comments section.
Here are the steps laid down:
1) Check the network tab in your browser's console and see if the request to load FB's SDK is successful or not
2) Most common culprit is some extension like Ad-Blocker blocking such async requests which loads JS on your web page. Disable it or try it incognito mode
3) Other common mistake I have seen is forgetting to use the FB.init({ // config }); function - which is the actual call which initializes the fb sdk and makes available the FB variable globally.

How does jQuery.sap.require work?

Does SAPUI5 load the libraries each time I call jQuery.sap.require("someLibrary")?
For instance if I am calling the above statement in multiple modules in my application, is "someLibrary" loaded multiple times also?
In case someone still considers to use jQuery.sap.require, be aware that it sends only synchronous XHRs which should be avoided.
The use of jQuery.sap.require is synchronous and considered as "bad practice" because syncXHR is deprecated by the Web Hypertext Application Technology Working Group. (Source: Modules and Dependencies)
Instead, the current best practice is to use sap.ui.define or .require for asynchronous module loading:
<!-- Enable asynchronous module loading in index.html (available since 1.58.2) -->
<script id="sap-ui-bootstrap" src="..." data-sap-ui-async="true" ...>
sap.ui.define([ // or .require
// modules to load
], function(/* modules available once loaded */) {
// ...
});
Source: Asynchronify Your App by Arnd vom Hofe. Note: anonymous sap.ui.define can be called only once at top-level.
Same as jQuery.sap.require, the API sap.ui.require([/*...*/]) fetches the modules also only once depending on their internal states.
For more information, please take a look at the topics under Modules and Dependencies.
Sync XHR is deprecated not only by the web platform generally, but will be also replaced by UI5 gradually with a new set of APIs.
Source: UI5 Evolution by Peter Muessig
Consequently, jQuery.sap.require and jQuery.sap.declare are now deprecated and will be removed in the next major UI5 version (aka. "Legacy-free UI5")!
The lib is only loaded once. You can find this information in the SDK
https://sapui5.hana.ondemand.com/sdk/#docs/guide/ModularizationConcept.html
Module Loading
As mentioned already, modules are loaded by calling function jQuery.sap.require with the name of a required module. The framework then checks whether the named module is loaded already. If so, the function simply returns. Otherwise it tries to load and execute the module synchronously. If any of these two steps fails, an exception is thrown and execution of the calling module thereby is disrupted.
When you call this function with some library, it checks that given library is loaded or not using associative array. If the library is loaded, then it returns null. And if the library is not loaded, then it loads the library using sjax call and after a success of the sjax call, it sets the library name as key into associative array.
The libraries are loaded once. This can be seen in the network tab in chrome developer tools.
Also check the documentation as pointed by cevou here:
https://openui5.hana.ondemand.com/#/topic/91f23a736f4d1014b6dd926db0e91070

How GWT code runs in development code

In GWT web/production mode, Java code is complied into Javascript code that is rendered in the browser.
Also,I have always thought that in GWT development mode, GWT developer plugin compiles my Java code into JavaScript to render it in the browser. But after reading on some site, I came to know that there's no compiling of code to JavaScript to view it in the browser in development mode.
So, I wonder: What are all these widgets I see in the browser during this mode if they aren't JavaScript code?. I don't understand it.
Please help understanding this.
The crux of the Dev Mode is that your code runs in Java. This is a prerequisite if you can use a standard Java debugger. You'll find a high-level overview in the GWT documentation.
The magic happens with JSNI methods and overlay types: when a class is loaded, all its JSNI methods are extracted and their JS body is sent to the browser, ready to be executed (as JavaScript then), and the class is rewritten on the fly to reimplement the JSNI method to make a call to the browser (via the Dev Plugin you installed there and is triggered by ?gwt.codesvr= in the URL) to execute the corresponding JS function. This is the reason why Java objects are seen as opaque handles in JSNI methods; they're assigned a numeric ID to pair the Java object with a dummy JS object on the server-side. A similar though more complex rewriting is done for overlay types, and the same ID mapping is used when JS objects are passed to Java code (as overlay types).
BTW, Super Dev Mode compiles to JavaScript (almost) on the fly.

body.onload and GWT onModuleLoad launch order

According to this FAQ, when GWT bootstraps, onModuleLoad is supossed to run before HTML body's onload event. The process detailed within that FAQ works like this:
1. The HTML document is fetched and parsing begins.
...
9. externalScriptOne.js completes. The document is ready, so onModuleLoad() fires.
...
12. body.onload() fires, in this case showing an alert() box.
But in my tests, i have checked that it doesnt work this way. Or at least not in every browser (oddly, Google Chrome in particular doesn't stick to this kind of behaviour). For example, I have this little test involving onModuleLoad and body.onLoad:
public void onModuleLoad() {
runTestFunction();
}
private native void runTestFunction() /*-{
console.log("GWT's onModuleLoad");
$wnd.loaded=true;
}-*/;
And:
<body onload="console.log('body.onLoad');if(loaded!=null) console.log('loaded var is set');">
If i launch firefox, and run this example, the console will show this:
GWT's onModuleLoad
body.onLoad
loaded var is set
But in Chrome:
body.onLoad
Uncaught ReferenceError: loaded is not defined
GWT's onModuleLoad
In the latter, onModuleLoad runs the last, thus "loaded" var is not yet available and body.onLoad code cant use it.
And what Im trying to achieve? I want some handwritten Javascript that runs within body.onload to interact with my GWT code. In this example i use this dummy "loaded" var, but in the future it should be able to call GWT functions written in Java. The problem is that i need to make sure that onModuleLoad runs first so it can export the variables and methods for javascript to access them.
So, what am i missing? Is this behaviour as unreliable as it looks like, or am i doing something wrong?
PS: i have a plan B to achieve this which is proved to work, but first i want to make sure that it isnt possible to do it this way since this should be the preferred method.
First, the latest version of the doc is at http://code.google.com/webtoolkit/doc/latest/DevGuideOrganizingProjects.html#DevGuideBootstrap
And it says (even the GWT 1.5 version you were looking at) that "onModuleLoad() can be called at any point after the outer document has been parsed", which includes before and after window.onload.
As the doc says, GWT loads your code in an iframe (used here as a sandbox), which is asynchronous; so your code loads when both the iframe and the "body" are loaded. Depending on the time needed to load the iframe, that can be before or after window.onload (in the example, they assume it loads right away, which could be the case when the *.cache.* file is effectively in the browser's cache).
But the rule of thumb is that GWT tries hard (at least the built-in linkers) to make things start asynchronously so that it doesn't break loading of other external resources (stylesheets and images, for instance). That implies that it cannot be guaranteed to run before the window.onload (they could have guaranteed to run after window.onload, but why wait?)