-
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
Conversation
I agree we should act on this before we introduce the ESM. I'm not sure if applying a so important breaking change without any deprecation period is fine in terms of UX. Evaluating possible alternatives, do we have the option to keep the same current behaviour but with the addition of a print warning? So we could have this logic deprecated now and removed when the ESM will be introduced. |
36f9466
to
b9bb3d0
Compare
b9bb3d0
to
da13b03
Compare
Given that this is clearly not what should've been happening - having access to another modules/script variables without importing it I think:
Making any kind let's print something on this being abused will likely require quite a lot of code and I doubt it will have any effect -warnings are rarely being noticed unless they are obnoxious. We will be writing it in the release notes, but if we have to slow down the development for ESM on the off chance people are abusing this - I am against it. It is still likely that they will have this next release without native ESM support and only this change. |
This is also true for anything defined in the main module exported or not. It is just much easier to showcase with options particularly. This IMO should never have been the case and should be fixed. Additionally ESM in practice will "fix" this as modules all have their own scopes. So it makes sense to maybe break this before we add ESM support
da13b03
to
35146ca
Compare
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.
LGTM, just a suggestion
js/bundle.go
Outdated
@@ -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 comment
The 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 comment
The reason will be displayed to describe this comment to others. Learn more.
in all the places where access this we either:
- know that there will be the key - otherwise we have some major bug
- we do check that it is there and have something else to do
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 comment
The 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.
I will just squash this whole thing in the github interface at the end as I don't see why any of this should be in separate commits. If somebody wants something to remain as separate commits I am opened to it, it just doesn't seem necessary to me |
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.
👍
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 comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm it would be relatively easy to make this in a DynamicObject
that prints a warning if anyone tries to access any of the properties, right? 🤔 Telling people (with a sync.Once
, to limit spam) to use test.options
from k6/execution
for Get()
, Keys() and Has
() operations, and telling (with another sync.Once
) them that modifying the options
during the script runtime is useless and won't actually affect anything?
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 comment
The 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 comment
The reason will be displayed to describe this comment to others. Learn more.
When I tried during the test.options
implementation, there was an issue in the case of options exported as const
, where IIRC it isn't compatible with dynamic solutions.
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.
#2601 please comment/edit if I've missed something
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.
Hmm this in practice will not work ... all that well even with just this cchanges as we already can not change the original options
. This here only sets exports.options
in case they are empty.
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 options
is in hte scope of the module.
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.
Not really. In the case of commonjs transpiled by babel the actual code is something like
let options = {...}
exports.options = options;
// and then later it's accessed as `options`
options.scenario.....
In this case we can resset exports.options
but nothing will be using it. What we have done so far (and what this PR changes) is basically setting globalThis.options
which just so happens to be the same as having let options
in the global scope.
In ESM
export let options ={}
is more or less
let options = {}
export options;
And then we get access to options
and can set it's fields (just as before) but AFAIK there is no way to just change what options
is supposed to be.
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 comment
The reason will be displayed to describe this comment to others. Learn more.
Got it, I think... Then this whole logic of updating the script options
with the consolidated values won't work at all? 😕
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.
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 comment
The reason will be displayed to describe this comment to others. Learn more.
I mean this:
Lines 297 to 299 in 6b77bfc
if err := jsOptionsObj.Set(key, val); err != nil { | |
instErr = err | |
} |
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.
This should work for all varitants 🤔
js/bundle.go
Outdated
@@ -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()] |
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.
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.
LGTM except the comment nitpick. Though I have to say, the JS initialization code is getting more complicated instead of less, and with ESM I expect the problem will only become worse? So I'd love some cleanup and renaming of confusingly named objects (Runner especially) soon, since it's difficult to keep track how everything fits together...
7e289a5
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.
👍
This is the continuation of #2566 with a fix in which I wrap the main module the same way every other module.
This more or less gets us inline with what will be the behaviour once ESM lands from #2563.
As you can see I had to also change other tests as they make no sense once the main module doesn't just work in the global scope.
This still needs work if we decide to merge it:
getExports
seems like of strangely out of place which I also noticed while working on ESM