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

Turbopack: more static typeof replacements for ESM #69914

Merged
merged 3 commits into from
Sep 10, 2024
Merged
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
5 changes: 3 additions & 2 deletions turbopack/crates/turbopack-ecmascript/src/analyzer/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use super::{
use crate::{
analyzer::{is_unresolved, WellKnownObjectKind},
utils::{unparen, AstPathRange},
SpecifiedModuleType,
};

#[derive(Debug, Clone)]
Expand Down Expand Up @@ -312,8 +313,8 @@ impl EvalContext {
}
}

pub fn is_esm(&self) -> bool {
self.imports.is_esm()
pub fn is_esm(&self, specified_type: SpecifiedModuleType) -> bool {
self.imports.is_esm(specified_type)
}

fn eval_prop_name(&self, prop: &PropName) -> JsValue {
Expand Down
15 changes: 12 additions & 3 deletions turbopack/crates/turbopack-ecmascript/src/analyzer/imports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ use turbo_tasks::{RcStr, Vc};
use turbopack_core::{issue::IssueSource, source::Source};

use super::{top_level_await::has_top_level_await, JsValue, ModuleValue};
use crate::tree_shake::{find_turbopack_part_id_in_asserts, PartId};
use crate::{
tree_shake::{find_turbopack_part_id_in_asserts, PartId},
SpecifiedModuleType,
};

#[turbo_tasks::value(serialization = "auto_for_input")]
#[derive(Default, Debug, Clone, Hash)]
Expand Down Expand Up @@ -209,8 +212,14 @@ pub(crate) struct ImportMapReference {
}

impl ImportMap {
pub fn is_esm(&self) -> bool {
self.has_exports || self.has_imports || self.has_top_level_await
pub fn is_esm(&self, specified_type: SpecifiedModuleType) -> bool {
match specified_type {
SpecifiedModuleType::Automatic => {
self.has_exports || self.has_imports || self.has_top_level_await
}
SpecifiedModuleType::CommonJs => false,
SpecifiedModuleType::EcmaScript => true,
}
Comment on lines +215 to +222
Copy link
Member

Choose a reason for hiding this comment

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

Moving this logic out of the callsite in lib.rs and references/mod.rs seems like a very good cleanup 👍, otherwise this API seems like a very subtle footgun (if you don't check SpecifiedModuleType, it will work 90% of the time until it doesn't).

}

pub fn get_import(&self, id: &Id) -> Option<JsValue> {
Expand Down
3 changes: 1 addition & 2 deletions turbopack/crates/turbopack-ecmascript/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -885,8 +885,7 @@ async fn gen_content_with_visitors(
Ok(EcmascriptModuleContent {
inner_code: bytes.into(),
source_map: Some(Vc::upcast(srcmap)),
is_esm: eval_context.is_esm()
|| specified_module_type == SpecifiedModuleType::EcmaScript,
is_esm: eval_context.is_esm(specified_module_type),
}
.cell())
}
Expand Down
26 changes: 18 additions & 8 deletions turbopack/crates/turbopack-ecmascript/src/references/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -491,23 +491,35 @@ pub(crate) async fn analyse_ecmascript_module_internal(
return analysis.build(false).await;
};

let compile_time_info = if (specified_type == SpecifiedModuleType::CommonJs)
|| (specified_type == SpecifiedModuleType::Automatic && !eval_context.is_esm())
{
let compile_time_info = {
let compile_time_info = raw_module.compile_time_info.await?;
let mut free_var_references = compile_time_info.free_var_references.await?.clone_value();

let (typeof_exports, typeof_module) = if eval_context.is_esm(specified_type) {
("undefined", "undefined")
} else {
("object", "object")
};

free_var_references
.entry(vec![
DefineableNameSegment::Name("exports".into()),
DefineableNameSegment::Name("import".into()),
DefineableNameSegment::Name("meta".into()),
DefineableNameSegment::TypeOf,
])
.or_insert("object".into());
free_var_references
.entry(vec![
DefineableNameSegment::Name("exports".into()),
DefineableNameSegment::TypeOf,
])
.or_insert(typeof_exports.into());
free_var_references
.entry(vec![
DefineableNameSegment::Name("module".into()),
DefineableNameSegment::TypeOf,
])
.or_insert("object".into());
.or_insert(typeof_module.into());
free_var_references
.entry(vec![
DefineableNameSegment::Name("require".into()),
Expand All @@ -521,8 +533,6 @@ pub(crate) async fn analyse_ecmascript_module_internal(
free_var_references: FreeVarReferences(free_var_references).cell(),
}
.cell()
} else {
raw_module.compile_time_info
};

let mut import_references = Vec::new();
Expand Down Expand Up @@ -844,7 +854,7 @@ pub(crate) async fn analyse_ecmascript_module_internal(
set_handler_and_globals(&handler, globals, || has_top_level_await(program));
let has_top_level_await = top_level_await_span.is_some();

if eval_context.is_esm() || specified_type == SpecifiedModuleType::EcmaScript {
if eval_context.is_esm(specified_type) {
let async_module = AsyncModule {
has_top_level_await,
import_externals,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
console.log("typeof require", typeof require)
console.log("typeof import.meta", typeof import.meta)
// CJS, should be `object`
console.log("typeof module", typeof module)
console.log("typeof exports", typeof exports)
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import './dep.js'

console.log("typeof require", typeof require)
console.log("typeof import.meta", typeof import.meta)
// ESM, should be `undefined`
console.log("typeof module", typeof module)
console.log("typeof exports", typeof exports)
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
console.log("typeof require", typeof require)
console.log("typeof import.meta", typeof import.meta)
// ESM, should be `undefined`
console.log("typeof module", typeof module)
console.log("typeof exports", typeof exports)
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import "./cjs.js"
import "./esm-automatic.js"
import "./esm-specified.mjs"
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
warning - [analysis] [project]/turbopack/crates/turbopack-tests/tests/snapshot/comptime/typeof/input/esm-specified.mjs Specified module format (EcmaScript Modules) is not matching the module format of the source code (CommonJs)
The EcmaScript module format was specified in the package.json that is affecting this source file or by using an special extension, but it looks like that CommonJs syntax is used in the source code.
Exports made by CommonJs syntax will lead to a runtime error, since the module is in EcmaScript mode. Either change the "type" field in the package.json or replace CommonJs syntax with EcmaScript import/export syntax in the source file.

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

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

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

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Loading