mirror of
https://github.com/servo/servo.git
synced 2025-06-06 16:45:39 +00:00
Unminify module scripts. (#34206)
* script: Unminify module scripts. Signed-off-by: Josh Matthews <josh@joshmatthews.net> * Fix clippy. Signed-off-by: Josh Matthews <josh@joshmatthews.net> --------- Signed-off-by: Josh Matthews <josh@joshmatthews.net>
This commit is contained in:
parent
672b37dd9c
commit
ae029242f8
9 changed files with 151 additions and 102 deletions
|
@ -66,6 +66,7 @@ impl DissimilarOriginWindow {
|
|||
global_to_clone_from.get_user_agent(),
|
||||
global_to_clone_from.wgpu_id_hub(),
|
||||
Some(global_to_clone_from.is_secure_context()),
|
||||
false,
|
||||
),
|
||||
window_proxy: Dom::from_ref(window_proxy),
|
||||
location: Default::default(),
|
||||
|
|
|
@ -143,6 +143,7 @@ use crate::task_source::{TaskSource, TaskSourceName};
|
|||
use crate::timers::{
|
||||
IsInterval, OneshotTimerCallback, OneshotTimerHandle, OneshotTimers, TimerCallback,
|
||||
};
|
||||
use crate::unminify::unminified_path;
|
||||
|
||||
#[derive(JSTraceable)]
|
||||
pub struct AutoCloseWorker {
|
||||
|
@ -356,6 +357,10 @@ pub struct GlobalScope {
|
|||
|
||||
/// Is considered in a secure context
|
||||
inherited_secure_context: Option<bool>,
|
||||
|
||||
/// Directory to store unminified scripts for this window if unminify-js
|
||||
/// opt is enabled.
|
||||
unminified_js_dir: Option<String>,
|
||||
}
|
||||
|
||||
/// A wrapper for glue-code between the ipc router and the event-loop.
|
||||
|
@ -764,6 +769,7 @@ impl GlobalScope {
|
|||
user_agent: Cow<'static, str>,
|
||||
gpu_id_hub: Arc<IdentityHub>,
|
||||
inherited_secure_context: Option<bool>,
|
||||
unminify_js: bool,
|
||||
) -> Self {
|
||||
Self {
|
||||
message_port_state: DomRefCell::new(MessagePortState::UnManaged),
|
||||
|
@ -805,6 +811,7 @@ impl GlobalScope {
|
|||
console_count_map: Default::default(),
|
||||
dynamic_modules: DomRefCell::new(DynamicModuleList::new()),
|
||||
inherited_secure_context,
|
||||
unminified_js_dir: unminify_js.then(|| unminified_path("unminified-js")),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3439,6 +3446,10 @@ impl GlobalScope {
|
|||
network_listener.into_callback(),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn unminified_js_dir(&self) -> Option<String> {
|
||||
self.unminified_js_dir.clone()
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the Rust global scope from a JS global object.
|
||||
|
|
|
@ -4,8 +4,7 @@
|
|||
#![allow(unused_imports)]
|
||||
use core::ffi::c_void;
|
||||
use std::cell::Cell;
|
||||
use std::fs::{create_dir_all, read_to_string, File};
|
||||
use std::io::{Read, Seek, Write};
|
||||
use std::fs::read_to_string;
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
use std::ptr;
|
||||
|
@ -70,9 +69,34 @@ use crate::script_runtime::CanGc;
|
|||
use crate::task::TaskCanceller;
|
||||
use crate::task_source::dom_manipulation::DOMManipulationTaskSource;
|
||||
use crate::task_source::{TaskSource, TaskSourceName};
|
||||
use crate::unminify::{
|
||||
create_output_file, create_temp_files, execute_js_beautify, BeautifyFileType,
|
||||
};
|
||||
use crate::unminify::{unminify_js, ScriptSource};
|
||||
|
||||
impl ScriptSource for ScriptOrigin {
|
||||
fn unminified_dir(&self) -> Option<String> {
|
||||
self.unminified_dir.clone()
|
||||
}
|
||||
|
||||
fn extract_bytes(&self) -> &[u8] {
|
||||
match &self.code {
|
||||
SourceCode::Text(text) => text.as_bytes(),
|
||||
SourceCode::Compiled(compiled_source_code) => {
|
||||
compiled_source_code.original_text.as_bytes()
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn rewrite_source(&mut self, source: Rc<DOMString>) {
|
||||
self.code = SourceCode::Text(source);
|
||||
}
|
||||
|
||||
fn url(&self) -> ServoUrl {
|
||||
self.url.clone()
|
||||
}
|
||||
|
||||
fn is_external(&self) -> bool {
|
||||
self.external
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Implement offthread compilation in mozjs
|
||||
/*pub struct OffThreadCompilationContext {
|
||||
|
@ -263,6 +287,7 @@ pub struct ScriptOrigin {
|
|||
external: bool,
|
||||
fetch_options: ScriptFetchOptions,
|
||||
type_: ScriptType,
|
||||
unminified_dir: Option<String>,
|
||||
}
|
||||
|
||||
impl ScriptOrigin {
|
||||
|
@ -271,6 +296,7 @@ impl ScriptOrigin {
|
|||
url: ServoUrl,
|
||||
fetch_options: ScriptFetchOptions,
|
||||
type_: ScriptType,
|
||||
unminified_dir: Option<String>,
|
||||
) -> ScriptOrigin {
|
||||
ScriptOrigin {
|
||||
code: SourceCode::Text(text),
|
||||
|
@ -278,6 +304,7 @@ impl ScriptOrigin {
|
|||
external: false,
|
||||
fetch_options,
|
||||
type_,
|
||||
unminified_dir,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -286,6 +313,7 @@ impl ScriptOrigin {
|
|||
url: ServoUrl,
|
||||
fetch_options: ScriptFetchOptions,
|
||||
type_: ScriptType,
|
||||
unminified_dir: Option<String>,
|
||||
) -> ScriptOrigin {
|
||||
ScriptOrigin {
|
||||
code: SourceCode::Text(text),
|
||||
|
@ -293,6 +321,7 @@ impl ScriptOrigin {
|
|||
external: true,
|
||||
fetch_options,
|
||||
type_,
|
||||
unminified_dir,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -471,6 +500,7 @@ impl FetchResponseListener for ClassicContext {
|
|||
final_url.clone(),
|
||||
self.fetch_options.clone(),
|
||||
ScriptType::Classic,
|
||||
elem.parser_document.global().unminified_js_dir(),
|
||||
);
|
||||
finish_fetching_a_classic_script(
|
||||
&elem,
|
||||
|
@ -813,6 +843,7 @@ impl HTMLScriptElement {
|
|||
base_url.clone(),
|
||||
options.clone(),
|
||||
script_type,
|
||||
self.global().unminified_js_dir(),
|
||||
));
|
||||
|
||||
// Step 27-2.
|
||||
|
@ -855,51 +886,6 @@ impl HTMLScriptElement {
|
|||
}
|
||||
}
|
||||
|
||||
fn unminify_js(&self, script: &mut ScriptOrigin) {
|
||||
if self.parser_document.window().unminified_js_dir().is_none() {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some((mut input, mut output)) = create_temp_files() {
|
||||
match &script.code {
|
||||
SourceCode::Text(text) => {
|
||||
input.write_all(text.as_bytes()).unwrap();
|
||||
},
|
||||
SourceCode::Compiled(compiled_source_code) => {
|
||||
input
|
||||
.write_all(compiled_source_code.original_text.as_bytes())
|
||||
.unwrap();
|
||||
},
|
||||
}
|
||||
|
||||
if execute_js_beautify(
|
||||
input.path(),
|
||||
output.try_clone().unwrap(),
|
||||
BeautifyFileType::Js,
|
||||
) {
|
||||
let mut script_content = String::new();
|
||||
output.seek(std::io::SeekFrom::Start(0)).unwrap();
|
||||
output.read_to_string(&mut script_content).unwrap();
|
||||
script.code = SourceCode::Text(Rc::new(DOMString::from(script_content)));
|
||||
}
|
||||
}
|
||||
|
||||
match create_output_file(
|
||||
window_from_node(self).unminified_js_dir(),
|
||||
&script.url,
|
||||
Some(script.external),
|
||||
) {
|
||||
Ok(mut file) => match &script.code {
|
||||
SourceCode::Text(text) => file.write_all(text.as_bytes()).unwrap(),
|
||||
SourceCode::Compiled(compiled_source_code) => {
|
||||
file.write_all(compiled_source_code.original_text.as_bytes())
|
||||
.unwrap();
|
||||
},
|
||||
},
|
||||
Err(why) => warn!("Could not store script {:?}", why),
|
||||
}
|
||||
}
|
||||
|
||||
fn substitute_with_local_script(&self, script: &mut ScriptOrigin) {
|
||||
if self
|
||||
.parser_document
|
||||
|
@ -948,7 +934,7 @@ impl HTMLScriptElement {
|
|||
};
|
||||
|
||||
if script.type_ == ScriptType::Classic {
|
||||
self.unminify_js(&mut script);
|
||||
unminify_js(&mut script);
|
||||
self.substitute_with_local_script(&mut script);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
use std::borrow::{Cow, ToOwned};
|
||||
use std::cell::{Cell, RefCell, RefMut};
|
||||
use std::cmp;
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::default::Default;
|
||||
|
@ -13,7 +14,6 @@ use std::rc::Rc;
|
|||
use std::sync::atomic::Ordering;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::Duration;
|
||||
use std::{cmp, env};
|
||||
|
||||
use app_units::Au;
|
||||
use backtrace::Backtrace;
|
||||
|
@ -154,6 +154,7 @@ use crate::script_thread::{
|
|||
use crate::task_manager::TaskManager;
|
||||
use crate::task_source::{TaskSource, TaskSourceName};
|
||||
use crate::timers::{IsInterval, TimerCallback};
|
||||
use crate::unminify::unminified_path;
|
||||
use crate::webdriver_handlers::jsval_to_webdriver;
|
||||
use crate::{fetch, window_named_properties};
|
||||
|
||||
|
@ -294,10 +295,6 @@ pub struct Window {
|
|||
/// available at some point in the future.
|
||||
pending_layout_images: DomRefCell<HashMapTracedValues<PendingImageId, Vec<Dom<Node>>>>,
|
||||
|
||||
/// Directory to store unminified scripts for this window if unminify-js
|
||||
/// opt is enabled.
|
||||
unminified_js_dir: DomRefCell<Option<String>>,
|
||||
|
||||
/// Directory to store unminified css for this window if unminify-css
|
||||
/// opt is enabled.
|
||||
unminified_css_dir: DomRefCell<Option<String>>,
|
||||
|
@ -332,9 +329,6 @@ pub struct Window {
|
|||
/// True if it is safe to write to the image.
|
||||
prepare_for_screenshot: bool,
|
||||
|
||||
/// Unminify Javascript.
|
||||
unminify_js: bool,
|
||||
|
||||
/// Unminify Css.
|
||||
unminify_css: bool,
|
||||
|
||||
|
@ -2259,13 +2253,9 @@ impl Window {
|
|||
assert!(document.window() == self);
|
||||
self.document.set(Some(document));
|
||||
|
||||
set_unminified_path(self.unminify_js, &self.unminified_js_dir, "unminified-js");
|
||||
|
||||
set_unminified_path(
|
||||
self.unminify_css,
|
||||
&self.unminified_css_dir,
|
||||
"unminified-css",
|
||||
);
|
||||
if self.unminify_css {
|
||||
*self.unminified_css_dir.borrow_mut() = Some(unminified_path("unminified-css"));
|
||||
}
|
||||
}
|
||||
|
||||
/// Commence a new URL load which will either replace this window or scroll to a fragment.
|
||||
|
@ -2528,10 +2518,6 @@ impl Window {
|
|||
self.throttled.get()
|
||||
}
|
||||
|
||||
pub fn unminified_js_dir(&self) -> Option<String> {
|
||||
self.unminified_js_dir.borrow().clone()
|
||||
}
|
||||
|
||||
pub fn unminified_css_dir(&self) -> Option<String> {
|
||||
self.unminified_css_dir.borrow().clone()
|
||||
}
|
||||
|
@ -2636,6 +2622,7 @@ impl Window {
|
|||
user_agent,
|
||||
gpu_id_hub,
|
||||
inherited_secure_context,
|
||||
unminify_js,
|
||||
),
|
||||
script_chan,
|
||||
task_manager,
|
||||
|
@ -2676,7 +2663,6 @@ impl Window {
|
|||
webgl_chan,
|
||||
webxr_registry,
|
||||
pending_layout_images: Default::default(),
|
||||
unminified_js_dir: Default::default(),
|
||||
unminified_css_dir: Default::default(),
|
||||
local_script_source,
|
||||
test_worklet: Default::default(),
|
||||
|
@ -2687,7 +2673,6 @@ impl Window {
|
|||
has_sent_idle_message: Cell::new(false),
|
||||
relayout_event,
|
||||
prepare_for_screenshot,
|
||||
unminify_js,
|
||||
unminify_css,
|
||||
userscripts_path,
|
||||
replace_surrogates,
|
||||
|
@ -2920,12 +2905,3 @@ fn is_named_element_with_name_attribute(elem: &Element) -> bool {
|
|||
fn is_named_element_with_id_attribute(elem: &Element) -> bool {
|
||||
elem.is_html_element()
|
||||
}
|
||||
|
||||
fn set_unminified_path(option: bool, dir_ref: &DomRefCell<Option<String>>, folder_name: &str) {
|
||||
if option {
|
||||
// Set a path for the document host to store unminified files.
|
||||
let mut path = env::current_dir().unwrap();
|
||||
path.push(folder_name);
|
||||
*dir_ref.borrow_mut() = Some(path.into_os_string().into_string().unwrap());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -166,6 +166,7 @@ impl WorkerGlobalScope {
|
|||
init.user_agent,
|
||||
gpu_id_hub,
|
||||
init.inherited_secure_context,
|
||||
false,
|
||||
),
|
||||
worker_id: init.worker_id,
|
||||
worker_name,
|
||||
|
|
|
@ -101,6 +101,7 @@ impl WorkletGlobalScope {
|
|||
init.user_agent.clone(),
|
||||
init.gpu_id_hub.clone(),
|
||||
init.inherited_secure_context,
|
||||
false,
|
||||
),
|
||||
base_url,
|
||||
to_script_thread_sender: init.to_script_thread_sender.clone(),
|
||||
|
|
|
@ -418,8 +418,37 @@ pub enum ModuleStatus {
|
|||
Finished,
|
||||
}
|
||||
|
||||
struct ModuleSource {
|
||||
source: Rc<DOMString>,
|
||||
unminified_dir: Option<String>,
|
||||
external: bool,
|
||||
url: ServoUrl,
|
||||
}
|
||||
|
||||
impl crate::unminify::ScriptSource for ModuleSource {
|
||||
fn unminified_dir(&self) -> Option<String> {
|
||||
self.unminified_dir.clone()
|
||||
}
|
||||
|
||||
fn extract_bytes(&self) -> &[u8] {
|
||||
self.source.as_bytes()
|
||||
}
|
||||
|
||||
fn rewrite_source(&mut self, source: Rc<DOMString>) {
|
||||
self.source = source;
|
||||
}
|
||||
|
||||
fn url(&self) -> ServoUrl {
|
||||
self.url.clone()
|
||||
}
|
||||
|
||||
fn is_external(&self) -> bool {
|
||||
self.external
|
||||
}
|
||||
}
|
||||
|
||||
impl ModuleTree {
|
||||
#[allow(unsafe_code)]
|
||||
#[allow(unsafe_code, clippy::too_many_arguments)]
|
||||
/// <https://html.spec.whatwg.org/multipage/#creating-a-module-script>
|
||||
/// Step 7-11.
|
||||
fn compile_module_script(
|
||||
|
@ -430,17 +459,25 @@ impl ModuleTree {
|
|||
url: &ServoUrl,
|
||||
options: ScriptFetchOptions,
|
||||
mut module_script: RustMutableHandleObject,
|
||||
inline: bool,
|
||||
) -> Result<(), RethrowError> {
|
||||
let cx = GlobalScope::get_cx();
|
||||
let _ac = JSAutoRealm::new(*cx, *global.reflector().get_jsobject());
|
||||
|
||||
let compile_options = unsafe { CompileOptionsWrapper::new(*cx, url.as_str(), 1) };
|
||||
let mut module_source = ModuleSource {
|
||||
source: module_script_text,
|
||||
unminified_dir: global.unminified_js_dir(),
|
||||
external: !inline,
|
||||
url: url.clone(),
|
||||
};
|
||||
crate::unminify::unminify_js(&mut module_source);
|
||||
|
||||
unsafe {
|
||||
module_script.set(CompileModule1(
|
||||
*cx,
|
||||
compile_options.ptr,
|
||||
&mut transform_str_to_source_text(&module_script_text),
|
||||
&mut transform_str_to_source_text(&module_source.source),
|
||||
));
|
||||
|
||||
if module_script.is_null() {
|
||||
|
@ -931,12 +968,14 @@ impl ModuleOwner {
|
|||
script_src.clone(),
|
||||
fetch_options,
|
||||
ScriptType::Module,
|
||||
global.unminified_js_dir(),
|
||||
)),
|
||||
ModuleIdentity::ScriptId(_) => Ok(ScriptOrigin::internal(
|
||||
Rc::clone(&module_tree.get_text().borrow()),
|
||||
document.base_url().clone(),
|
||||
fetch_options,
|
||||
ScriptType::Module,
|
||||
global.unminified_js_dir(),
|
||||
)),
|
||||
},
|
||||
}
|
||||
|
@ -1149,6 +1188,7 @@ impl FetchResponseListener for ModuleContext {
|
|||
meta.final_url,
|
||||
self.options.clone(),
|
||||
ScriptType::Module,
|
||||
global.unminified_js_dir(),
|
||||
))
|
||||
});
|
||||
|
||||
|
@ -1178,6 +1218,7 @@ impl FetchResponseListener for ModuleContext {
|
|||
&self.url,
|
||||
self.options.clone(),
|
||||
compiled_module.handle_mut(),
|
||||
false,
|
||||
);
|
||||
|
||||
match compiled_module_result {
|
||||
|
@ -1748,6 +1789,7 @@ pub(crate) fn fetch_inline_module_script(
|
|||
&url,
|
||||
options.clone(),
|
||||
compiled_module.handle_mut(),
|
||||
true,
|
||||
);
|
||||
|
||||
match compiled_module_result {
|
||||
|
|
|
@ -94,9 +94,9 @@ pub struct StylesheetContext {
|
|||
|
||||
impl StylesheetContext {
|
||||
fn unminify_css(&self, data: Vec<u8>, file_url: ServoUrl) -> Vec<u8> {
|
||||
if self.document.root().window().unminified_css_dir().is_none() {
|
||||
let Some(unminified_dir) = self.document.root().window().unminified_css_dir() else {
|
||||
return data;
|
||||
}
|
||||
};
|
||||
|
||||
let mut style_content = data;
|
||||
|
||||
|
@ -110,11 +110,7 @@ impl StylesheetContext {
|
|||
output.read_to_end(&mut style_content).unwrap();
|
||||
}
|
||||
}
|
||||
match create_output_file(
|
||||
self.document.root().window().unminified_css_dir(),
|
||||
&file_url,
|
||||
None,
|
||||
) {
|
||||
match create_output_file(unminified_dir, &file_url, None) {
|
||||
Ok(mut file) => {
|
||||
file.write_all(&style_content).unwrap();
|
||||
},
|
||||
|
|
|
@ -2,15 +2,27 @@
|
|||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use std::env;
|
||||
use std::fs::{create_dir_all, File};
|
||||
use std::io::{Error, ErrorKind};
|
||||
use std::io::{Error, Read, Seek, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
use std::rc::Rc;
|
||||
|
||||
use servo_url::ServoUrl;
|
||||
use tempfile::NamedTempFile;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::dom::bindings::str::DOMString;
|
||||
|
||||
pub(crate) trait ScriptSource {
|
||||
fn unminified_dir(&self) -> Option<String>;
|
||||
fn extract_bytes(&self) -> &[u8];
|
||||
fn rewrite_source(&mut self, source: Rc<DOMString>);
|
||||
fn url(&self) -> ServoUrl;
|
||||
fn is_external(&self) -> bool;
|
||||
}
|
||||
|
||||
pub fn create_temp_files() -> Option<(NamedTempFile, File)> {
|
||||
// Write the minified code to a temporary file and pass its path as an argument
|
||||
// to js-beautify to read from. Meanwhile, redirect the process' stdout into
|
||||
|
@ -53,20 +65,11 @@ pub fn execute_js_beautify(input: &Path, output: File, file_type: BeautifyFileTy
|
|||
}
|
||||
|
||||
pub fn create_output_file(
|
||||
unminified_dir: Option<String>,
|
||||
unminified_dir: String,
|
||||
url: &ServoUrl,
|
||||
external: Option<bool>,
|
||||
) -> Result<File, Error> {
|
||||
let path = match unminified_dir {
|
||||
Some(unminified_dir) => PathBuf::from(unminified_dir),
|
||||
None => {
|
||||
warn!("Unminified file directory not found");
|
||||
return Err(Error::new(
|
||||
ErrorKind::NotFound,
|
||||
"Unminified file directory not found",
|
||||
));
|
||||
},
|
||||
};
|
||||
let path = PathBuf::from(unminified_dir);
|
||||
|
||||
let (base, has_name) = match url.as_str().ends_with('/') {
|
||||
true => (
|
||||
|
@ -98,3 +101,35 @@ pub fn create_output_file(
|
|||
|
||||
File::create(path)
|
||||
}
|
||||
|
||||
pub(crate) fn unminify_js(script: &mut dyn ScriptSource) {
|
||||
let Some(unminified_dir) = script.unminified_dir() else {
|
||||
return;
|
||||
};
|
||||
|
||||
if let Some((mut input, mut output)) = create_temp_files() {
|
||||
input.write_all(script.extract_bytes()).unwrap();
|
||||
|
||||
if execute_js_beautify(
|
||||
input.path(),
|
||||
output.try_clone().unwrap(),
|
||||
BeautifyFileType::Js,
|
||||
) {
|
||||
let mut script_content = String::new();
|
||||
output.seek(std::io::SeekFrom::Start(0)).unwrap();
|
||||
output.read_to_string(&mut script_content).unwrap();
|
||||
script.rewrite_source(Rc::new(DOMString::from(script_content)));
|
||||
}
|
||||
}
|
||||
|
||||
match create_output_file(unminified_dir, &script.url(), Some(script.is_external())) {
|
||||
Ok(mut file) => file.write_all(script.extract_bytes()).unwrap(),
|
||||
Err(why) => warn!("Could not store script {:?}", why),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn unminified_path(dir: &str) -> String {
|
||||
let mut path = env::current_dir().unwrap();
|
||||
path.push(dir);
|
||||
path.into_os_string().into_string().unwrap()
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue