Skip to content

Commit

Permalink
js: make certain only one copy of the exports is used per each module (
Browse files Browse the repository at this point in the history
…#2773)

This is inline with ESM and works for source code modules, but not for
modules written in go as the code was never made to work with it.

This also lets (as the test suggests) change what `k6/http`.get is
across the VU just as it should be possible.
  • Loading branch information
mstoykov authored Nov 23, 2022
1 parent 3f90d2c commit 2753196
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 6 deletions.
20 changes: 14 additions & 6 deletions js/initcontext.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,14 @@ type InitContext struct {
pwd *url.URL

// Cache of loaded programs and files.
programs map[string]programWithSource
programs map[string]programWithSource
exportsCache map[string]goja.Value

compatibilityMode lib.CompatibilityMode

logger logrus.FieldLogger

modules map[string]interface{}
moduleRegistry map[string]interface{}
}

// NewInitContext creates a new initcontext with the provided arguments
Expand All @@ -66,7 +67,8 @@ func NewInitContext(
programs: make(map[string]programWithSource),
compatibilityMode: compatMode,
logger: logger,
modules: getJSModules(),
moduleRegistry: getJSModules(),
exportsCache: make(map[string]goja.Value),
moduleVUImpl: &moduleVUImpl{
ctx: context.Background(),
runtime: rt,
Expand All @@ -92,14 +94,20 @@ func newBoundInitContext(base *InitContext, vuImpl *moduleVUImpl) *InitContext {

programs: programs,
compatibilityMode: base.compatibilityMode,
exportsCache: make(map[string]goja.Value),
logger: base.logger,
modules: base.modules,
moduleRegistry: base.moduleRegistry,
moduleVUImpl: vuImpl,
}
}

// Require is called when a module/file needs to be loaded by a script
func (i *InitContext) Require(arg string) goja.Value {
func (i *InitContext) Require(arg string) (export goja.Value) {
var ok bool
if export, ok = i.exportsCache[arg]; ok {
return export
}
defer func() { i.exportsCache[arg] = export }()
switch {
case arg == "k6", strings.HasPrefix(arg, "k6/"):
// Builtin or external modules ("k6", "k6/*", or "k6/x/*") are handled
Expand Down Expand Up @@ -144,7 +152,7 @@ func toESModuleExports(exp modules.Exports) interface{} {
}

func (i *InitContext) requireModule(name string) (goja.Value, error) {
mod, ok := i.modules[name]
mod, ok := i.moduleRegistry[name]
if !ok {
return nil, fmt.Errorf("unknown module: %s", name)
}
Expand Down
31 changes: 31 additions & 0 deletions js/initcontext_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -687,3 +687,34 @@ export default function () {
// likely settings in the transpilers
require.Equal(t, "cool is cool\n\tat webpack:///./test1.ts:2:4(2)\n\tat r (webpack:///./test1.ts:5:4(3))\n\tat file:///script.js:4:2(4)\n\tat native\n", exception.String())
}

func TestImportModificationsAreConsistentBetweenFiles(t *testing.T) {
t.Parallel()
logger := testutils.NewLogger(t)
fs := afero.NewMemMapFs()
require.NoError(t, afero.WriteFile(fs, "/notk6.js", []byte(`export default {group}; function group() {}`), 0o644))
require.NoError(t, afero.WriteFile(fs, "/instrument.js", []byte(`
import k6 from "k6";
k6.newKey = 5;
k6.group = 3;
import notk6 from "./notk6.js";
notk6.group = 3;
notk6.newKey = 5;
`), 0o644))

b, err := getSimpleBundle(t, "/script.js", `
import k6 from "k6";
import notk6 from "./notk6.js";
import "./instrument.js";
if (k6.newKey != 5) { throw "k6.newKey is wrong "+ k6.newKey}
if (k6.group != 3) { throw "k6.group is wrong "+ k6.group}
if (notk6.newKey != 5) { throw "notk6.newKey is wrong "+ notk6.newKey}
if (notk6.group != 3) { throw "notk6.group is wrong "+ notk6.group}
export default () => { throw "this shouldn't be ran" }
`, fs)
require.NoError(t, err, "bundle error")

_, err = b.Instantiate(logger, 0)
require.NoError(t, err)
}

0 comments on commit 2753196

Please sign in to comment.