turbopack_browser/
react_refresh.rs1use anyhow::Result;
2use async_trait::async_trait;
3use turbo_rcstr::rcstr;
4use turbo_tasks::{ResolvedVc, Vc};
5use turbo_tasks_fs::FileSystemPath;
6use turbopack_core::{
7 issue::{Issue, IssueExt, IssueSeverity, IssueStage, StyledString},
8 reference_type::{CommonJsReferenceSubType, ReferenceType},
9 resolve::parse::Request,
10};
11use turbopack_resolve::{
12 ecmascript::apply_cjs_specific_options, resolve_options_context::ResolveOptionsContext,
13};
14
15#[turbo_tasks::function]
16fn react_refresh_request() -> Vc<Request> {
17 Request::parse_string(rcstr!("@next/react-refresh-utils/dist/runtime"))
18}
19
20#[turbo_tasks::function]
21fn react_refresh_request_in_next() -> Vc<Request> {
22 Request::parse_string(rcstr!(
23 "next/dist/compiled/@next/react-refresh-utils/dist/runtime"
24 ))
25}
26
27#[turbo_tasks::value]
28pub enum ResolveReactRefreshResult {
29 NotFound,
30 Found(ResolvedVc<Request>),
31}
32
33impl ResolveReactRefreshResult {
34 pub fn as_request(&self) -> Option<Vc<Request>> {
35 match self {
36 ResolveReactRefreshResult::NotFound => None,
37 ResolveReactRefreshResult::Found(r) => Some(**r),
38 }
39 }
40 pub fn is_found(&self) -> bool {
41 match self {
42 ResolveReactRefreshResult::NotFound => false,
43 ResolveReactRefreshResult::Found(_) => true,
44 }
45 }
46}
47
48#[turbo_tasks::function]
51pub async fn assert_can_resolve_react_refresh(
52 path: FileSystemPath,
53 resolve_options_context: Vc<ResolveOptionsContext>,
54) -> Result<Vc<ResolveReactRefreshResult>> {
55 let resolve_options = apply_cjs_specific_options(turbopack_resolve::resolve::resolve_options(
56 path.clone(),
57 resolve_options_context,
58 ));
59 for request in [react_refresh_request_in_next(), react_refresh_request()] {
60 let result = turbopack_core::resolve::resolve(
61 path.clone(),
62 ReferenceType::CommonJs(CommonJsReferenceSubType::Undefined),
63 request,
64 resolve_options,
65 )
66 .first_source();
67
68 if result.await?.is_some() {
69 return Ok(ResolveReactRefreshResult::Found(request.to_resolved().await?).cell());
70 }
71 }
72 ReactRefreshResolvingIssue { path }.resolved_cell().emit();
73 Ok(ResolveReactRefreshResult::NotFound.cell())
74}
75
76#[turbo_tasks::value(shared)]
78pub struct ReactRefreshResolvingIssue {
79 path: FileSystemPath,
80}
81
82#[async_trait]
83#[turbo_tasks::value_impl]
84impl Issue for ReactRefreshResolvingIssue {
85 fn severity(&self) -> IssueSeverity {
86 IssueSeverity::Warning
87 }
88
89 async fn title(&self) -> Result<StyledString> {
90 Ok(StyledString::Text(rcstr!(
91 "Could not resolve React Refresh runtime"
92 )))
93 }
94
95 fn stage(&self) -> IssueStage {
96 IssueStage::Resolve
97 }
98
99 async fn file_path(&self) -> Result<FileSystemPath> {
100 Ok(self.path.clone())
101 }
102
103 async fn description(&self) -> Result<Option<StyledString>> {
104 Ok(Some(StyledString::Line(vec![
105 StyledString::Text(rcstr!(
106 "React Refresh will be disabled.\nTo enable React Refresh, install the "
107 )),
108 StyledString::Code(rcstr!("react-refresh")),
109 StyledString::Text(rcstr!(" and ")),
110 StyledString::Code(rcstr!("@next/react-refresh-utils")),
111 StyledString::Text(rcstr!(" modules.")),
112 ])))
113 }
114}