diff --git a/components/devtools/actor.rs b/components/devtools/actor.rs index 73a05bfe5f3..9ee43dcb13a 100644 --- a/components/devtools/actor.rs +++ b/components/devtools/actor.rs @@ -84,6 +84,8 @@ pub struct ActorRegistry { /// Lookup table for SourceActor names associated with a given PipelineId. source_actor_names: RefCell>>, + /// Lookup table for inline source content associated with a given PipelineId. + inline_source_content: RefCell>, shareable: Option>>, next: Cell, @@ -99,6 +101,7 @@ impl ActorRegistry { old_actors: RefCell::new(vec![]), script_actors: RefCell::new(HashMap::new()), source_actor_names: RefCell::new(HashMap::new()), + inline_source_content: RefCell::new(HashMap::new()), shareable: None, next: Cell::new(0), start_stamp: CrossProcessInstant::now(), @@ -262,4 +265,20 @@ impl ActorRegistry { vec![] } + + pub fn set_inline_source_content(&mut self, pipeline_id: PipelineId, content: String) { + assert!( + self.inline_source_content + .borrow_mut() + .insert(pipeline_id, content) + .is_none() + ); + } + + pub fn inline_source_content(&mut self, pipeline_id: PipelineId) -> Option { + self.inline_source_content + .borrow() + .get(&pipeline_id) + .cloned() + } } diff --git a/components/devtools/lib.rs b/components/devtools/lib.rs index 22594c9ddd8..03cba49a516 100644 --- a/components/devtools/lib.rs +++ b/components/devtools/lib.rs @@ -543,11 +543,14 @@ impl DevtoolsInstance { fn handle_create_source_actor(&mut self, pipeline_id: PipelineId, source_info: SourceInfo) { let mut actors = self.actors.lock().unwrap(); + let source_content = source_info + .content + .or_else(|| actors.inline_source_content(pipeline_id)); let source_actor = SourceActor::new_registered( &mut actors, pipeline_id, source_info.url, - source_info.content, + source_content, source_info.content_type, ); let source_actor_name = source_actor.name.clone(); @@ -613,6 +616,10 @@ impl DevtoolsInstance { source_actor.content = Some(source_content.clone()); } } + + // Store the source content separately for any future source actors that get created *after* we finish parsing + // the HTML. For example, adding an `import` to an inline module script can delay it until after parsing. + actors.set_inline_source_content(pipeline_id, source_content); } } diff --git a/python/servo/devtools_tests.py b/python/servo/devtools_tests.py index 8b3ebf0dbb9..825f52eb3b0 100644 --- a/python/servo/devtools_tests.py +++ b/python/servo/devtools_tests.py @@ -112,6 +112,14 @@ class DevtoolsTests(unittest.IsolatedAsyncioTestCase): expected_content = open(self.get_test_path("sources/test.html")).read() self.assert_source_content(f"{self.base_url}/test.html", expected_content) + def test_source_content_with_inline_module_import_external(self): + self.start_web_server(test_dir=self.get_test_path("sources_content_with_inline_module_import_external")) + self.run_servoshell() + expected_content = open( + self.get_test_path("sources_content_with_inline_module_import_external/test.html") + ).read() + self.assert_source_content(f"{self.base_urls[0]}/test.html", expected_content) + # Test case that uses innerHTML and would actually need the HTML parser # (innerHTML has a fast path for values that don’t contain b'&' | b'\0' | b'<' | b'\r') def test_source_content_inline_script_with_inner_html(self):