-
Notifications
You must be signed in to change notification settings - Fork 41
Kernel behaviour (known issues & workarounds)
Workarounds
- All top level variables are converted to
var
-
const
&let
variables are converted tovar
, hence read-write
-
- Use of top-level awaits in the cells will result in the code being altered
- Note, this isn't as bad as it sounds, this is precisely what node.js runtime does and this extension utilizes the exact same code
- With the exception of maintaining changes to the source maps (to get better error reporting & debugging)
- Value of the last
promise
expression displayed by awaiting on the promise- Unlike the traditional
node.js console
window, promises are displayed in the console window. - This extension will await on the promise and display the result instead.
- Unlike the traditional
- There's no concept of interrupts (due to a limitation in node.js runtime), instead the node.js process is killed.
Worthy mentions
- Imports are converted into commonjs
require
statements - Latest version of typeScript is bundled with the extension
- ts-node is bundled with the extension
- TypeScript compiler settings are harcoded
- TypeScript compiler warnings/errors are not displayed
Runtime
- All code is executed in a separate node process. Each notebook owns its own node process.
- The node process is spawned with debugging enabled by default (the assumption is there isn't any perf degradation in enabling this).
- Simple shell commands (such as pwd, ls, cp, etc) are executed in node, and more complex ones are executed in a real shell using node-pty.
- As we own the runtime execution, we can inject and intercept all modules. Thus when users import modules, we have the ability to alter some imports or inject some code (this is enables the rich integration with danfo.js, plotly and tensorflow.js).
let x = 'Hello;
const y = 'World';
var z = '1234';
All top level variables are converted into global variables. Thus variables x, y, z will be available in subsequent cells.
As top level const
is converted into a var
, these variables are now read-write.
The reason being one might want to run the following code multiple times (i.e. run the same cell over & over)
const y = 'World';
If it were a const
, node runtime would throw an error on subsequent executions.
As the notebook is deemed as a means of iterative development, all constants
are converted into var during run time.
Running code such as const result = await Promise.resolve(1324)
is not possible without some special handling. For instance Nodejs too doesn't support this out of the box (at least not in all versions of node.js).
In order to support top level awaits, the code is updated prior to execution. Nodejs runtime also makes simiar (almost identical) changes to support top level awaits in the Repl, see here for more info.
Just like a repl, the value of the last expression will be displayed in the output. E.g. in each of the following cases, the value of the last expression is displayed, just like a regular REPL:
var a = 111;
var b = 222;
c = a + b
or
var a = 111;
var b = 222;
var c = a + b
c
If the last expression evaluates to a promise, then the promise is awaited, and the result displayed in the cell.
const result = Promise.resolve(1234);
result
In the above case, the promise result
will be awaited upon and the value displayed in the output.
Unlike the node.js repl, the value promise
is not displayed, instead the kernel will await on the promise and display the result.
The code is updated prior to execution for two reasons:
- Support top level awaits As mentioned earlier, code needs to be altered prior to execution (just as node.js runtime also modifies the code under the hood)..
- Support breaking in exceptions (exception breakpoints)
For some reason breaking on exceptions requires user code (cells) to be wrapped within a
try..catch
& re-throwing of the errors. Without this, thebreak on exception
doesn't work in the debugger.
As code is updated for the above reasons, the source maps need to be re-adjusted. Though the source maps work, sometimes breakpoints might move around after the debugger starts, this is a known issue and will hopefully be addressed in a future version.
Once a cell has commenced execution, its not possible to interrupt the code and still maintain the state in the kernel. E.g. if you have a CPU bound code as follows:
var a = 1234;
var b = 999;
for (var i = 0; i < 1000000; i++){
// Perform some CPU bound operation...
console.log(i);
}
Hitting the stop button will not stop execution. The only way completely stop execution is to re-start the kernel using the toolbar icon.
At this stage the Stop
button on the cell does nothing, perhaps in the future it can be updated to just restart the kernel with a message.
This is due to a limitation in the node runtime.
If a cell contains an unused import, the typescript compiler will not generate code for these imports. Assume we have a cells as follows:
import * as fs from 'fs';
The typescript compiler is used to compile each cell individually, hence even if fs
variable is used subsequently, when using the typescript compiler, the import statement is not generated (unfortunately there's no way to preserve this in tsc).
The solution is for the extension to identify all imports and generate the commonjs compliant require statement and inject them at the top of the code that will be executed.
The goal is to ship the latest version of TyepScript with every release of this extension.
ts-node is shipped with the extension and enabled, so as to enable importing typescript modules without the user having to compile typescript into javascript.
At this stage all TypeScript compiler settings are hardcoded. The plan is to support user defined tsconfig files.
The compiler in the extension will not display any warnings or errors encountered during the compilation. I.e if there's invalid code in the cell, these errors will not prevent the cell from being executed. The expectation is the user will see rely on standard features of VS Code to look for errors in their JavaScript/TypeScript.
Home