Skip to content
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

Merged
merged 7 commits into from
Jul 18, 2022

Conversation

mstoykov
Copy link
Contributor

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:

  1. I will try to fix the lines for main modules(and not only) with no source maps and/or not going through babel.
  2. More polishing - I likely will want to refactor some of the code a bit more. Like getExports seems like of strangely out of place which I also noticed while working on ESM

@codebien
Copy link
Contributor

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.
Do we have cons in doing it (except if someone is using this directly as a feature)?

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.

@na-- na-- added this to the v0.40.0 milestone Jun 15, 2022
@mstoykov mstoykov force-pushed the wrapMainScriptAsWell branch from 36f9466 to b9bb3d0 Compare June 30, 2022 12:08
@mstoykov mstoykov marked this pull request as ready for review June 30, 2022 12:09
@mstoykov mstoykov force-pushed the wrapMainScriptAsWell branch from b9bb3d0 to da13b03 Compare June 30, 2022 12:14
@mstoykov
Copy link
Contributor Author

Given that this is clearly not what should've been happening - having access to another modules/script variables without importing it I think:

  1. there likely will be no one actually using it on purpose
  2. all the people who use it by accident likely will be better off finding out this was buggy and likely not what they intended.
  3. the major breaking change IMO is that options will now not be available if you haven't export let options = {} which to be honest was previously very strange behaviour. This is even less of an issue as the options are now available through k6/execution and actually have the correct values instead of having some correct values.

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.

@mstoykov mstoykov changed the base branch from optionsAreGlobal to master July 7, 2022 11:51
mstoykov added 2 commits July 13, 2022 17:44
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
@mstoykov mstoykov force-pushed the wrapMainScriptAsWell branch from da13b03 to 35146ca Compare July 13, 2022 14:49
Copy link
Contributor

@codebien codebien left a 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 Show resolved Hide resolved
js/bundle.go Outdated Show resolved Hide resolved
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()]
Copy link
Contributor

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?

Copy link
Contributor Author

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:

  1. know that there will be the key - otherwise we have some major bug
  2. 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.

Copy link
Member

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.

js/bundle.go Outdated Show resolved Hide resolved
js/bundle_test.go Outdated Show resolved Hide resolved
@mstoykov
Copy link
Contributor Author

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

codebien
codebien previously approved these changes Jul 14, 2022
olegbespalov
olegbespalov previously approved these changes Jul 14, 2022
Copy link
Contributor

@olegbespalov olegbespalov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@na-- na-- added the breaking change for PRs that need to be mentioned in the breaking changes section of the release notes label Jul 14, 2022
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
Copy link
Member

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?

Copy link
Contributor Author

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 🤷

Copy link
Contributor

@codebien codebien Jul 14, 2022

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.

Copy link
Member

@na-- na-- Jul 14, 2022

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

Copy link
Contributor Author

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.

Copy link
Contributor Author

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 🤷

Copy link
Member

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? 😕

Copy link
Member

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?

Copy link
Member

@na-- na-- Jul 15, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean this:

k6/js/bundle.go

Lines 297 to 299 in 6b77bfc

if err := jsOptionsObj.Set(key, val); err != nil {
instErr = err
}

Copy link
Contributor Author

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()]
Copy link
Member

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.

na--
na-- previously approved these changes Jul 15, 2022
Copy link
Member

@na-- na-- left a 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...

@mstoykov mstoykov dismissed stale reviews from na--, olegbespalov, and codebien via 7e289a5 July 18, 2022 07:28
Copy link
Contributor

@olegbespalov olegbespalov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaking change for PRs that need to be mentioned in the breaking changes section of the release notes
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants