Skip to content

Commit 29276c1

Browse files
authored
Turbopack: properly replace __dirname and __filename (vercel#78843)
Replace `__dirname` and `__filename` references at compile time Our current approach of computing `__dirname` at runtime based on the module id is broken in production builds where numeric ids are used. Arguably it is incorrect in development builds as well as the value we produce is not actually usable as a path. We already compute a correct __dirname and __filename for our statically evaluated functions, so this uses the same approach which is to use the source path of the module. Closes PACK-4332
1 parent ea30af4 commit 29276c1

File tree

112 files changed

+341
-290
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

112 files changed

+341
-290
lines changed

turbopack/crates/turbopack-core/src/compile_time_info.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use anyhow::Result;
2+
use serde::{Deserialize, Serialize};
23
use turbo_rcstr::RcStr;
3-
use turbo_tasks::{FxIndexMap, ResolvedVc, Vc};
4+
use turbo_tasks::{trace::TraceRawVcs, FxIndexMap, NonLocalValue, ResolvedVc, Vc};
45
use turbo_tasks_fs::FileSystemPath;
56

67
use crate::environment::Environment;
@@ -200,6 +201,14 @@ impl CompileTimeDefines {
200201
}
201202
}
202203

204+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, TraceRawVcs, NonLocalValue)]
205+
pub enum InputRelativeConstant {
206+
// The project relative directory name of the source file
207+
DirName,
208+
// The project relative file name of the source file.
209+
FileName,
210+
}
211+
203212
#[turbo_tasks::value]
204213
#[derive(Debug, Clone)]
205214
pub enum FreeVarReference {
@@ -211,6 +220,7 @@ pub enum FreeVarReference {
211220
Ident(RcStr),
212221
Member(RcStr, RcStr),
213222
Value(CompileTimeDefineValue),
223+
InputRelative(InputRelativeConstant),
214224
Error(RcStr),
215225
}
216226

turbopack/crates/turbopack-ecmascript-runtime/js/src/browser/runtime/base/build-base.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -125,10 +125,6 @@ function instantiateModule(id: ModuleId, source: SourceInfo): Module {
125125
U: relativeURL,
126126
R: createResolvePathFromModule(r),
127127
b: getWorkerBlobURL,
128-
d:
129-
typeof module.id === 'string'
130-
? module.id.replace(/(^|\/)\/+$/, '')
131-
: module.id,
132128
})
133129
)
134130
} catch (error) {

turbopack/crates/turbopack-ecmascript-runtime/js/src/browser/runtime/base/dev-base.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ const getOrInstantiateModuleFromParent: GetOrInstantiateModuleFromParent<
129129
})
130130
}
131131

