0 votes
by (120 points)

Twine2, Sugarcube2, tweego, vuejs.org

On importing Vuejs the following error occurs:

<<script>>
	importScripts('vue.min.js');
<</script>>

Cannot set property of 'Vue' of null

Vue lives in the window object. It probably misses the reference to the window object and thus cannot be set as a property.

What would be the proper way to include Vue, hopefully without modifying/hacking Sugarcube2?

1 Answer

+1 vote
by (68.6k points)
edited by

(On my phone, so this is going to suck)  I'm not in a position to look at this deeper, however, the error you're seeing is likely coming from elsewhere.

The importScripts() function works by creating a global script element within the document head for the given URL (i.e. it is evaluated globally).  The imported script should have no issues finding whatever it needs.

Your problem likely stems from:

  1. Calling importScripts() from a <<script>> macro.  It should be invoked within a script section.
  2. Not waiting for it to load before attempting to use it.  Loading a script from an external source is always an asynchronous operation, so you must wait for it to finish before you may use it.

Since you're using Tweego, I'd simply wrap Vue.js, to give it the environment it expects, and include it within the sources you feed to Tweego, so that it loads synchronously.  For example:

(function (define, exports) {

	/* LIBRARY GOES HERE */

}).call(window);

 

If you want to continue to load it asynchronously, then you'll need to delay your use of it until it's loaded.  One way to do this would be to use the Promise returned by the call to importScripts().

by (159k points)
edited by

For anyone (else) wondering what an example of using the Promise object returned by the importScripts() function after loading Vue from an external file could look like, the following is a simple demonstration.

This Javascript code should be placed either: a. if using TweeGo then within a script tagged passage; and b. if using Twine 2 application then within the Story Javascript area.

/* Import the Vue script. */
var promise = importScripts('https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.min.jss');

/* Output a message to console once the importScripts task has finished. */
promise
	.then(function () {
		console.log('The import was successful!');
		if (typeof window.Vue === "function") {
			console.log('\t...and the Vue global object exists.');
		}
	})
	.catch(function (reason) {
		console.log('The import failed!', reason);
	});

EDIT: Updated base on suggestion from TME, although I decided to still use a variable because I believe it makes the example easier to read due to the line length of the importScript() call. But as stated by TME the use of a variable to store the Promise is not needed.

by (68.6k points)

There's really no need for the variable here, simply chain off of the return value of the call.  Also, you're better off using the .catch() method than the second parameter of the .then() method, as the latter comes with limitations.

by (120 points)

Thank you, that works well! 

To clarify some things for others who want to apply this solution ...

If trying the snippet above and getting an 404 error: I myself could not reach the cloudflare CDN. The official URL for Vue is given in the snippet below.

Also, if using tweego, the file vue.min.js goes directly in the distribution directory, placed right next to the generated HTML file. And not in any source directory checked by tweego. If placed in any source directory checked by tweego, tweego will include it automatically and the error described in the initial post will occur.

 

::load-vue [script]

/* (A) place file in DIST directory, far away from tweego's reach */
var promise = importScripts('vue.min.js');

/* (B) or, load file over the internet, requires permanent internet access */
//var promise = importScripts('https://cdn.jsdelivr.net/npm/vue');

/* Output a message to console once the importScripts task has finished. */
promise
	.then(function () {
		console.log('The import was successful!');
		if (typeof window.Vue === "function") {
			console.log('\t...and the Vue global object exists.');
		}
	})
	.catch(function (reason) {
		console.log('The import failed!', reason);
	});

 

...