Let's say I have a pure node.js file.js as the following:

const fs = require('fs')
console.log("Hello World")

If I execute it inside Vim with :%terminal node it works perfectly fine. I see the same results I'd see executing it from the command line with node file.js.

My problem starts with node.js modules. On node.js, modules are .mjs files. Let's say I have the following file.mjs code:

import fs from 'fs'
console.log('Hello World')

The way node.js differentiates a module from a normal file is by its file extension, js files are pure node.js and mjs files are modules. Both of them can be executed from the command line as isolated scripts with the commands node file.js and node file.mjs. However, if I try to execute this mjs file with :%terminal node inside Vim it gives me the error :

SyntaxError: Cannot use import statement outside module

That's exactly the same error I'd receive if I had renamed file.mjs to file.js and tried to execute it with node file.js. My assumption is that Vim sees it as a js file even though its extension is mjs...

When I run :echo &ft inside Vim it prints javascript for both mjs and js files. I'm not completely sure if what I want to do is possible. From the command line it works perfectly fine executing mjs files, but if I try executing them from Vim with the :terminal command, like :%terminal node, it fails. Does anyone have any idea of a workaround for this issue? In a way that allows me to execute node.js modules from inside Vim?

  • 1
    You would probably be better off with :terminal node %—the range version using the lines as input, while the argument version gives the file name to the node process
    – D. Ben Knoble
    Apr 10, 2022 at 16:50
  • @D.BenKnoble You're right, when I use :terminal node % it executes the mjs file properly. However, I lose the ability to select lines and execute only them doing that. That was an important feature for me... So, apparently the problem is that Vim creates a js file with the selected lines when I use the range version. Then when it tries to execute it it won't be seen as a module. I'm not sure if I can change this behavior with the range version... I'm considering creating a function that creates a temporary mjs file with the selected lines just for executing it with a second command.
    – raylight
    Apr 10, 2022 at 17:57
  • 1
    Not quite: :%terminal node runs node and passes each line in the buffer to the node REPL by giving the line to the process's input. You do have the module part right, but there's no extra files or anything, just stdin. You could create a temp file as you mentioned though.
    – D. Ben Knoble
    Apr 10, 2022 at 19:09
  • @D.BenKnoble Just as a curiosity that's not related to the question. But if Vim uses stdin to execute files when we use the %terminal node syntax. Does that mean that it'd be possible to continuously execute parts of the code inside the same terminal? So we can create something like a Jupyter notebook just using Vim?
    – raylight
    Apr 11, 2022 at 4:42
  • Anything seems possible :)
    – D. Ben Knoble
    Apr 11, 2022 at 13:41

1 Answer 1


As discussed in the comments, I ended up writing a function that writes the selection content inside a temporary file. My vimrc file is as the following now:

function! ExecuteOnTerminal(type) range
    if (expand("%:e")=='mjs') " check if extension of file is mjs
        if a:type == "V"
            '<,'>w! /tmp/file.mjs
            :w! /tmp/file.mjs
        :vert botright terminal node /tmp/file.mjs
    elseif (&ft=='javascript') " check if filetype is javascript
        if a:type == "V"
            :vert botright '<,'> %terminal node
            :vert botright %terminal node

vnoremap <silent> <F6> :call ExecuteOnTerminal("V")<CR>
nnoremap <silent> <F6> :call ExecuteOnTerminal("I")<CR>

Basically, I'm doing the following:

  1. Getting the extension of the file that's being executed with expand("%:e").
  2. If it's mjs file, I write a temporary file with the selected lines or the entire file.
  3. Executing this temporary file with :terminal node /tmp/file.mjs.
  4. In case it doesn't have the mjs extension and is a javascript file I execute it normally with :%terminal node.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.