Modules in The Console – Take Two: Reload

The Console supports script prototyping which means you can edit a script and it will be automatically reloaded in The Console at the moment. But modules are different than single-file scripts. And this impacts script reloading, or rather module reloading.

Read on, GIFs included!

JS Environment

Every single tab consists of distinct JavaScript environment. You can observe that on this gif:

tabs_js_env

First, consider this situation: after some bunch of scripts and modules are loaded we decide to open a new tab. Since every single tab has distinct JS environment we need to load all scripts and modules into context of the new tab.

Scripts

What does it mean for supporting scripts? Every script has to be loaded for every tab. And that’s, actually, how it works right now.

For so called ScriptManager  every script is just a String. When new tab is created, this script is pushed to be evaluated inside JS engine. So, new tab doesn’t affect scripts in any way.

Modules

What to expect? Same thing – every module should be loaded for every tab.

Problems? No. OK, well, somehow. Modules are not loaded the same way as JS Scripts. Instead of evaluating a Java String, The Console gives Nashorn engine a path to the entry .js file of the module. Specifically, I use require() function described in previous article to load a module.

Script vs Module

Summarizing, script is loaded into Java String, while module is loaded inside JavaScript engine and through JavaScript engine. So, because every tab has it’s own JS context, modules need to be loaded inside JS environment, while simple scripts don’t have to.

Dynamic reload

Real issue comes with reloading stuff.

Single-file scripts are just evaluated as a whole file on command call. Second command call evaluates whole file again. And again, and again – every time. Between those command calls it’s easy to replace content of script.

A module, however, can implement some events like “onload”, “onunload” and have custom JS scope that lives in the engine until module is unloaded. There’s more – the module could require()  other modules. Or could be require()’d by other modules.

So, module reloading is a totally different story. If I’m going to reload modules, I have to do this inside JavaScript engine. And that means unloading is going to be a prelude of reload. And what if we do it muliple times? Load, unload, load, unload, load, then create new tab. All load/unload operations should be reduced to final result:

  1. Unload state means no loading
  2. Load state means loading a module

Current state

To properly manage all those loading and unloading of command scripts and modules (which could register commands) I’ll have to redesign code. Few things don’t make much sense, despite an attempt to press ahead without refactoring. Next post is going to treat about efforts on this little refactor.