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