vscode
vscode copied to clipboard
`require` of local files
Feature Request
Detailed Description
It would be useful to be able to require local *.[c]js files within playgrounds in the same way it's done in regular nodeJS scripts.
const myUtils = require("./utils.js");
Context
We're using this extension alongside a local docker image to handle dev databases, and the utility functions we've written are both a) getting a bit much for having inside the playground file, and b) would be useful in cases to share across playgrounds.
These utils are mostly useless to production, so including them there isn't ideal, and setting up the symlinks from our production code to a global node modules makes all of our code accessible, which we do not want. Splitting out a separate package exclusively for development helper functions is also extreme for a way to emulate native behavior.
I have tried using the path module to get the absolute path and require it dynamically, but as __dirname is not defined the only way that would be possible is a depth-first search of the entire filesystem, which is impractical and not guaranteed to find the correct file (or for some of the data-hoarders, not even guaranteed to complete one execution before lunch).
Possible Implementation
A basic implementation would look something like the following and would only support local files referenced via ./ or ../ at the start of the path. This transform would be applied before executing the script, and probably only to lines which actually require this behavior (pun intended).
// this code in the source of the MongoDB VSCode extension
import path from "node:path";
/**
* @param {string} file The absolute filepath to the `*.mongodb.js` file
* @param {string} content The line containing a `require` to parse
*/
function transformLocalRequires(file, content) {
const [requireExpression, requirePath] = content.match(/require\("(\.\.?\/.+?)"\)/);
if (!requireExpression) return content;
if (!requirePath) return content;
const absolutePath = path.resolve(path.dirname(file), requirePath);
return content.replace(requireExpression, `require("${absolutePath}")`);
}
// this code in a playgroud
const myUtil = require("./myUtil.js'); // correctly requires the local file
Not shown is iterating the file content and checking if the above transform is needed. Additionally, the above transform is proof of concept; it will, for example, modify a string literal which contains the textual content of a require call (eg, const foo = 'require("./gotcha.js")').
Non-Solutions
Define __dirname
If a solution is going to be provided, this is the worst one. Dynamically requiring is already an icky process in the cases where it is the best option, and in this case it would mean writing the dynamic lookup separately for every single playground. If a dynamic-ish require is going to be used, it should be authored once, centrally.
Define a Custom localRequire
The big problem with this solution is type information. The localRequire would be a playground global, like use or db, and would have no type information for it's return type (the required module). This issue doesn't exist for other playground globals, as the MongoDB extension provides intellisense itself, which is one of the major reasons for having type inference in JavaScript.
If it can be made to work with types however, I'm not against it. I just think it's going to be the same amount of effort as supporting the native require, which is definitely preferable to new custom syntax for emulating native behavior.
Thank you for opening the issue! We're going to track this in our internal JIRA tracker here: https://jira.mongodb.org/browse/VSCODE-468
@WillsterJohnson – we just added the ability to require local js files in the latest version of the extension (v1.6.0). This should allow you to write your utility functions once and reuse that across various Playground files. Would love to hear your feedback on if that resolves your issue.
@GaurabAryal thanks for bringing this live. Is it expected that console.log statements won't work from inside functions defined in the required file? print isn#t defined anyways, but console.log doesn't give any output.
Shall I create a bug report for this?