-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support NeedData responses in SourceMap/SourceMapTrace ContentSources (…
…#3907) This implements a new `ContentSourceProcessor` trait and `WrappedContentSource` struct that allows our `ContentSource`s to register some processor to transform the eventual `ContentSourceContent` that an inner `ContentSource` returns. Yah, it's a bit of a mouthful with lots of very similar sounding names. Essentially, the old `SourceMapContentSource` and `NextSourceMapTraceContentSource` wrapped some inner `ContentSource`, and would request content from them, and process that content into a source map JSON or trace JSON. But, they didn't implement the `NeedData` response, so it only supported very primitive inner content sources. This PR extracts that knowledge into a single `WrappedContentSource`, which will recursively wrap every `ContentSourceResult` until we land on a fully resolved `ContentSourceResult::Result`. At that point, it hands off the work to a `WrappedGetContentSource`, which performs the processing on whatever content is returned by the inner `GetContentSourceContent`. If you can't tell yet, I'm making the description intentionally verbose to highlight just how similar our struct/trait names are. Fixes WEB-614
- Loading branch information
1 parent
9942db8
commit a6f9274
Showing
5 changed files
with
264 additions
and
79 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
122 changes: 122 additions & 0 deletions
122
crates/turbopack-dev-server/src/source/wrapping_source.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
use anyhow::Result; | ||
use turbo_tasks::Value; | ||
|
||
use super::{ | ||
ContentSource, ContentSourceContentVc, ContentSourceData, ContentSourceDataVaryVc, | ||
ContentSourceResult, ContentSourceResultVc, ContentSourceVc, GetContentSourceContent, | ||
GetContentSourceContentVc, NeededData, | ||
}; | ||
|
||
/// A ContentSourceProcessor handles the final processing of an eventual | ||
/// [ContentSourceContent]. | ||
/// | ||
/// Used in conjunction with [WrappedContentSource], this allows a | ||
/// [ContentSource] implementation to easily register a final process step over | ||
/// some inner ContentSource's fully resolved [ContentSourceResult] and | ||
/// [ContentSourceContent]. | ||
#[turbo_tasks::value_trait] | ||
pub trait ContentSourceProcessor { | ||
fn process(&self, content: ContentSourceContentVc) -> ContentSourceContentVc; | ||
} | ||
|
||
/// A ContentSourceProcessor allows a [ContentSource] implementation to easily | ||
/// register a final process step over some inner ContentSource's fully resolved | ||
/// [ContentSourceResult] and [ContentSourceContent] without having to manually | ||
/// implement the NeedData resolution algorithm. | ||
/// | ||
/// This is the first of 2 steps, implementing the wrapping of | ||
/// ContentSourceResult so that we can wrap the fully resolved result with our | ||
/// [WrappedGetContentSourceContent]. | ||
#[turbo_tasks::value] | ||
pub struct WrappedContentSource { | ||
inner: ContentSourceVc, | ||
processor: ContentSourceProcessorVc, | ||
} | ||
|
||
#[turbo_tasks::value_impl] | ||
impl WrappedContentSourceVc { | ||
#[turbo_tasks::function] | ||
pub async fn new(inner: ContentSourceVc, processor: ContentSourceProcessorVc) -> Self { | ||
WrappedContentSource { inner, processor }.cell() | ||
} | ||
} | ||
|
||
#[turbo_tasks::value_impl] | ||
impl ContentSource for WrappedContentSource { | ||
#[turbo_tasks::function] | ||
async fn get( | ||
&self, | ||
path: &str, | ||
data: Value<ContentSourceData>, | ||
) -> Result<ContentSourceResultVc> { | ||
let res = self.inner.get(path, data); | ||
|
||
Ok(match &*res.await? { | ||
ContentSourceResult::NotFound => res, | ||
ContentSourceResult::NeedData(needed) => { | ||
// If the inner source needs more data, then we need to wrap the resuming source | ||
// in a new wrapped processor. That way, whatever ContentSourceResult is | ||
// returned when we resume can itself be wrapped, or be wrapped with a | ||
// WrappedGetContentSourceContent. | ||
ContentSourceResultVc::need_data(Value::new(NeededData { | ||
source: WrappedContentSourceVc::new(needed.source, self.processor).into(), | ||
path: needed.path.clone(), | ||
vary: needed.vary.clone(), | ||
})) | ||
} | ||
ContentSourceResult::Result { | ||
get_content, | ||
specificity, | ||
} => { | ||
// If we landed on a result, then the resolution algorithm is complete. All | ||
// that's left is to wrap the result's GetContentSourceContent | ||
// with our own, so that we can process whatever content it | ||
// returns. | ||
ContentSourceResult::Result { | ||
specificity: *specificity, | ||
get_content: WrappedGetContentSourceContentVc::new( | ||
*get_content, | ||
self.processor, | ||
) | ||
.into(), | ||
} | ||
.cell() | ||
} | ||
}) | ||
} | ||
} | ||
|
||
/// A WrappedGetContentSourceContent simply wraps the get_content of a | ||
/// [ContentSourceResult], allowing us to process whatever | ||
/// [ContentSourceContent] it would have returned. | ||
/// | ||
/// This is the second of 2 steps, implementing the processing of | ||
/// ContentSourceContent. The first step in [WrappedContentSource] handles | ||
/// ContentSourceResult. | ||
#[turbo_tasks::value] | ||
struct WrappedGetContentSourceContent { | ||
inner: GetContentSourceContentVc, | ||
processor: ContentSourceProcessorVc, | ||
} | ||
|
||
#[turbo_tasks::value_impl] | ||
impl WrappedGetContentSourceContentVc { | ||
#[turbo_tasks::function] | ||
fn new(inner: GetContentSourceContentVc, processor: ContentSourceProcessorVc) -> Self { | ||
WrappedGetContentSourceContent { inner, processor }.cell() | ||
} | ||
} | ||
|
||
#[turbo_tasks::value_impl] | ||
impl GetContentSourceContent for WrappedGetContentSourceContent { | ||
#[turbo_tasks::function] | ||
fn vary(&self) -> ContentSourceDataVaryVc { | ||
self.inner.vary() | ||
} | ||
|
||
#[turbo_tasks::function] | ||
async fn get(&self, data: Value<ContentSourceData>) -> Result<ContentSourceContentVc> { | ||
let res = self.inner.get(data); | ||
Ok(self.processor.process(res)) | ||
} | ||
} |
Oops, something went wrong.