rspack_plugin_javascript/dependency/url/
mod.rs1use std::sync::Arc;
2
3use concat_string::concat_string;
4use rspack_cacheable::{cacheable, cacheable_dyn, with::AsPreset};
5use rspack_core::{
6 AsContextDependency, CodeGenerationPublicPathAutoReplace, ConnectionState, Dependency,
7 DependencyCategory, DependencyCodeGeneration, DependencyCondition, DependencyConditionFn,
8 DependencyId, DependencyRange, DependencyTemplate, DependencyTemplateType, DependencyType,
9 ExportsInfoArtifact, JavascriptParserUrl, ModuleDependency, ModuleGraph,
10 ModuleGraphCacheArtifact, ModuleGraphConnection, RuntimeGlobals, RuntimeSpec,
11 SideEffectsStateArtifact, TemplateContext, TemplateReplaceSource, URLStaticMode, UsedByExports,
12};
13
14use crate::{Atom, connection_active_used_by_exports, runtime::AUTO_PUBLIC_PATH_PLACEHOLDER};
15
16#[cacheable]
17#[derive(Debug)]
18pub struct URLDependency {
19 id: DependencyId,
20 #[cacheable(with=AsPreset)]
21 request: Atom,
22 range: DependencyRange,
23 range_url: DependencyRange,
24 used_by_exports: Option<Arc<UsedByExports>>,
25 mode: Option<JavascriptParserUrl>,
26}
27
28impl URLDependency {
29 pub fn new(
30 request: Atom,
31 range: DependencyRange,
32 range_url: DependencyRange,
33 mode: Option<JavascriptParserUrl>,
34 ) -> Self {
35 Self {
36 id: DependencyId::new(),
37 request,
38 range,
39 range_url,
40 used_by_exports: None,
41 mode,
42 }
43 }
44
45 pub fn set_used_by_exports(&mut self, used_by_exports: Option<Arc<UsedByExports>>) {
46 self.used_by_exports = used_by_exports;
47 }
48
49 pub fn used_by_exports(&self) -> Option<&UsedByExports> {
50 self.used_by_exports.as_deref()
51 }
52
53 pub fn replace_request(&self, source: &mut TemplateReplaceSource, request: String) {
56 source.replace(
57 self.range_url.start,
58 self.range_url.end,
59 concat_string!(request, ", import.meta.url"),
60 None,
61 );
62 }
63}
64
65#[cacheable_dyn]
66impl Dependency for URLDependency {
67 fn id(&self) -> &DependencyId {
68 &self.id
69 }
70
71 fn category(&self) -> &DependencyCategory {
72 &DependencyCategory::Url
73 }
74
75 fn dependency_type(&self) -> &DependencyType {
76 &DependencyType::NewUrl
77 }
78
79 fn url_mode(&self) -> Option<JavascriptParserUrl> {
80 self.mode
81 }
82
83 fn range(&self) -> Option<DependencyRange> {
84 Some(self.range)
85 }
86
87 fn could_affect_referencing_module(&self) -> rspack_core::AffectType {
88 rspack_core::AffectType::True
89 }
90}
91
92#[cacheable_dyn]
93impl ModuleDependency for URLDependency {
94 fn request(&self) -> &str {
95 &self.request
96 }
97
98 fn user_request(&self) -> &str {
99 &self.request
100 }
101
102 fn get_condition(&self) -> Option<DependencyCondition> {
103 Some(DependencyCondition::new(URLDependencyCondition))
104 }
105}
106
107#[cacheable_dyn]
108impl DependencyCodeGeneration for URLDependency {
109 fn dependency_template(&self) -> Option<DependencyTemplateType> {
110 Some(URLDependencyTemplate::template_type())
111 }
112}
113
114impl AsContextDependency for URLDependency {}
115
116#[cacheable]
117#[derive(Debug, Clone, Default)]
118pub struct URLDependencyTemplate;
119
120pub static URL_STATIC_PLACEHOLDER: &str = "RSPACK_AUTO_URL_STATIC_PLACEHOLDER_";
121
122impl URLDependencyTemplate {
123 pub fn template_type() -> DependencyTemplateType {
124 DependencyTemplateType::Dependency(DependencyType::NewUrl)
125 }
126}
127
128impl DependencyTemplate for URLDependencyTemplate {
129 fn render(
130 &self,
131 dep: &dyn DependencyCodeGeneration,
132 source: &mut TemplateReplaceSource,
133 code_generatable_context: &mut TemplateContext,
134 ) {
135 let dep = dep
136 .as_any()
137 .downcast_ref::<URLDependency>()
138 .expect("URLDependencyTemplate should be used for URLDependency");
139 let TemplateContext {
140 compilation,
141 runtime_template,
142 ..
143 } = code_generatable_context;
144
145 match dep.mode {
146 Some(JavascriptParserUrl::Relative) => {
147 source.replace(
148 dep.range.start,
149 dep.range.end,
150 format!(
151 "/* asset import */ new {}({}({}))",
152 runtime_template.render_runtime_globals(&RuntimeGlobals::RELATIVE_URL),
153 runtime_template.render_runtime_globals(&RuntimeGlobals::REQUIRE),
154 runtime_template.module_id(compilation, &dep.id, &dep.request, false),
155 ),
156 None,
157 );
158 }
159 Some(JavascriptParserUrl::NewUrlRelative) => {
160 code_generatable_context.data.insert(URLStaticMode);
161 code_generatable_context
162 .data
163 .insert(CodeGenerationPublicPathAutoReplace(true));
164 source.replace(
165 dep.range.start,
166 dep.range.end,
167 format!(
168 "new URL({}, import.meta.url)",
169 rspack_util::json_stringify_str(&format!(
170 "{AUTO_PUBLIC_PATH_PLACEHOLDER}{URL_STATIC_PLACEHOLDER}{}",
171 &dep.id.as_u32()
172 )),
173 ),
174 None,
175 );
176 }
177 _ => {
178 source.replace(
179 dep.range_url.start,
180 dep.range_url.end,
181 format!(
182 "/* asset import */{}({}), {}",
183 runtime_template.render_runtime_globals(&RuntimeGlobals::REQUIRE),
184 runtime_template.module_id(compilation, &dep.id, &dep.request, false),
185 runtime_template.render_runtime_globals(&RuntimeGlobals::BASE_URI)
186 ),
187 None,
188 );
189 }
190 }
191 }
192}
193
194struct URLDependencyCondition;
195
196impl DependencyConditionFn for URLDependencyCondition {
197 fn get_connection_state(
198 &self,
199 connection: &ModuleGraphConnection,
200 runtime: Option<&RuntimeSpec>,
201 module_graph: &ModuleGraph,
202 _module_graph_cache: &ModuleGraphCacheArtifact,
203 _side_effects_state_artifact: &SideEffectsStateArtifact,
204 exports_info_artifact: &ExportsInfoArtifact,
205 ) -> ConnectionState {
206 let dependency = module_graph.dependency_by_id(&connection.dependency_id);
207 let dependency = dependency
208 .downcast_ref::<URLDependency>()
209 .expect("should be URLDependency");
210 ConnectionState::Active(connection_active_used_by_exports(
211 connection,
212 runtime,
213 module_graph,
214 exports_info_artifact,
215 dependency.used_by_exports.as_deref(),
216 ))
217 }
218}