Skip to content
This repository was archived by the owner on Apr 2, 2026. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 29 additions & 1 deletion core/modules/map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1971,7 +1971,7 @@ impl ModuleMap {
.unwrap()
.clone();
match state.phase {
ModuleImportPhase::Defer | ModuleImportPhase::Evaluation => {
ModuleImportPhase::Evaluation => {
// The top-level module from a dynamic import has been instantiated.
// Load is done.
let module_id =
Expand All @@ -1987,6 +1987,34 @@ impl ModuleMap {
state,
)?;
}
ModuleImportPhase::Defer => {
// For defer phase imports, the module is instantiated but NOT evaluated.
// V8 will handle creating the deferred namespace object that triggers
// evaluation on first property access.
// Requires V8 flag --js-defer-import-eval (enabled in runtime/setup.rs).
let module_id =
load.root_module_id.expect("Root module should be loaded");
let result = self.instantiate_module(scope, module_id);
if let Err(exception) = result {
self.dynamic_import_reject(scope, dyn_import_id, exception);
continue;
}
// Resolve with the module namespace without evaluating.
// V8's deferred namespace will trigger evaluation on property access.
let module_handle =
self.get_handle(module_id).expect("ModuleInfo not found");
let module = module_handle.open(scope);
let module_namespace = module.get_module_namespace();
let resolver_handle = self
.dynamic_import_map
.borrow_mut()
.remove(&dyn_import_id)
.expect("Invalid dynamic import id")
.resolver;
let resolver = resolver_handle.open(scope);
resolver.resolve(scope, module_namespace).unwrap();
scope.perform_microtask_checkpoint();
}
ModuleImportPhase::Source => {
let module_reference = load.root_module_reference.as_ref().expect("Root module reference had to have been resolved to get here.");
let key = ModuleSourceKey::from_reference(module_reference);
Expand Down
3 changes: 2 additions & 1 deletion core/runtime/setup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ fn v8_init(
" --harmony-temporal",
" --js-float16array",
" --js-explicit-resource-management",
" --js-source-phase-imports"
" --js-source-phase-imports",
" --js-defer-import-eval"
);
let snapshot_flags = "--predictable --random-seed=42";
let expose_natives_flags = "--expose_gc --allow_natives_syntax";
Expand Down
6 changes: 6 additions & 0 deletions testing/integration/import_defer/deferred.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Copyright 2018-2025 the Deno authors. MIT license.
console.log("deferred module evaluated");
export const value = 42;
export function add(a, b) {
return a + b;
}
25 changes: 25 additions & 0 deletions testing/integration/import_defer/import_defer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright 2018-2025 the Deno authors. MIT license.

// Test for TC39 proposal: Deferred Module Evaluation
// https://github.com/tc39/proposal-defer-import-eval
//
// The `import defer` syntax allows loading a module without immediately
// executing it. The module is executed synchronously when any property
// on the namespace is first accessed.
//
console.log("before import defer");

// Static import defer syntax - module is loaded but not executed
import defer * as deferred from "./deferred.js";

console.log("after import defer, before access");

// First property access triggers module evaluation
console.log(`value: ${deferred.value}`);

console.log("after first access");

// Subsequent accesses use the already-evaluated module
console.log(`add: ${deferred.add(1, 2)}`);

console.log("done");
7 changes: 7 additions & 0 deletions testing/integration/import_defer/import_defer.out

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions testing/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ integration_test!(
dyn_import_op,
dyn_import_no_hang,
dyn_import_pending_tla,
import_defer,
error_async_stack,
error_callsite,
error_non_existent_eval_source,
Expand Down
Loading