puter icon indicating copy to clipboard operation
puter copied to clipboard

Add support for modules import in workers

Open reynaldichernando opened this issue 3 months ago • 9 comments

Right now, there is no way to import external modules in workers.

When trying to import something it shows this

import code example

import React from "https://esm.sh/react";

(importing via CDN here, since worker only support single file)

Image

Some ideas I thought:

  • Somehow support ESM module import
  • Enable upload worker as .mjs (?), since that error message specifically talks about worker not being in a module

Haven't tried yet:

  • Importing CommonJS with require

reynaldichernando avatar Oct 08 '25 13:10 reynaldichernando

Not sure how possible this is without a bundler but I don't think react in a worker makes sense in the first place really, isn't that a front end framework? Or is this some ssg thing

ProgrammerIn-wonderland avatar Oct 09 '25 03:10 ProgrammerIn-wonderland

actually, the react is just an example module, since that was what i copied from this ESM import via CDN https://esm.sh/

for my case I needed the xmldom lib (https://esm.sh/@xmldom/xmldom)

The point of the issue was to enable external module import 🙏

reynaldichernando avatar Oct 09 '25 04:10 reynaldichernando

i don't know if it can help, but i found this https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope/importScripts

reynaldichernando avatar Oct 09 '25 16:10 reynaldichernando

I'm not sure if this will work, probably not, but what happens if you do

const module = await import(someURL)

ProgrammerIn-wonderland avatar Oct 10 '25 07:10 ProgrammerIn-wonderland

dynamic imports might work

ProgrammerIn-wonderland avatar Oct 10 '25 07:10 ProgrammerIn-wonderland

sure, i'll try several variations and let you know

reynaldichernando avatar Oct 10 '25 16:10 reynaldichernando

update on this @ProgrammerIn-wonderland all the variations of trying to import, in this worker https://rey-import.puter.work

unfortunately none of them work

  • basic import esm fails, because worker is not inside a module
  • dynamic import via import() doesn't work, no such module
  • service worker importScripts() doesn't work, not defined
  • hack using fetch + eval, cannot run eval inside worker
  • esm hack, using data url for dynamic import, does not work, no such module
// import {nanoid} from "https://cdn.jsdelivr.net/npm/dayjs@1/+esm";
// above would cause the following error:
// Failed to deploy rey-import! Uncaught SyntaxError: Cannot use import statement outside a module at worker.js:1

router.get('/', () => {
    return "Endpoints:\n/esm\n/import-scripts\n/eval\n/esm-hack"
})

router.get('/esm', async ({request}) => {
    const {nanoid} = await import('https://cdn.jsdelivr.net/npm/dayjs@1/+esm');
    return 'esm';
});
router.get('/import-scripts', ({request}) => {
    importScripts("https://cdn.jsdelivr.net/npm/dayjs@1/dayjs.min.js");
    return 'importScripts';
});
router.get('/eval', async ({request, params}) => {
    const res = await fetch('https://cdn.jsdelivr.net/npm/dayjs@1/dayjs.min.js');
    const code = await res.text();
    (0, eval)(code); // run in global scope
    return 'eval';
});
router.get('/esm-hack', async ({request, params}) => {
    const mod = await import(
        'data:text/javascript,' +
        encodeURIComponent('export const echo = (m) => console.log("[echo]", m);')
    );

    mod.echo('hello from data: url');
    return 'esm-hack';
});

reynaldichernando avatar Nov 10 '25 11:11 reynaldichernando

knowing that our worker is built on top of cf workers, their solution for this is the packages must be bundled with the worker and it's doing something like wrangler deploy

personally i think this is annoying, and i wonder if we can just automatically detect cdn import, and build that into the worker

like if we are doing the following

import {nanoid} from "https://cdn.jsdelivr.net/npm/dayjs@1/+esm";

router.get('/esm', async ({request}) => {
    console.log(nanoid())
    return 'esm';
});

although i'm not sure how feasible this is, so i'll just hear what you think

reynaldichernando avatar Nov 10 '25 11:11 reynaldichernando

I'm unsure either, I'll probably need to look into this more deeply. If we have to webpack on every upload then we can no longer do it every save for performance reasons so it's one of those things which feels like walking on landmines

ProgrammerIn-wonderland avatar Nov 10 '25 12:11 ProgrammerIn-wonderland

if anyone's looking for how to import module in workers, for now you can follow this demo https://github.com/reynaldichernando/workers-import-demo/

basically, setup your worker as nodejs project, where you can import libraries as normally then build it using esbuild where it will bundle all your imported library into a single worker.js that you can use in puter

reynaldichernando avatar Dec 01 '25 04:12 reynaldichernando