简体   繁体   中英

Cordova Plugin js-module Limitation

So I'm creating a Cordova plugin that needs to pull in a whole bunch of js files, 5 in total, each one of them needs to execute code. I understand that if I declare it like this,


//in Plugin.xml

<js-module src="www/js/alice.js" name="alice">
    <runs/>
</js-module>
<js-module src="www/js/bob.js" name="bob">
    <runs/>
</js-module>

The should both run, and considering the following code,

//in alice.js

function alice()
{
    console.log("Hello World From Alice!");
}

//in bob.js

function bob()
{
    console.log("Hello World From Bob! Are you there Alice?");
    alice();
}

bob();

//Output

Hello World From Bob! Are you there Alice?
Uncaught ReferenceError: alice is not defined

Now bob executes fine, but it can't find the alice method even though that script executes prior to bob. Any idea how to get around this issue, if it's even possible to do so? Merging all my js into a single file is not an option unfortunately.


Edit: (16:00) 28/05/2015

Okay so I have another idea of including one script with the "runs" attribute, and just copying the remaining scripts without the attribute. This script will then embed the copied scripts for me, execute then go onto the next in a kind of linked list. My init script looks like this,

var scripts = [
    "js/1.js",
    "js/2.js",
    "js/3.js",
    "js/4.js",
    "js/startup.js"
]

function InjectLinkedScript(parent, scripts, index)
{
    console.log("Injecting script '" + scripts[index] + "', at index '" + index + "'.");
    var head = document.getElementsByTagName('head')[0];
    var script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = scripts[index];
    script.onload = function(script)
    {
        if(index < (scripts.length - 1))
        {
            var head = document.getElementsByTagName('head')[0]
            InjectLinkedScript(head, scripts, index + 1);   
        }
    };
    head.appendChild(script);
}

var head = document.getElementsByTagName('head')[0]
InjectLinkedScript(head, scripts, 0);

The final script, has some code that I would like to execute that completes my initialisation, unfortunately it then embeds all of the scripts again but I don't know why. My plugin.xml looks like this,

<asset src="www/js" target="js" />
<js-module src="www/jspre/init.js" name="init">
    <runs/>
</js-module>

The asset tag, are my scripts that i just want to copy over, and the js-module one is the script above that executes the second its injected.

So just to recap what happens here, init.js injects 1.js into the header, which then executes, once 1.js then injects 2.js, and so on until 4.js injects startup.js which has my method that I would like to call. I can let the script finish and exit at that point and then use the JavaScript console to execute the method in startup.js myself, this results in a bunch of scripts being embedded again. But they are already there and ready, I don't need them embedded again.

You can only have up to one "runs" tag

Official documentation: https://cordova.apache.org/docs/en/3.0.0/plugin_ref_spec.md

The <runs/> node causes the defined <js-module> to be made available on the plugin's namespace. This means to use a defined module you need to require() it with the prefix of your plugins id followed by the name of your js-module.

You also need to need to use exports to gain access to your components methods.

So to get your bob snippet to work your code would be as follows.

plugin.xml

<plugin id="cordova-plugin-bob-and-alice" version="0.0.1" xmlns="http://apache.org/cordova/ns/plugins/1.0" xmlns:android="http://schemas.android.com/apk/res/android">
    <js-module src="www/js/alice.js" name="alice">
        <runs/>
    </js-module>
    <js-module src="www/js/bob.js" name="bob">
         <runs/>
    </js-module>
</plugin>

alice.js

function alice(){
   console.log("Hello World From Alice!");
}
module.exports = alice;

bob.js

var alice = require('cordova-plugin-bob-and-alice.alice');

function bob(){
    console.log("Hello World From Bob! Are you there Alice?");
    alice();
}

bob();

module.exports = bob;

The bob() method will execute because you have executed it at run time. If you wanted to implement it as a reusable method you would need to export it from the js file as well.

Also I can't see any reason technically or otherwise as to why you couldn't have more than one <runs/> module. The intend is to create reusable modules between plugins. You can even import <js-modules/> that have been defined by other plugins.

Also..

As a last note you can make your plugin available in the DOM by using either the <clobbers/> or <merges/> instead of run.

For example :

plugin.xml

<plugin id="cordova-plugin-bob-and-alice" version="0.0.1" xmlns="http://apache.org/cordova/ns/plugins/1.0" xmlns:android="http://schemas.android.com/apk/res/android">
    <js-module src="www/js/alice.js" name="alice">
        <clobbers target="alice"/>
    </js-module>
    <js-module src="www/js/bob.js" name="bob">
         <merges target="cordova.plugins"/>
    </js-module>
</plugin>

In which case you would be able to call both elements within your webview.

alice();
cordova.plugins.bob();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM