-
Notifications
You must be signed in to change notification settings - Fork 18
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Example of Providing Custom Modules #4
Comments
Hey there, Thanks for your interest in this library! I'm currently working on extending the documentation (see pr #5). Here’s a basic overview of the two main options available, each targeting different use cases: Virtual File System OptionsThere are two separate virtual file systems: one for primitive Option One: Providing Custom Node ModulesYou can provide custom node modules, which can be used like regular node modules with In the runtime options, you can set import { quickJS } from '@sebastianwessel/quickjs'
import { readFileSync } from 'node:fs'
const { createRuntime } = await quickJS()
const { evalCode } = await createRuntime({
nodeModules: {
'my-package': readFileSync('host/path/file'),
},
})
await evalCode(`
import { myFunction } from 'my-package'
export default await myFunction()
`) Currently, handling relative imports within a package is not feasible. Therefore, you should convert the library you want to use into a single JavaScript file. You can use ESBuild or Bun for this purpose. Personally, I use Bun. Check out the repository, where you can find vendor.ts. This setup script builds the library testRunner.ts. You only need to run Option Two: Providing Custom Files for
|
There was a bug in custom module handling, which is fixed in version 1.1.0. An example can be found here An example can be found here |
@sebastianwessel I have a use case where I don’t know in advance what modules the user will import. So, I need to resolve them dynamically. This can be done here https://github.com/justjake/quickjs-emscripten?tab=readme-ov-file#async-module-loader because a callback is called and I can resolve the dependencies. Do I understand correctly that this cannot be done now? |
...but you should know which modules the sandbox can provide i general or? Why not providing them all? What is the reason to have this dynamically during sandbox execution? I do not really understand, why there is a need to have it dynamically during sandbox execution. ...but to answer your question: |
I am working on a low-code platform where users can write their own JavaScript functions and can also use npm dependencies. These dependencies will then be resolved dynamically through https://esm.sh/. I’m basically doing exactly what’s in this README. Except instead of using fs, I will make a fetch request to esm.sh.
So it would be sufficient if the setModuleLoader callback were exposed to me. |
Ah, ok, I see. Now I understand what you try to achieve. Generally, the import { quickJS } from '@sebastianwessel/quickjs'
const { createRuntime } = await quickJS()
const { evalCode, vm } = await createRuntime()
vm.context.runtime.setModuleLoader(....) But, currently, the created virtual file system is not exposed. In return { vm: arena, dispose, evalCode }; to return { vm: arena, dispose, evalCode, fs }; import { quickJS } from '@sebastianwessel/quickjs'
const { createRuntime } = await quickJS()
const { evalCode, vm, fs } = await createRuntime()
vm.context.runtime.setModuleLoader((moduleName) => {
const modulePath = path.join(importsPath, moduleName)
if (!modulePath.startsWith(importsPath)) {
throw new Error("out of bounds")
}
console.log("loading", moduleName, "from", modulePath)
// use the the fs returned by createRuntime, not the Node.js one for readFile
return fs.readFile(modulePath, "utf-8")
}, modulePathNormalizer)
const modulePathNormalizer: JSModuleNormalizer = (baseName: string, requestedName: string) => {
// relative import
if (requestedName.startsWith('.')) {
const parts = baseName.split('/')
parts.pop()
return resolve(`/${parts.join('/')}`, requestedName)
}
// module import
const moduleName = requestedName.replace('node:', '')
return join('/node_modules', moduleName)
} Created an issue #19 to improve this |
@sebastianwessel Cool, thanks 🙏. |
@petrbrzek version 1.3 is out. It returns So, it should make it a bit easier for you. |
Hello, thank you for the nice library with a great API. I have a question: how can I provide my own modules? I would like to achieve essentially what is described here: https://github.com/justjake/quickjs-emscripten?tab=readme-ov-file#async-module-loader. Thanks.
The text was updated successfully, but these errors were encountered: