Windows WebView is not able to invoke script function wrapped by webpack - javascript

I have UWP C# app and I am trying to invoke my javascript function from code like this:
webView.InvokeScriptAsync("myCoolFunc", new List<string> { });
Everything is fine if I have function in *.html file like this:
<Script>
function myCoolFunc() {
//do something...
}
</Script>
If I use webpack and I move content of generated bundle file into script tags my function is not called.
Webpack wraps my function something like this:
<Script>
...
(function(module, exports, __webpack_require__) {
"use strict";
/* WEBPACK VAR INJECTION */(function(process) {
Object.defineProperty(exports, "__esModule", { value: true });
const store_1 = __webpack_require__(8);
function myCoolFunc() {
//do something...
}
exports.updateMyFunc = updateMyFunc;
...
</Script>
How should I set webpack.config or webView.invokeFunction to properly call my function?

A public access function
If you don't want to make your method public, you could write just a "communicator" function, that will call your webpack-wrapped myCoolFunc() like the following:
<Script>
function uwpCommunicator( functionToCall ) {
if ( functionToCall === "myCoolFunc" ){
//call myCoolFunc();
}
}
</Script>
Eval
You can also run arbitrary script on the page using the eval function:
await webView.InvokeScriptAsync("eval", new string[] { "//your JS code" });

Related

How to write a type declaration for UMD global js library

I'm trying to enhance a third-party js library with typing.
Consider the following structure of the js library:
'use strict';
var AutoModel = AutoModel || {};
if (typeof AutoModel.constructed === "undefined") {
(function (o) {
function open() {
...
}
o.Motor = new function() {
function start()...
}
...
o.constructed = true;
})(AutoModel);
}
The js is loaded in the <script> section and in my ts file it would use it like:
declare const AutoModel: any;
export class TestClass {
doSomething(): void {
AutoModel.open();
AutoModel.Motor.start();
}
}
How can I write a d.ts that gives me typing and code completion for 'AutoModel'?
Would be cool if I could omit the redeclaration completely.
I've already tried a lot of different approaches but none leads to a completely satisfying solution.

jQuery noop causing JS minify to remove code in .NET Framework 4.8 web app

When I publish my .NET app, one of my JS files doesn't minify correctly. I have several hundred lines of code in the file but end up with a near empty function after the process has completed. I have gone through it and determined it is down to a $.noop that I use, without it the process works fine. To demonstrate this I have broken it down into a simple example that shows how it affects the file.
var MyApp = {};
MyApp.EmailPopup = (function () {
function Test() {
// do lots of jquery stuff
alert('hi');
}
var thisObject = {
Show: $.noop
};
thisObject.Show = function () {
Test();
};
return thisObject;
})();
When minified the call to Test is removed as shown:
var MyApp={};MyApp.EmailPopup=function(){return{Show:$.noop}}();
However if I remove the $.noop function and add an empty function instead like so:
var MyApp = {};
MyApp.EmailPopup = (function () {
function Test() {
// do lots of jquery stuff
alert('hi');
}
var thisObject = {
Show: function () { } // this has changed
};
thisObject.Show = function () {
Test();
};
return thisObject;
})();
Then I get the desired minified version:
var MyApp={};MyApp.EmailPopup=function(){return{Show:function(){alert("hi")}}}();
In the real app, by it not including the equivalent Test function I am losing hundreds of lines of code. Can someone explain why using $.noop prevents it from working, but initialising to an empty function or null works? It is a .NET 4.8 web application, it uses jQuery 3.3.1 and I build it with Visual Studio 2019.

Javascript Browserify, require function and run it

I have this little browserify problem. I want to require a self made module and run it instantly.
Main File:
(function() {
require('./modules/initScrollReveal')();
require('./modules/initChart')();
require('./modules/initDatamap')();
})();
Module:
exports.initChart = function () {
// do stuff
};
now i get an error with the Message
"require(...) is not a function" at require('./modules/initScrollReveal')();
Browserify is running via Watchify with
watchify public-modules/res/js/main.js -o public/res/js/main.js
module.exports allows the initChart function to be called like a function when required. Simply setting exports wouldn't allow the function to be exported because node exports the object module.exports references.
change
exports.initChart = function () {
// do stuff
};
to
module.exports = function initChart () {
// do stuff
};
More details : browserify-handbook#exports
Try:
(function() {
require('./modules/initScrollReveal').initScrollReveal();
require('./modules/initChart').initChart();
require('./modules/initDatamap').initDatamap();
})();
if your modules looks like:
exports.initScrollReveal= function () {
// do stuff
};
exports.initChart = function () {
// do stuff
};
exports.initDatamap= function () {
// do stuff
};

requirejs returns undefined in asp.net core application

I installed requirejs nuget package and added to my Index.cshtml this:
<script src="~/lib/requirejs/require.js" data-main="/js/scripts/tetromino-client/client.js"></script>
My project structure looks like this:
wwwroot
|-js
|-scripts
|-tetromino-client
|-client.js
|-block.js
Views
|-Home
|-Index.cshtml
client.js
requirejs(["block"], function (Block) {
var block = new Block(); // Block is undefined
console.log(block.value);
});
block.js
function Block() {
this.value = 50;
}
Requirejs cannot resolve block.js and returns undefined. What did I do wrong?
What you're missing is a requirejs.config call with baseUrl, telling RequireJS where to look for additional libraries:
requirejs.config({baseUrl: './js/scripts/tetromino-client'}):
requirejs(["block"], function (Block) {
var block = new Block(); // Block is undefined
console.log(block.value);
});
And then you need to use define syntax when defining the block module:
define(function () {
function Block() {
this.value = 50;
}
return Block;
});

requirejs loading same module twice

I'm using the single-page app template from https://github.com/volojs/create-template
I tried to make a simple example below.
Problem
ModuleA.js is being loaded twice, once directly from main.js and again from simulator.js which depends also on that module. This is causing two different references to an object (which I thought would only be one, like a singleton). I thought requirejs would not load the same module twice. Being (relatively) new to JavaScript I realize this may be naivete on my part. I'm trying to follow the template.
Here's a simplified version that demonstrates the problem:
www/index.html
<head>
...
<script data-main="app" src="lib/require.js"></script>
</head>
...
www/app.js
// For any third party dependencies, like jQuery, place them in the lib folder.
// Configure loading modules from the lib directory,
// except for 'app' ones, which are in a sibling
// directory.
requirejs.config({
baseUrl: 'lib',
paths: {
app: '../app'
}
});
// Start loading the main app file. Put all of
// your application logic in there.
requirejs(['app/main']);
www/app/main.js
define(function (require) {
var simulator = require('./simulator.js');
var ModuleA = require('./ModuleA.js');
ModuleA.init();
ModuleA.displayList();
ModuleA.update("joe", 99);
ModuleA.displayList();
simulator.start(); // should display the same list
});
www/app/ModuleA.js
define(function () {
var theList = {};
console.log("loading ModuleA");
return {
displayList: function () {
console.log(Object.keys(theList));
},
init : function () {
theList["fred"] = 10;
},
update : function (k, v) {
theList[k] = v;
}
}
});
www/app/simulator.js
define(["./ModuleA"], function (ModuleA) {
return {
start: function () {
ModuleA.displayList();
}
};
});
console output:
loading ModuleA
loading ModuleA
["fred"]
["fred", "joe"]
[]
The empty [] displayed on the last line is (likely) the second copy of the list due to the second loading of ModuleA.
The problem is the module references are not consistent. In main.js it requires ./ModuleA.js whereas in simulator.js it defines ./ModuleA (without the .js filetype).
Making those references identical corrects the behavior such that the module is only loaded once.
I guess I mixed the styles because of the many examples on the web. It kind of seems like a bug that it works this way, but maybe it's a feature?
If you want to share an instantiated singleton object using requireJS, you can do something like this for ModuleA:
define(function () {
console.log("loading ModuleA");
function myList(){
this.theList = {}
}
myList.prototype.displayList = function () {
console.log(Object.keys(this.theList));
}
myList.prototype.init = function () {
this.theList["fred"] = 10;
}
myList.prototype.update = function (k, v) {
this.theList[k] = v;
}
return new myList();
});

Categories