132-
function getDevWorkerBlobURL(chunks) {
132+
function getDevWorkerBlobURL(chunks: ChunkPath[]) {
133133
return getWorkerBlobURL(
134134
chunks,
135135
`// noop fns to prevent runtime errors during initialization
@@ -232,10 +232,6 @@ function instantiateModule(id: ModuleId, source: SourceInfo): Module {
232232
R: createResolvePathFromModule(r),
233233
b: getDevWorkerBlobURL,
234234
z: requireStub,
235-
d:
236-
typeof module.id === 'string'
237-
? module.id.replace(/(^|\/)\/+$/, '')
238-
: module.id,
239235
})
240236
)
241237
})

turbopack/crates/turbopack-ecmascript-runtime/js/src/nodejs/runtime.ts

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -295,10 +295,6 @@ function instantiateModule(
295295
R: createResolvePathFromModule(r),
296296
b: getWorkerBlobURL,
297297
z: requireStub,
298-
__dirname:
299-
typeof module.id === 'string'
300-
? module.id.replace(/(^|\/)\/+$/, '')
301-
: module.id,
302298
})
303299
} catch (error) {
304300
module.error = error as any

turbopack/crates/turbopack-ecmascript-runtime/js/src/shared/runtime-types.d.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,5 +112,4 @@ interface TurbopackBaseContext<M> {
112112
U: RelativeURL
113113
b: GetWorkerBlobURL
114114
z: CommonJsRequire
115-
d: string
116115
}

turbopack/crates/turbopack-ecmascript/src/analyzer/mod.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,20 @@ impl From<&FreeVarReference> for JsValue {
602602
FreeVarReference::Error(_) => {
603603
JsValue::unknown_empty(false, "compile time injected free var error")
604604
}
605+
FreeVarReference::InputRelative(kind) => {
606+
use turbopack_core::compile_time_info::InputRelativeConstant;
607+
JsValue::unknown_empty(
608+
false,
609+
match kind {
610+
InputRelativeConstant::DirName => {
611+
"compile time injected free var referencing the directory name"
612+
}
613+
InputRelativeConstant::FileName => {
614+
"compile time injected free var referencing the file name"
615+
}
616+
},
617+
)
618+
}
605619
}
606620
}
607621
}

turbopack/crates/turbopack-ecmascript/src/chunk/item.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,8 @@ impl EcmascriptChunkItemContent {
8787

8888
#[turbo_tasks::function]
8989
pub async fn module_factory(&self) -> Result<Vc<Code>> {
90-
let mut args = vec![
91-
"g: global",
92-
// HACK
93-
"__dirname",
94-
];
90+
// TODO(lukesandberg): find a better way to bind this parameter.
91+
let mut args = vec!["g: global"];
9592
if self.options.async_module.is_some() {
9693
args.push("a: __turbopack_async_module__");
9794
}

turbopack/crates/turbopack-ecmascript/src/references/mod.rs

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ use turbo_tasks_fs::FileSystemPath;
6060
use turbopack_core::{
6161
compile_time_info::{
6262
CompileTimeInfo, DefineableNameSegment, FreeVarReference, FreeVarReferences,
63-
FreeVarReferencesIndividual,
63+
FreeVarReferencesIndividual, InputRelativeConstant,
6464
},
6565
environment::Rendering,
6666
error::PrettyPrintError,
@@ -1495,6 +1495,32 @@ async fn compile_time_info_for_module_type(
14951495
.entry(vec![DefineableNameSegment::Name("require".into())])
14961496
.or_insert(require.into());
14971497

1498+
let dir_name: RcStr = "__dirname".into();
1499+
free_var_references
1500+
.entry(vec![
1501+
DefineableNameSegment::Name(dir_name.clone()),
1502+
DefineableNameSegment::TypeOf,
1503+
])
1504+
.or_insert("string".into());
1505+
free_var_references
1506+
.entry(vec![DefineableNameSegment::Name(dir_name)])
1507+
.or_insert(FreeVarReference::InputRelative(
1508+
InputRelativeConstant::DirName,
1509+
));
1510+
let file_name: RcStr = "__filename".into();
1511+
1512+
free_var_references
1513+
.entry(vec![
1514+
DefineableNameSegment::Name(file_name.clone()),
1515+
DefineableNameSegment::TypeOf,
1516+
])
1517+
.or_insert("string".into());
1518+
free_var_references
1519+
.entry(vec![DefineableNameSegment::Name(file_name)])
1520+
.or_insert(FreeVarReference::InputRelative(
1521+
InputRelativeConstant::FileName,
1522+
));
1523+
14981524
free_var_references.extend(TUBROPACK_RUNTIME_FUNCTION_SHORTCUTS.into_iter().map(
14991525
|(name, shortcut)| {
15001526
(
@@ -2508,7 +2534,6 @@ async fn handle_free_var_reference(
25082534
errors::failed_to_analyse::ecmascript::FREE_VAR_REFERENCE.to_string(),
25092535
),
25102536
),
2511-
25122537
FreeVarReference::Value(value) => {
25132538
analysis.add_code_gen(ConstantValueCodeGen::new(
25142539
Value::new(value.clone()),
@@ -2576,6 +2601,17 @@ async fn handle_free_var_reference(
25762601
ast_path.to_vec().into(),
25772602
));
25782603
}
2604+
FreeVarReference::InputRelative(kind) => {
2605+
let source_path = (*state.source).ident().path();
2606+
let source_path = match kind {
2607+
InputRelativeConstant::DirName => source_path.parent(),
2608+
InputRelativeConstant::FileName => source_path,
2609+
};
2610+
analysis.add_code_gen(ConstantValueCodeGen::new(
2611+
Value::new(as_abs_path(source_path).await?.into()),
2612+
ast_path.to_vec().into(),
2613+
));
2614+
}
25792615
}
25802616
Ok(true)
25812617
}
@@ -2774,7 +2810,7 @@ async fn analyze_amd_define_with_deps(
27742810

27752811
/// Used to generate the "root" path to a __filename/__dirname/import.meta.url
27762812
/// reference.
2777-
pub async fn as_abs_path(path: Vc<FileSystemPath>) -> Result<JsValue> {
2813+
pub async fn as_abs_path(path: Vc<FileSystemPath>) -> Result<String> {
27782814
// TODO: This should be updated to generate a real system path on the fly
27792815
// during runtime, so that the generated code is constant between systems
27802816
// but the runtime evaluation can take into account the project's
@@ -2783,8 +2819,8 @@ pub async fn as_abs_path(path: Vc<FileSystemPath>) -> Result<JsValue> {
27832819
}
27842820

27852821
/// Generates an absolute path usable for `require.resolve()` calls.
2786-
async fn require_resolve(path: Vc<FileSystemPath>) -> Result<JsValue> {
2787-
Ok(format!("/ROOT/{}", path.await?.path.as_str()).into())
2822+
async fn require_resolve(path: Vc<FileSystemPath>) -> Result<String> {
2823+
Ok(format!("/ROOT/{}", path.await?.path.as_str()))
27882824
}
27892825

27902826
async fn early_value_visitor(mut v: JsValue) -> Result<(JsValue, bool)> {
@@ -2908,8 +2944,8 @@ async fn value_visitor_inner(
29082944
}
29092945
}
29102946
JsValue::FreeVar(ref kind) => match &**kind {
2911-
"__dirname" => as_abs_path(origin.origin_path().parent()).await?,
2912-
"__filename" => as_abs_path(origin.origin_path()).await?,
2947+
"__dirname" => as_abs_path(origin.origin_path().parent()).await?.into(),
2948+
"__filename" => as_abs_path(origin.origin_path()).await?.into(),
29132949

29142950
"require" => JsValue::unknown_if(
29152951
ignore,
@@ -2971,7 +3007,11 @@ async fn require_resolve_visitor(
29713007
.primary_sources()
29723008
.await?
29733009
.iter()
2974-
.map(|&source| async move { require_resolve(source.ident().path()).await })
3010+
.map(|&source| async move {
3011+
require_resolve(source.ident().path())
3012+
.await
3013+
.map(JsValue::from)
3014+
})
29753015
.try_join()
29763016
.await?;
29773017

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
it('__dirname and __filename should be set', () => {
2-
expect(__dirname).toMatch(
3-
/^\[project\]\/.*\/code-gen\/dirname-filename\/input\/index\.js \[test\] \(ecmascript\)$/
2+
expect(__dirname).toEqual(
3+
'/ROOT/turbopack/crates/turbopack-tests/tests/execution/turbopack/code-gen/dirname-filename/input'
4+
)
5+
expect(__filename).toEqual(
6+
'/ROOT/turbopack/crates/turbopack-tests/tests/execution/turbopack/code-gen/dirname-filename/input/index.js'
47
)
5-
expect(__filename).toMatch(/dirname-filename\/output\/.*.js$/)
68
})

turbopack/crates/turbopack-tests/tests/snapshot/basic-tree-shake/dynamic-import/output/4c35f_tests_snapshot_basic-tree-shake_dynamic-import_input_index_92a5f455.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

turbopack/crates/turbopack-tests/tests/snapshot/basic-tree-shake/dynamic-import/output/4c35f_tests_snapshot_basic-tree-shake_dynamic-import_input_lib_b2d8c81e.js

Lines changed: 11 additions & 11 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

turbopack/crates/turbopack-tests/tests/snapshot/basic-tree-shake/dynamic-import/output/4c35f_tests_snapshot_basic-tree-shake_dynamic-import_input_lib_f6ff4167.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
"[project]/turbopack/crates/turbopack-tests/tests/snapshot/basic-tree-shake/dynamic-import/input/lib.js [test] (ecmascript, async loader)": ((__turbopack_context__) => {
44

5-
var { g: global, __dirname } = __turbopack_context__;
5+
var { g: global } = __turbopack_context__;
66
{
77
__turbopack_context__.v((parentImport) => {
88
return Promise.all([

0 commit comments

Comments
 (0)