-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
Contain main module within it's own scope as well #2571
Changes from 6 commits
e5941d5
35146ca
42bf5d6
3e52cb8
a614cfe
6b77bfc
7e289a5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
|
@@ -67,9 +67,9 @@ type BundleInstance struct { | |||||||
// TODO: maybe just have a reference to the Bundle? or save and pass rtOpts? | ||||||||
env map[string]string | ||||||||
|
||||||||
exports map[string]goja.Callable | ||||||||
|
||||||||
exports map[string]goja.Callable | ||||||||
moduleVUImpl *moduleVUImpl | ||||||||
pgm programWithSource | ||||||||
} | ||||||||
|
||||||||
// NewBundle creates a new bundle from a source file and a filesystem. | ||||||||
|
@@ -90,7 +90,7 @@ func NewBundle( | |||||||
Strict: true, | ||||||||
SourceMapLoader: generateSourceMapLoader(logger, filesystems), | ||||||||
} | ||||||||
pgm, _, err := c.Compile(code, src.URL.String(), true) | ||||||||
pgm, _, err := c.Compile(code, src.URL.String(), false) | ||||||||
if err != nil { | ||||||||
return nil, err | ||||||||
} | ||||||||
|
@@ -142,7 +142,7 @@ func NewBundleFromArchive( | |||||||
CompatibilityMode: compatMode, | ||||||||
SourceMapLoader: generateSourceMapLoader(logger, arc.Filesystems), | ||||||||
} | ||||||||
pgm, _, err := c.Compile(string(arc.Data), arc.FilenameURL.String(), true) | ||||||||
pgm, _, err := c.Compile(string(arc.Data), arc.FilenameURL.String(), false) | ||||||||
if err != nil { | ||||||||
return nil, err | ||||||||
} | ||||||||
|
@@ -208,7 +208,8 @@ func (b *Bundle) makeArchive() *lib.Archive { | |||||||
|
||||||||
// getExports validates and extracts exported objects | ||||||||
func (b *Bundle) getExports(logger logrus.FieldLogger, rt *goja.Runtime, options bool) error { | ||||||||
exportsV := rt.Get("exports") | ||||||||
pgm := b.BaseInitContext.programs[b.Filename.String()] | ||||||||
exportsV := pgm.module.Get("exports") | ||||||||
if goja.IsNull(exportsV) || goja.IsUndefined(exportsV) { | ||||||||
return errors.New("exports must be an object") | ||||||||
} | ||||||||
|
@@ -262,26 +263,31 @@ func (b *Bundle) Instantiate(logger logrus.FieldLogger, vuID uint64) (*BundleIns | |||||||
} | ||||||||
|
||||||||
rt := vuImpl.runtime | ||||||||
pgm := init.programs[b.Filename.String()] | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd suggest using a getter here instead of the map. For example, let's imagine there will be a case when nothing storing for the desired key, better in the case of stop execution, e.g., panic, whatever? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. in all the places where access this we either:
Given that I am going to be rewriting even more of this in #2563 or following PRs and this will just increase the amount of abstraction here. Especially not now. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fair enough, don't increase the abstraction, but this naked map lookup is giving me anxiety 😅 So at least add a few words of comment and/or a TODO here, that we are sure this index exists because of so and so, etc. |
||||||||
bi := &BundleInstance{ | ||||||||
Runtime: rt, | ||||||||
exports: make(map[string]goja.Callable), | ||||||||
env: b.RuntimeOptions.Env, | ||||||||
moduleVUImpl: vuImpl, | ||||||||
pgm: pgm, | ||||||||
} | ||||||||
|
||||||||
// Grab any exported functions that could be executed. These were | ||||||||
// already pre-validated in cmd.validateScenarioConfig(), just get them here. | ||||||||
exports := rt.Get("exports").ToObject(rt) | ||||||||
exports := pgm.module.Get("exports").ToObject(rt) | ||||||||
for k := range b.exports { | ||||||||
fn, _ := goja.AssertFunction(exports.Get(k)) | ||||||||
bi.exports[k] = fn | ||||||||
} | ||||||||
|
||||||||
jsOptions := rt.Get("options") | ||||||||
jsOptions := exports.Get("options") | ||||||||
var jsOptionsObj *goja.Object | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm it would be relatively easy to make this in a Not in this PR, of course, but should I open an issue about that? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it's possible - not certain how well it will play once we have ESM, but it should work 🤷 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When I tried during the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. #2601 please comment/edit if I've missed something There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm this in practice will not work ... all that well even with just this cchanges as we already can not change the original even before that again we were just setting something globally. This won't work with ESM as well as in that case just as now we don't have access to change waht There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not really. In the case of commonjs transpiled by babel the actual code is something like
In this case we can resset In ESM
is more or less
And then we get access to You can think of it as modules are supposed to encapsulate stuff so that the outside world can't mangle them and what you want is basically what modules are kind of trying to prevent. (They also prevent spilling stuff from inside modules in the global scope which is the other side of the coin - arguably the one that is more commonly cited) So it seems like this isn't really a thing we can do 🤷 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Got it, I think... Then this whole logic of updating the script There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Or maybe it will, since we're going item by item and updating individual keys of the object? 🤔 In which case, we might be able to add the usage warnings at the key level? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I mean this: Lines 297 to 299 in 6b77bfc
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should work for all varitants 🤔 |
||||||||
if jsOptions == nil || goja.IsNull(jsOptions) || goja.IsUndefined(jsOptions) { | ||||||||
jsOptionsObj = rt.NewObject() | ||||||||
rt.Set("options", jsOptionsObj) | ||||||||
err := exports.Set("options", jsOptionsObj) | ||||||||
if err != nil { | ||||||||
return nil, fmt.Errorf("couldn't set exported options with merged values: %w", err) | ||||||||
} | ||||||||
} else { | ||||||||
jsOptionsObj = jsOptions.ToObject(rt) | ||||||||
} | ||||||||
|
@@ -298,16 +304,23 @@ func (b *Bundle) Instantiate(logger logrus.FieldLogger, vuID uint64) (*BundleIns | |||||||
|
||||||||
// Instantiates the bundle into an existing runtime. Not public because it also messes with a bunch | ||||||||
// of other things, will potentially thrash data and makes a mess in it if the operation fails. | ||||||||
|
||||||||
func (b *Bundle) initializeProgramObject(rt *goja.Runtime, init *InitContext) programWithSource { | ||||||||
pgm := programWithSource{ | ||||||||
pgm: b.Program, | ||||||||
src: b.Source, | ||||||||
exports: rt.NewObject(), | ||||||||
module: rt.NewObject(), | ||||||||
} | ||||||||
_ = pgm.module.Set("exports", pgm.exports) | ||||||||
init.programs[b.Filename.String()] = pgm | ||||||||
return pgm | ||||||||
} | ||||||||
|
||||||||
func (b *Bundle) instantiate(logger logrus.FieldLogger, rt *goja.Runtime, init *InitContext, vuID uint64) (err error) { | ||||||||
rt.SetFieldNameMapper(common.FieldNameMapper{}) | ||||||||
rt.SetRandSource(common.NewRandSource()) | ||||||||
|
||||||||
exports := rt.NewObject() | ||||||||
rt.Set("exports", exports) | ||||||||
module := rt.NewObject() | ||||||||
_ = module.Set("exports", exports) | ||||||||
rt.Set("module", module) | ||||||||
|
||||||||
env := make(map[string]string, len(b.RuntimeOptions.Env)) | ||||||||
for key, value := range b.RuntimeOptions.Env { | ||||||||
env[key] = value | ||||||||
|
@@ -330,10 +343,21 @@ func (b *Bundle) instantiate(logger logrus.FieldLogger, rt *goja.Runtime, init * | |||||||
init.moduleVUImpl.ctx = context.Background() | ||||||||
init.moduleVUImpl.initEnv = initenv | ||||||||
init.moduleVUImpl.eventLoop = eventloop.New(init.moduleVUImpl) | ||||||||
pgm := b.initializeProgramObject(rt, init) | ||||||||
|
||||||||
err = common.RunWithPanicCatching(logger, rt, func() error { | ||||||||
return init.moduleVUImpl.eventLoop.Start(func() error { | ||||||||
_, errRun := rt.RunProgram(b.Program) | ||||||||
return errRun | ||||||||
f, errRun := rt.RunProgram(b.Program) | ||||||||
if errRun != nil { | ||||||||
return errRun | ||||||||
} | ||||||||
if call, ok := goja.AssertFunction(f); ok { | ||||||||
if _, errRun = call(pgm.exports, pgm.module, pgm.exports); errRun != nil { | ||||||||
return errRun | ||||||||
} | ||||||||
return nil | ||||||||
} | ||||||||
panic("Somehow a commonjs main module is not wrapped in a function") | ||||||||
}) | ||||||||
}) | ||||||||
|
||||||||
|
@@ -344,6 +368,12 @@ func (b *Bundle) instantiate(logger logrus.FieldLogger, rt *goja.Runtime, init * | |||||||
} | ||||||||
return err | ||||||||
} | ||||||||
exportsV := pgm.module.Get("exports") | ||||||||
if goja.IsNull(exportsV) { | ||||||||
return errors.New("exports must be an object") | ||||||||
} | ||||||||
pgm.exports = exportsV.ToObject(rt) | ||||||||
init.programs[b.Filename.String()] = pgm | ||||||||
unbindInit() | ||||||||
init.moduleVUImpl.ctx = nil | ||||||||
init.moduleVUImpl.initEnv = nil | ||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ugh, my other comment (#2571 (comment)) seems to be in a thread that's not visible in the diff anymore, so let me repeat it. Please add a comment and/or TODO here that explain why this is safe to do and how we can change it to not look so scary.