/
source_map.rs
158 lines (142 loc) · 4.99 KB
/
source_map.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
use anyhow::Result;
use turbo_tasks::{primitives::StringVc, ValueToString, ValueToStringVc};
use turbo_tasks_fs::{File, FileSystemPathVc};
use turbo_tasks_hash::{encode_hex, Xxh3Hash64Hasher};
use turbopack_core::{
asset::{Asset, AssetContentVc, AssetVc},
chunk::ModuleIdVc,
code_builder::CodeVc,
reference::{AssetReference, AssetReferenceVc, AssetReferencesVc},
resolve::{ResolveResult, ResolveResultVc},
};
use super::{EcmascriptChunkItemVc, EcmascriptChunkVc};
/// Represents the source map of an ecmascript chunk.
#[turbo_tasks::value]
pub struct EcmascriptChunkSourceMapAsset {
chunk: EcmascriptChunkVc,
}
#[turbo_tasks::value_impl]
impl EcmascriptChunkSourceMapAssetVc {
#[turbo_tasks::function]
pub fn new(chunk: EcmascriptChunkVc) -> Self {
EcmascriptChunkSourceMapAsset { chunk }.cell()
}
}
#[turbo_tasks::value_impl]
impl Asset for EcmascriptChunkSourceMapAsset {
#[turbo_tasks::function]
async fn path(&self) -> Result<FileSystemPathVc> {
// NOTE(alexkirsz) We used to include the chunk's version id in the path,
// but this caused `all_assets_map` to be recomputed on every change.
Ok(self.chunk.path().append(".map"))
}
#[turbo_tasks::function]
async fn content(&self) -> Result<AssetContentVc> {
let sm = self.chunk.chunk_content().code().source_map().await?;
Ok(File::from(sm).into())
}
#[turbo_tasks::function]
fn references(&self) -> AssetReferencesVc {
AssetReferencesVc::empty()
}
}
/// Represents the source map of an ecmascript chunk item.
#[turbo_tasks::value]
pub struct EcmascriptChunkEntrySourceMapAsset {
chunk_path: FileSystemPathVc,
id: ModuleIdVc,
code: CodeVc,
}
#[turbo_tasks::value_impl]
impl EcmascriptChunkEntrySourceMapAssetVc {
#[turbo_tasks::function]
pub fn new(chunk_path: FileSystemPathVc, id: ModuleIdVc, code: CodeVc) -> Self {
EcmascriptChunkEntrySourceMapAsset {
chunk_path,
id,
code,
}
.cell()
}
}
#[turbo_tasks::value_impl]
impl Asset for EcmascriptChunkEntrySourceMapAsset {
#[turbo_tasks::function]
async fn path(&self) -> Result<FileSystemPathVc> {
// NOTE(alexkirsz) We used to asset's hash in the path, but this caused
// `all_assets_map` to be recomputed on every change.
let mut hasher = Xxh3Hash64Hasher::new();
hasher.write_value(self.id.await?);
let hash = encode_hex(hasher.finish());
let truncated_hash = &hash[..6];
Ok(self.chunk_path.append(&format!(".{}.map", truncated_hash)))
}
#[turbo_tasks::function]
async fn content(&self) -> Result<AssetContentVc> {
let sm = self.code.source_map().await?;
Ok(File::from(sm).into())
}
#[turbo_tasks::function]
fn references(&self) -> AssetReferencesVc {
AssetReferencesVc::empty()
}
}
/// A reference to a [`EcmascriptChunkSourceMapAsset`], used to inform the dev
/// server/build system of the presence of the source map
#[turbo_tasks::value]
pub struct EcmascriptChunkSourceMapAssetReference {
chunk: EcmascriptChunkVc,
hot_module_replacement: bool,
}
#[turbo_tasks::value_impl]
impl EcmascriptChunkSourceMapAssetReferenceVc {
#[turbo_tasks::function]
pub fn new(chunk: EcmascriptChunkVc, hot_module_replacement: bool) -> Self {
EcmascriptChunkSourceMapAssetReference {
chunk,
hot_module_replacement,
}
.cell()
}
}
#[turbo_tasks::value(serialization = "auto_for_input")]
#[derive(Debug, PartialOrd, Ord, Hash)]
struct EcmascriptChunkEntrySourceMapAssetCellKey(EcmascriptChunkItemVc);
#[turbo_tasks::value_impl]
impl AssetReference for EcmascriptChunkSourceMapAssetReference {
#[turbo_tasks::function]
async fn resolve_reference(&self) -> Result<ResolveResultVc> {
let path = self.chunk.path();
let mut source_maps = Vec::new();
source_maps.push(
EcmascriptChunkSourceMapAsset { chunk: self.chunk }
.cell()
.into(),
);
if self.hot_module_replacement {
// Expose a SourceMap for each chunk item when HMR is enabled
for item in &self.chunk.chunk_content().await?.module_factories {
source_maps.push(
EcmascriptChunkEntrySourceMapAsset {
chunk_path: path,
code: item.code_vc,
id: item.chunk_item.id(),
}
.keyed_cell(EcmascriptChunkEntrySourceMapAssetCellKey(item.chunk_item))
.into(),
);
}
}
Ok(ResolveResult::Alternatives(source_maps, vec![]).cell())
}
}
#[turbo_tasks::value_impl]
impl ValueToString for EcmascriptChunkSourceMapAssetReference {
#[turbo_tasks::function]
async fn to_string(&self) -> Result<StringVc> {
Ok(StringVc::cell(format!(
"source maps for {}",
self.chunk.path().to_string().await?
)))
}
}