Not the OP, but the approach sounds roughly similar to SE linux, but for node.

A major problem with a half-secure security solution is that it's not actually secure. You might do everything right, and still get owned. For the threat model the solution needs to be complete (or able to be complete, but turned down to less than complete by the user*).

Part of the way this manifests with SElinux is that to have a fully locked down box with SElinux you have to consider access controls for _everything_ on the box on top of regular unix permissions. And to actually be a full solution, you have to install kernel headers because anything user-space isn't good enough to guarantee full security.

For node to make a similar guarantee locking down everything means turning off a lot of the features that allow javascript to be so dynamic or making major changes to the run-time implementation to support being able to use those features without making the security swiss-cheese.

And then, even though the system is securable, there's the issue of turning it on for all the modules you use. And not just the module's you use, but the modules your modules use and on and on. You could delegate the module-module to the module you import but that means either granting overly broad permissions to the module and hoping they don't screw something up (and that any module they delegate to does the same) or not delegating anything and personally granting explicit permissions to every module, no matter how deep in your hierarchy of requirements. If that sounds exhausting, it kind of is.

In SElinux's case what that leads to instead usually is rearchitecting things such that you can use virtualization to sandbox things and limiting access across the sandboxes (ohai, it's the deno solution). There's still places where a VM or other sandbox isn't appropriate though and if you want to be on linux you have to use SElinux (or a competitor, but i've only touched selinux), and it's not uncommon to have an entire team whose only job is to configure SElinux and support other teams that interact with it (eg, coaching them on how SElinux interacts with their codebase and what they need to tune, auditing teams' SElinux configs, and keeping SElinux working for the base system as that gets upgraded). And if you screw up or get lazy with auditing permissions, you've just limited the effectiveness of SElinux, possibly rendering it useless.

A large part of the reason SElinux is so hard to use and use right (and that directly translates to js and node) is that it's attempting to bolt-on security to an existing system that wasn't designed with (that kind of) security in mind. That's a monumentally hard thing to do in a way that doesn't require rewriting everything that uses it. And not having to rewrite everything is a hard requirement, because if you're going to rewrite everything that uses it, it's usually cheaper and easier to just make something new from scratch (in SElinux's case a new OS, in js's case a new language).

So holistic options:
1) remove all the dynamism that makes javascript javascript. this (potentially) breaks all existing code. Call it rustscript and get that to ship in all the browsers, and get all the websites to use that instead of javascript, and then make a serverside environment for rustscript. Now you can do fine-grained module permissioning.
1.5) remove only the dynamism that breaks this sort of security access control as part of a new ECMAScript spec and add support for the security access control at the same time. This breaks existing code, but the old code can still run in a runtime for the earlier spec. New code can take advantage of the new spec features. Old code can be modified to work with the new features. Broken code can be rewritten to the new spec. This makes rustscript ESNext. It will be up to various runtime to support this new runtime, so nodeNext will have support for it but it won't get backported. Browsers will require transpilation from ESNext to an earlier ES version as they do now, but eventually even they would drop support for the older js versions.
2) accept that module permissioning systems are easy enough to get around in JS that anything attempting to implement them is at best security theater. The deno solution isn't security theater, but that's because it makes much less stringent guarantees (ie only runtime granularity and not module granularity).

* why allow the user to make themselves insecure? In some cases, the user will choose to be less secure for some external reason or will be using the security solution as a part of a more holistic security solution, so some other part guarantees the security that is given up.