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

Modules are executed every time they're imported. #587

Closed
ry opened this issue Aug 24, 2018 · 5 comments · Fixed by #599
Closed

Modules are executed every time they're imported. #587

ry opened this issue Aug 24, 2018 · 5 comments · Fixed by #599
Labels
bug Something isn't working correctly
Milestone

Comments

@ry
Copy link
Member

ry commented Aug 24, 2018

They should be executed only once - their exports cached.

Node behavior

~/src/deno> cat test.js
require("./foo");
require("./foo");
~/src/deno> cat foo.js
console.log("HELLO");
~/src/deno> node test.js
HELLO
~/src/deno>

Current deno behavior

~/src/deno> cat test.ts
import "./foo.ts";
import "./foo.ts";
~/src/deno> cat foo.ts
console.log("HELLO");
~/src/deno> ./out/debug/deno test.ts
HELLO
HELLO
~/src/deno>
@ry ry added this to the v0.2 milestone Aug 24, 2018
@ry ry added the bug Something isn't working correctly label Aug 24, 2018
@satyarohith
Copy link
Member

Should we also warn them about duplication of imports?

@kitsonk
Copy link
Contributor

kitsonk commented Aug 24, 2018

No, duplication of imports can often happen, and be intentional, for example:

import * as foo from "./foo.ts";
import { bar } from "./foo.ts";

If it is valid TypeScript/JavaScript (which it is) there should be no warning.

@ry
Copy link
Member Author

ry commented Aug 24, 2018

@kitsonk Sure that's valid and there should be no warning - it's about how many times the top-level function is executed.
Try this:

~/src/deno> cat test.html
<script type="module">
  import { printHi } from './foo.js'
  import * as foo from './foo.js'

  foo.printHi();
  printHi();
</script>
~/src/deno> cat foo.js
export function printHi () {
  console.log("hi");
}

console.log("top-level");

When I open test.html in my browser I get

top-level
hi
hi

@ry
Copy link
Member Author

ry commented Aug 24, 2018

@kitsonk What do you think of this fix?

From 5061bf873f542a80a33db1a7c280d25bc4ca7a7f Mon Sep 17 00:00:00 2001
From: Ryan Dahl <ry@tinyclouds.org>
Date: Thu, 23 Aug 2018 22:29:07 -0400
Subject: [PATCH] Add failing test and potential fix for #587

---
 js/compiler.ts                               | 32 ++++++++++++++++------------
 tests/modules_should_be_executed_once.ts     |  2 ++
 tests/modules_should_be_executed_once.ts.out |  1 +
 tests/subdir/print_hello_on_import.ts        |  1 +
 4 files changed, 22 insertions(+), 14 deletions(-)
 create mode 100644 tests/modules_should_be_executed_once.ts
 create mode 100644 tests/modules_should_be_executed_once.ts.out
 create mode 100644 tests/subdir/print_hello_on_import.ts

diff --git a/js/compiler.ts b/js/compiler.ts
index fcbfc7c..c45a939 100644
--- a/js/compiler.ts
+++ b/js/compiler.ts
@@ -61,6 +61,7 @@ export class ModuleMetaData {
   public readonly exports = {};
   public scriptSnapshot?: ts.IScriptSnapshot;
   public scriptVersion = "";
+  public hasRun = false
 
   constructor(
     public readonly fileName: string,
@@ -401,21 +402,24 @@ export class DenoCompiler implements ts.LanguageServiceHost {
   ): ModuleMetaData {
     this._log("run", { moduleSpecifier, containingFile });
     const moduleMetaData = this.resolveModule(moduleSpecifier, containingFile);
-    const fileName = moduleMetaData.fileName;
-    this._scriptFileNames = [fileName];
-    const sourceCode = moduleMetaData.sourceCode;
-    let outputCode = moduleMetaData.outputCode;
-    if (!outputCode) {
-      outputCode = moduleMetaData.outputCode = `${this.compile(
-        fileName
-      )}\n//# sourceURL=${fileName}`;
-      moduleMetaData!.scriptVersion = "1";
-      this._os.codeCache(fileName, sourceCode, outputCode);
+    if (!moduleMetaData.hasRun) {
+      const fileName = moduleMetaData.fileName;
+      this._scriptFileNames = [fileName];
+      const sourceCode = moduleMetaData.sourceCode;
+      let outputCode = moduleMetaData.outputCode;
+      if (!outputCode) {
+        outputCode = moduleMetaData.outputCode = `${this.compile(
+          fileName
+        )}\n//# sourceURL=${fileName}`;
+        moduleMetaData.scriptVersion = "1";
+        this._os.codeCache(fileName, sourceCode, outputCode);
+      }
+      this._window.define = this.makeDefine(moduleMetaData);
+      this._globalEval(moduleMetaData.outputCode);
+      this._window.define = undefined;
+      moduleMetaData.hasRun = true;
     }
-    this._window.define = this.makeDefine(moduleMetaData);
-    this._globalEval(moduleMetaData.outputCode);
-    this._window.define = undefined;
-    return moduleMetaData!;
+    return moduleMetaData;
   }
 
   /**
diff --git a/tests/modules_should_be_executed_once.ts b/tests/modules_should_be_executed_once.ts
new file mode 100644
index 0000000..7b52ad5
--- /dev/null
+++ b/tests/modules_should_be_executed_once.ts
@@ -0,0 +1,2 @@
+import "./subdir/print_hello_on_import.ts";
+import "./subdir/print_hello_on_import.ts";
diff --git a/tests/modules_should_be_executed_once.ts.out b/tests/modules_should_be_executed_once.ts.out
new file mode 100644
index 0000000..e965047
--- /dev/null
+++ b/tests/modules_should_be_executed_once.ts.out
@@ -0,0 +1 @@
+Hello
diff --git a/tests/subdir/print_hello_on_import.ts b/tests/subdir/print_hello_on_import.ts
new file mode 100644
index 0000000..bf6b817
--- /dev/null
+++ b/tests/subdir/print_hello_on_import.ts
@@ -0,0 +1 @@
+console.log("Hello");
-- 
2.15.0

It doesn't quite work tho. Maybe you have a better way of doing this?

@kitsonk
Copy link
Contributor

kitsonk commented Aug 24, 2018

I am starting on #581 now, which should implicitly resolve this problem, because it will collect all the modules before it evals any of them, and will eval them in a dependency order. There maybe a need to track if they have been eval'ed, but I think it will be a more complete solution than just avoiding this one bug. I should be able to get a working PR today.

@ry ry closed this as completed in #599 Aug 28, 2018
hardfist pushed a commit to hardfist/deno that referenced this issue Aug 7, 2024
hardfist pushed a commit to hardfist/deno that referenced this issue Aug 7, 2024
This reverts commit 312cf8e.

This V8 upgrade causes some serious test failures in Deno: 

https://github.com/denoland/deno/actions/runs/7981611991/job/21793650383?pr=22505

This will require more work. I don't want to block others before the
Deno v1.41 release.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working correctly
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants