diff --git a/crates/rspack_core/src/dependency/dependency_type.rs b/crates/rspack_core/src/dependency/dependency_type.rs index f9cf8b42c7f..0dc2d29591b 100644 --- a/crates/rspack_core/src/dependency/dependency_type.rs +++ b/crates/rspack_core/src/dependency/dependency_type.rs @@ -37,6 +37,8 @@ pub enum DependencyType { NewUrl, // new Worker() NewWorker, + // create script url + CreateScriptUrl, // import.meta.webpackHot.accept ImportMetaHotAccept, // import.meta.webpackHot.decline @@ -118,6 +120,7 @@ impl DependencyType { DependencyType::CjsSelfReference => "cjs self exports reference", DependencyType::NewUrl => "new URL()", DependencyType::NewWorker => "new Worker()", + DependencyType::CreateScriptUrl => "create script url", DependencyType::ImportMetaHotAccept => "import.meta.webpackHot.accept", DependencyType::ImportMetaHotDecline => "import.meta.webpackHot.decline", DependencyType::ModuleHotAccept => "module.hot.accept", diff --git a/crates/rspack_plugin_devtool/src/eval_dev_tool_module_plugin.rs b/crates/rspack_plugin_devtool/src/eval_dev_tool_module_plugin.rs index 315b6d9ef7a..1f2877ba710 100644 --- a/crates/rspack_plugin_devtool/src/eval_dev_tool_module_plugin.rs +++ b/crates/rspack_plugin_devtool/src/eval_dev_tool_module_plugin.rs @@ -9,6 +9,7 @@ use rspack_core::{ ApplyContext, BoxModule, ChunkInitFragments, ChunkUkey, Compilation, CompilationParams, CompilerCompilation, CompilerOptions, Plugin, PluginContext, }; +use rspack_core::{CompilationAdditionalTreeRuntimeRequirements, RuntimeGlobals}; use rspack_error::Result; use rspack_hash::RspackHash; use rspack_hook::{plugin, plugin_hook}; @@ -83,6 +84,7 @@ async fn eval_devtool_plugin_compilation( hooks .inline_in_runtime_bailout .tap(eval_devtool_plugin_inline_in_runtime_bailout::new(self)); + Ok(()) } @@ -135,11 +137,16 @@ fn eval_devtool_plugin_render_module_content( .trim_start_matches('/') ) ); - // TODO: Implement support for the trustedTypes option. - // This will depend on the additionalModuleRuntimeRequirements hook. + + let module_content = + simd_json::to_string(&format!("{source}{footer}")).expect("failed to parse string"); RawSource::from(format!( "eval({});", - simd_json::to_string(&format!("{source}{footer}")).expect("failed to parse string") + if compilation.options.output.trusted_types.is_some() { + format!("{}({})", RuntimeGlobals::CREATE_SCRIPT, module_content) + } else { + module_content + } )) .boxed() }; @@ -183,10 +190,29 @@ impl Plugin for EvalDevToolModulePlugin { .compiler_hooks .compilation .tap(eval_devtool_plugin_compilation::new(self)); + ctx + .context + .compilation_hooks + .additional_tree_runtime_requirements + .tap(eval_devtool_plugin_additional_tree_runtime_requirements::new(self)); Ok(()) } } +#[plugin_hook(CompilationAdditionalTreeRuntimeRequirements for EvalDevToolModulePlugin)] +async fn eval_devtool_plugin_additional_tree_runtime_requirements( + &self, + compilation: &mut Compilation, + _chunk_ukey: &ChunkUkey, + runtime_requirements: &mut RuntimeGlobals, +) -> Result<()> { + if compilation.options.output.trusted_types.is_some() { + runtime_requirements.insert(RuntimeGlobals::CREATE_SCRIPT); + } + + Ok(()) +} + // https://tc39.es/ecma262/#sec-encode // UNESCAPED is combined by ALWAYS_UNESCAPED and ";/?:@&=+$,#" static UNESCAPED: LazyLock> = LazyLock::new(|| { diff --git a/crates/rspack_plugin_devtool/src/eval_source_map_dev_tool_plugin.rs b/crates/rspack_plugin_devtool/src/eval_source_map_dev_tool_plugin.rs index 51f9b3db6bd..6667e9cf665 100644 --- a/crates/rspack_plugin_devtool/src/eval_source_map_dev_tool_plugin.rs +++ b/crates/rspack_plugin_devtool/src/eval_source_map_dev_tool_plugin.rs @@ -5,8 +5,9 @@ use derivative::Derivative; use futures::future::join_all; use rspack_core::{ rspack_sources::{BoxSource, MapOptions, RawSource, Source, SourceExt}, - ApplyContext, BoxModule, ChunkInitFragments, ChunkUkey, Compilation, CompilationParams, - CompilerCompilation, CompilerOptions, ModuleIdentifier, Plugin, PluginContext, + ApplyContext, BoxModule, ChunkInitFragments, ChunkUkey, Compilation, + CompilationAdditionalTreeRuntimeRequirements, CompilationParams, CompilerCompilation, + CompilerOptions, ModuleIdentifier, Plugin, PluginContext, RuntimeGlobals, }; use rspack_error::Result; use rspack_hash::RspackHash; @@ -173,9 +174,15 @@ fn eval_source_map_devtool_plugin_render_module_content( let base64 = rspack_base64::encode_to_string(&map_buffer); let footer = format!("\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,{base64}"); + let module_content = + simd_json::to_string(&format!("{source}{footer}")).expect("should convert to string"); RawSource::from(format!( "eval({});", - simd_json::to_string(&format!("{source}{footer}")).expect("should convert to string") + if compilation.options.output.trusted_types.is_some() { + format!("{}({})", RuntimeGlobals::CREATE_SCRIPT, module_content) + } else { + module_content + } )) .boxed() }; @@ -205,6 +212,20 @@ fn eval_source_map_devtool_plugin_inline_in_runtime_bailout( Ok(Some("the eval-source-map devtool is used.".to_string())) } +#[plugin_hook(CompilationAdditionalTreeRuntimeRequirements for EvalSourceMapDevToolPlugin)] +async fn eval_source_map_devtool_plugin_additional_tree_runtime_requirements( + &self, + compilation: &mut Compilation, + _chunk_ukey: &ChunkUkey, + runtime_requirements: &mut RuntimeGlobals, +) -> Result<()> { + if compilation.options.output.trusted_types.is_some() { + runtime_requirements.insert(RuntimeGlobals::CREATE_SCRIPT); + } + + Ok(()) +} + #[async_trait::async_trait] impl Plugin for EvalSourceMapDevToolPlugin { fn name(&self) -> &'static str { @@ -221,6 +242,11 @@ impl Plugin for EvalSourceMapDevToolPlugin { .compiler_hooks .compilation .tap(eval_source_map_devtool_plugin_compilation::new(self)); + ctx + .context + .compilation_hooks + .additional_tree_runtime_requirements + .tap(eval_source_map_devtool_plugin_additional_tree_runtime_requirements::new(self)); Ok(()) } } diff --git a/crates/rspack_plugin_javascript/src/dependency/worker/create_script_url_dependency.rs b/crates/rspack_plugin_javascript/src/dependency/worker/create_script_url_dependency.rs new file mode 100644 index 00000000000..ad96495985f --- /dev/null +++ b/crates/rspack_plugin_javascript/src/dependency/worker/create_script_url_dependency.rs @@ -0,0 +1,78 @@ +use rspack_core::{ + AsContextDependency, AsModuleDependency, Compilation, Dependency, DependencyCategory, + DependencyId, DependencyTemplate, DependencyType, RealDependencyLocation, RuntimeGlobals, + RuntimeSpec, TemplateContext, TemplateReplaceSource, +}; + +#[derive(Debug, Clone)] +pub struct CreateScriptUrlDependency { + id: DependencyId, + range: RealDependencyLocation, + range_path: (u32, u32), +} + +impl CreateScriptUrlDependency { + pub fn new(range: RealDependencyLocation, range_path: (u32, u32)) -> Self { + Self { + id: DependencyId::new(), + range, + range_path, + } + } +} + +impl Dependency for CreateScriptUrlDependency { + fn id(&self) -> &DependencyId { + &self.id + } + + fn category(&self) -> &DependencyCategory { + &DependencyCategory::Worker + } + + fn dependency_type(&self) -> &DependencyType { + &DependencyType::CreateScriptUrl + } + + fn range(&self) -> Option<&RealDependencyLocation> { + Some(&self.range) + } + + fn could_affect_referencing_module(&self) -> rspack_core::AffectType { + rspack_core::AffectType::False + } +} + +impl DependencyTemplate for CreateScriptUrlDependency { + fn apply( + &self, + source: &mut TemplateReplaceSource, + code_generatable_context: &mut TemplateContext, + ) { + code_generatable_context + .runtime_requirements + .insert(RuntimeGlobals::CREATE_SCRIPT_URL); + + source.insert( + self.range_path.0, + format!("{}(", RuntimeGlobals::CREATE_SCRIPT_URL).as_str(), + None, + ); + source.insert(self.range_path.1, ")", None); + } + + fn dependency_id(&self) -> Option { + Some(self.id) + } + + fn update_hash( + &self, + _hasher: &mut dyn std::hash::Hasher, + _compilation: &Compilation, + _runtime: Option<&RuntimeSpec>, + ) { + } +} + +impl AsModuleDependency for CreateScriptUrlDependency {} +impl AsContextDependency for CreateScriptUrlDependency {} diff --git a/crates/rspack_plugin_javascript/src/dependency/worker/mod.rs b/crates/rspack_plugin_javascript/src/dependency/worker/mod.rs index f1b2a2bddd1..6763e61a220 100644 --- a/crates/rspack_plugin_javascript/src/dependency/worker/mod.rs +++ b/crates/rspack_plugin_javascript/src/dependency/worker/mod.rs @@ -1,3 +1,5 @@ +mod create_script_url_dependency; +pub use create_script_url_dependency::CreateScriptUrlDependency; use rspack_core::{ get_chunk_from_ukey, AsContextDependency, Compilation, Dependency, DependencyCategory, DependencyId, DependencyTemplate, DependencyType, ExtendedReferencedExport, ModuleDependency, diff --git a/crates/rspack_plugin_javascript/src/parser_plugin/worker_plugin.rs b/crates/rspack_plugin_javascript/src/parser_plugin/worker_plugin.rs index 9e4aa9dd958..4bc99daff2b 100644 --- a/crates/rspack_plugin_javascript/src/parser_plugin/worker_plugin.rs +++ b/crates/rspack_plugin_javascript/src/parser_plugin/worker_plugin.rs @@ -21,7 +21,7 @@ use super::{ JavascriptParserPlugin, }; use crate::{ - dependency::WorkerDependency, + dependency::{CreateScriptUrlDependency, WorkerDependency}, utils::object_properties::get_literal_str_by_obj_prop, visitors::{JavascriptParser, TagInfoData}, webpack_comment::try_extract_webpack_magic_comment, @@ -118,6 +118,16 @@ fn add_dependencies( }))); parser.blocks.push(Box::new(block)); + + if parser.compiler_options.output.trusted_types.is_some() { + parser + .dependencies + .push(Box::new(CreateScriptUrlDependency::new( + span.into(), + parsed_path.range, + ))); + } + if let Some(range) = range { parser .presentational_dependencies diff --git a/crates/rspack_plugin_runtime/src/runtime_module/create_script.rs b/crates/rspack_plugin_runtime/src/runtime_module/create_script.rs new file mode 100644 index 00000000000..90c92c52733 --- /dev/null +++ b/crates/rspack_plugin_runtime/src/runtime_module/create_script.rs @@ -0,0 +1,46 @@ +use rspack_collections::Identifier; +use rspack_core::{ + impl_runtime_module, + rspack_sources::{BoxSource, RawSource, SourceExt}, + Compilation, RuntimeGlobals, RuntimeModule, +}; + +#[impl_runtime_module] +#[derive(Debug)] +pub struct CreateScriptRuntimeModule { + id: Identifier, +} + +impl Default for CreateScriptRuntimeModule { + fn default() -> Self { + Self::with_default(Identifier::from("webpack/runtime/create_script")) + } +} + +impl RuntimeModule for CreateScriptRuntimeModule { + fn name(&self) -> Identifier { + self.id + } + + fn generate(&self, compilation: &Compilation) -> rspack_error::Result { + Ok( + RawSource::from(format!( + r#" + {} = function(script){{ + return {}; + }}; + "#, + RuntimeGlobals::CREATE_SCRIPT, + if compilation.options.output.trusted_types.is_some() { + format!( + "{}().createScript(script)", + RuntimeGlobals::GET_TRUSTED_TYPES_POLICY + ) + } else { + "script".to_string() + } + )) + .boxed(), + ) + } +} diff --git a/crates/rspack_plugin_runtime/src/runtime_module/mod.rs b/crates/rspack_plugin_runtime/src/runtime_module/mod.rs index 8d611b244f6..662b6e8052f 100644 --- a/crates/rspack_plugin_runtime/src/runtime_module/mod.rs +++ b/crates/rspack_plugin_runtime/src/runtime_module/mod.rs @@ -8,6 +8,7 @@ mod chunk_prefetch_trigger; mod chunk_preload_trigger; mod compat_get_default_export; mod create_fake_namespace_object; +mod create_script; mod create_script_url; mod define_property_getters; mod ensure_chunk; @@ -49,6 +50,7 @@ pub use chunk_prefetch_trigger::ChunkPrefetchTriggerRuntimeModule; pub use chunk_preload_trigger::ChunkPreloadTriggerRuntimeModule; pub use compat_get_default_export::CompatGetDefaultExportRuntimeModule; pub use create_fake_namespace_object::CreateFakeNamespaceObjectRuntimeModule; +pub use create_script::CreateScriptRuntimeModule; pub use create_script_url::CreateScriptUrlRuntimeModule; pub use define_property_getters::DefinePropertyGettersRuntimeModule; pub use ensure_chunk::EnsureChunkRuntimeModule; diff --git a/crates/rspack_plugin_runtime/src/runtime_plugin.rs b/crates/rspack_plugin_runtime/src/runtime_plugin.rs index 3a4bce9dead..e2c4441a6aa 100644 --- a/crates/rspack_plugin_runtime/src/runtime_plugin.rs +++ b/crates/rspack_plugin_runtime/src/runtime_plugin.rs @@ -18,13 +18,13 @@ use crate::runtime_module::{ chunk_has_css, is_enabled_for_chunk, AsyncRuntimeModule, AutoPublicPathRuntimeModule, BaseUriRuntimeModule, ChunkNameRuntimeModule, ChunkPrefetchPreloadFunctionRuntimeModule, CompatGetDefaultExportRuntimeModule, CreateFakeNamespaceObjectRuntimeModule, - CreateScriptUrlRuntimeModule, DefinePropertyGettersRuntimeModule, EnsureChunkRuntimeModule, - GetChunkFilenameRuntimeModule, GetChunkUpdateFilenameRuntimeModule, GetFullHashRuntimeModule, - GetMainFilenameRuntimeModule, GetTrustedTypesPolicyRuntimeModule, GlobalRuntimeModule, - HarmonyModuleDecoratorRuntimeModule, HasOwnPropertyRuntimeModule, LoadScriptRuntimeModule, - MakeNamespaceObjectRuntimeModule, NodeModuleDecoratorRuntimeModule, NonceRuntimeModule, - OnChunkLoadedRuntimeModule, PublicPathRuntimeModule, RelativeUrlRuntimeModule, - RuntimeIdRuntimeModule, SystemContextRuntimeModule, + CreateScriptRuntimeModule, CreateScriptUrlRuntimeModule, DefinePropertyGettersRuntimeModule, + EnsureChunkRuntimeModule, GetChunkFilenameRuntimeModule, GetChunkUpdateFilenameRuntimeModule, + GetFullHashRuntimeModule, GetMainFilenameRuntimeModule, GetTrustedTypesPolicyRuntimeModule, + GlobalRuntimeModule, HarmonyModuleDecoratorRuntimeModule, HasOwnPropertyRuntimeModule, + LoadScriptRuntimeModule, MakeNamespaceObjectRuntimeModule, NodeModuleDecoratorRuntimeModule, + NonceRuntimeModule, OnChunkLoadedRuntimeModule, PublicPathRuntimeModule, + RelativeUrlRuntimeModule, RuntimeIdRuntimeModule, SystemContextRuntimeModule, }; static GLOBALS_ON_REQUIRE: LazyLock> = LazyLock::new(|| { @@ -407,6 +407,9 @@ fn runtime_requirements_in_tree( compilation .add_runtime_module(chunk_ukey, CreateScriptUrlRuntimeModule::default().boxed())?; } + RuntimeGlobals::CREATE_SCRIPT => { + compilation.add_runtime_module(chunk_ukey, CreateScriptRuntimeModule::default().boxed())?; + } RuntimeGlobals::ON_CHUNKS_LOADED => { compilation .add_runtime_module(chunk_ukey, OnChunkLoadedRuntimeModule::default().boxed())?; diff --git a/packages/rspack-dev-server/tests/e2e/__snapshots__/overlay.test.js.snap.webpack5 b/packages/rspack-dev-server/tests/e2e/__snapshots__/overlay.test.js.snap.webpack5 index 80adb4be5bf..94441ff128a 100644 --- a/packages/rspack-dev-server/tests/e2e/__snapshots__/overlay.test.js.snap.webpack5 +++ b/packages/rspack-dev-server/tests/e2e/__snapshots__/overlay.test.js.snap.webpack5 @@ -516,6 +516,14 @@ exports[`overlay should not show initially, then show on an error, then show oth `; +exports[`overlay should not show overlay when Trusted Types are enabled, but policy is not allowed: page html 1`] = ` + +

webpack-dev-server is running...

+ + + +`; + exports[`overlay should show a warning after invalidation: overlay html 1`] = `
+
+
+ Compiled with problems: +
+ +
+
+
+ ERROR +
+
+ × Error: Error from compilation. Can't find 'test' module. │ at + Object.fn + (/tests/e2e/overlay.test.js::) + │ at SyncHook.callAsyncStageRange + (/node_modules/.pnpm/@rspack+lite-tapable@1.0.0/node_modules/@rspack/lite-tapable/dist/index.js::) + │ at SyncHook.callStageRange + (/node_modules/.pnpm/@rspack+lite-tapable@1.0.0/node_modules/@rspack/lite-tapable/dist/index.js::) + │ at QueriedHook.call + (/node_modules/.pnpm/@rspack+lite-tapable@1.0.0/node_modules/@rspack/lite-tapable/dist/index.js::) + │ at + /packages/rspack/dist/Compiler.js:: + │ at last.function + (/packages/rspack/dist/Compiler.js::) +
+
+
+
+ + +`; + +exports[`overlay should show overlay when Trusted Types are enabled and the "require-trusted-types-for 'script'" header was used: page html 1`] = ` + +

webpack-dev-server is running...

+ + + + + +`; + +exports[`overlay should show overlay when Trusted Types are enabled: overlay html 1`] = ` + +
+
+ Compiled with problems: +
+ +
+
+
+ ERROR +
+
+ × Error: Error from compilation. Can't find 'test' module. │ at + Object.fn + (/tests/e2e/overlay.test.js::) + │ at SyncHook.callAsyncStageRange + (/node_modules/.pnpm/@rspack+lite-tapable@1.0.0/node_modules/@rspack/lite-tapable/dist/index.js::) + │ at SyncHook.callStageRange + (/node_modules/.pnpm/@rspack+lite-tapable@1.0.0/node_modules/@rspack/lite-tapable/dist/index.js::) + │ at QueriedHook.call + (/node_modules/.pnpm/@rspack+lite-tapable@1.0.0/node_modules/@rspack/lite-tapable/dist/index.js::) + │ at + /packages/rspack/dist/Compiler.js:: + │ at last.function + (/packages/rspack/dist/Compiler.js::) +
+
+
+
+ + +`; + +exports[`overlay should show overlay when Trusted Types are enabled: page html 1`] = ` + +

webpack-dev-server is running...

+ + + + + +`; + exports[`overlay should show warning when it is not filtered: overlay html 1`] = `
{ } }); - // it("should show overlay when Trusted Types are enabled", async () => { - // const compiler = webpack(trustedTypesConfig); - - // new ErrorPlugin().apply(compiler); - - // const devServerOptions = { - // port, - // client: { - // overlay: { - // trustedTypesPolicyName: "webpack#dev-overlay", - // }, - // }, - // }; - // const server = new Server(devServerOptions, compiler); - - // await server.start(); - - // const { page, browser } = await runBrowser(); - - // try { - // const consoleMessages = []; - - // page.on("console", (message) => { - // consoleMessages.push(message.text()); - // }); - - // await page.goto(`http://localhost:${port}/`, { - // waitUntil: "networkidle0", - // }); - - // // Delay for the overlay to appear - // await delay(1000); - - // const pageHtml = await page.evaluate(() => document.body.outerHTML); - // const overlayHandle = await page.$("#webpack-dev-server-client-overlay"); - // const overlayFrame = await overlayHandle.contentFrame(); - // const overlayHtml = await overlayFrame.evaluate( - // () => document.body.outerHTML, - // ); - - // expect( - // consoleMessages.filter((item) => - // /requires 'TrustedHTML' assignment/.test(item), - // ), - // ).toHaveLength(0); - // expect( - // await prettier.format(pageHtml, { - // parser: "html", - // plugins: [prettierHTML, prettierCSS], - // }), - // ).toMatchSnapshot("page html"); - // expect( - // await prettier.format(overlayHtml, { - // parser: "html", - // plugins: [prettierHTML, prettierCSS], - // }), - // ).toMatchSnapshot("overlay html"); - // } catch (error) { - // throw error; - // } finally { - // await browser.close(); - // await server.stop(); - // } - // }); - - // it("should show overlay when Trusted Types are enabled and the \"require-trusted-types-for 'script'\" header was used", async () => { - // const compiler = webpack(trustedTypesConfig); - - // new ErrorPlugin().apply(compiler); - - // const devServerOptions = { - // port, - // headers: [ - // { - // key: "Content-Security-Policy", - // value: "require-trusted-types-for 'script'", - // }, - // ], - // client: { - // overlay: { - // trustedTypesPolicyName: "webpack#dev-overlay", - // }, - // }, - // }; - // const server = new Server(devServerOptions, compiler); - - // await server.start(); - - // const { page, browser } = await runBrowser(); - - // try { - // const consoleMessages = []; - - // page.on("console", (message) => { - // consoleMessages.push(message.text()); - // }); - - // await page.goto(`http://localhost:${port}/`, { - // waitUntil: "networkidle0", - // }); - - // // Delay for the overlay to appear - // await delay(1000); - - // const pageHtml = await page.evaluate(() => document.body.outerHTML); - // const overlayHandle = await page.$("#webpack-dev-server-client-overlay"); - // const overlayFrame = await overlayHandle.contentFrame(); - // const overlayHtml = await overlayFrame.evaluate( - // () => document.body.outerHTML, - // ); - - // await page.goto(`http://localhost:${port}/`, { - // waitUntil: "networkidle0", - // }); - - // expect( - // consoleMessages.filter((item) => - // /requires 'TrustedHTML' assignment/.test(item), - // ), - // ).toHaveLength(0); - // expect( - // await prettier.format(pageHtml, { - // parser: "html", - // plugins: [prettierHTML, prettierCSS], - // }), - // ).toMatchSnapshot("page html"); - // expect( - // await prettier.format(overlayHtml, { - // parser: "html", - // plugins: [prettierHTML, prettierCSS], - // }), - // ).toMatchSnapshot("overlay html"); - // } catch (error) { - // throw error; - // } finally { - // await browser.close(); - // await server.stop(); - // } - // }); - - // it("should not show overlay when Trusted Types are enabled, but policy is not allowed", async () => { - // const compiler = webpack(trustedTypesConfig); - - // new ErrorPlugin().apply(compiler); - - // const devServerOptions = { - // port, - // client: { - // overlay: { - // trustedTypesPolicyName: "disallowed-policy", - // }, - // }, - // }; - // const server = new Server(devServerOptions, compiler); - - // await server.start(); - - // const { page, browser } = await runBrowser(); - - // try { - // await page.goto(`http://localhost:${port}/`, { - // waitUntil: "networkidle0", - // }); - - // // Delay for the overlay to appear - // await delay(1000); - - // const pageHtml = await page.evaluate(() => document.body.outerHTML); - // const overlayHandle = await page.$("#webpack-dev-server-client-overlay"); - // expect(overlayHandle).toBe(null); - // expect( - // await prettier.format(pageHtml, { - // parser: "html", - // plugins: [prettierHTML, prettierCSS], - // }), - // ).toMatchSnapshot("page html"); - // } catch (error) { - // throw error; - // } finally { - // await browser.close(); - // await server.stop(); - // } - // }); + it("should show overlay when Trusted Types are enabled", async () => { + const compiler = webpack(trustedTypesConfig); + + new ErrorPlugin().apply(compiler); + + const devServerOptions = { + port, + client: { + overlay: { + trustedTypesPolicyName: "webpack#dev-overlay" + } + } + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const consoleMessages = []; + + page.on("console", message => { + consoleMessages.push(message.text()); + }); + + await page.goto(`http://localhost:${port}/`, { + waitUntil: "networkidle0" + }); + + // Delay for the overlay to appear + await delay(1000); + + const pageHtml = await page.evaluate(() => document.body.outerHTML); + const overlayHandle = await page.$("#webpack-dev-server-client-overlay"); + const overlayFrame = await overlayHandle.contentFrame(); + const overlayHtml = await overlayFrame.evaluate( + () => document.body.outerHTML + ); + + expect( + consoleMessages.filter(item => + /requires 'TrustedHTML' assignment/.test(item) + ) + ).toHaveLength(0); + expect( + await prettier.format(pageHtml, { + parser: "html", + plugins: [prettierHTML, prettierCSS] + }) + ).toMatchSnapshot("page html"); + expect( + await prettier.format(overlayHtml, { + parser: "html", + plugins: [prettierHTML, prettierCSS] + }) + ).toMatchSnapshot("overlay html"); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); + + it("should show overlay when Trusted Types are enabled and the \"require-trusted-types-for 'script'\" header was used", async () => { + const compiler = webpack(trustedTypesConfig); + + new ErrorPlugin().apply(compiler); + + const devServerOptions = { + port, + headers: [ + { + key: "Content-Security-Policy", + value: "require-trusted-types-for 'script'" + } + ], + client: { + overlay: { + trustedTypesPolicyName: "webpack#dev-overlay" + } + } + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + const consoleMessages = []; + + page.on("console", message => { + consoleMessages.push(message.text()); + }); + + await page.goto(`http://localhost:${port}/`, { + waitUntil: "networkidle0" + }); + + // Delay for the overlay to appear + await delay(1000); + + const pageHtml = await page.evaluate(() => document.body.outerHTML); + const overlayHandle = await page.$("#webpack-dev-server-client-overlay"); + const overlayFrame = await overlayHandle.contentFrame(); + const overlayHtml = await overlayFrame.evaluate( + () => document.body.outerHTML + ); + + await page.goto(`http://localhost:${port}/`, { + waitUntil: "networkidle0" + }); + + expect( + consoleMessages.filter(item => + /requires 'TrustedHTML' assignment/.test(item) + ) + ).toHaveLength(0); + expect( + await prettier.format(pageHtml, { + parser: "html", + plugins: [prettierHTML, prettierCSS] + }) + ).toMatchSnapshot("page html"); + expect( + await prettier.format(overlayHtml, { + parser: "html", + plugins: [prettierHTML, prettierCSS] + }) + ).toMatchSnapshot("overlay html"); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); + + it("should not show overlay when Trusted Types are enabled, but policy is not allowed", async () => { + const compiler = webpack(trustedTypesConfig); + + new ErrorPlugin().apply(compiler); + + const devServerOptions = { + port, + client: { + overlay: { + trustedTypesPolicyName: "disallowed-policy" + } + } + }; + const server = new Server(devServerOptions, compiler); + + await server.start(); + + const { page, browser } = await runBrowser(); + + try { + await page.goto(`http://localhost:${port}/`, { + waitUntil: "networkidle0" + }); + + // Delay for the overlay to appear + await delay(1000); + + const pageHtml = await page.evaluate(() => document.body.outerHTML); + const overlayHandle = await page.$("#webpack-dev-server-client-overlay"); + expect(overlayHandle).toBe(null); + expect( + await prettier.format(pageHtml, { + parser: "html", + plugins: [prettierHTML, prettierCSS] + }) + ).toMatchSnapshot("page html"); + } catch (error) { + throw error; + } finally { + await browser.close(); + await server.stop(); + } + }); it('should show an error when "client.overlay.errors" is "true"', async () => { const compiler = webpack(config); diff --git a/tests/webpack-test/configCases/trusted-types/devtool-eval/test.filter.js b/tests/webpack-test/configCases/trusted-types/devtool-eval/test.filter.js deleted file mode 100644 index 3be456dcd23..00000000000 --- a/tests/webpack-test/configCases/trusted-types/devtool-eval/test.filter.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = () => {return false} \ No newline at end of file diff --git a/tests/webpack-test/configCases/trusted-types/web-worker/test.filter.js b/tests/webpack-test/configCases/trusted-types/web-worker/test.filter.js deleted file mode 100644 index 4bee28e9aa7..00000000000 --- a/tests/webpack-test/configCases/trusted-types/web-worker/test.filter.js +++ /dev/null @@ -1,7 +0,0 @@ -// var supportsWorker = require("../../../helpers/supportsWorker"); - -// module.exports = function (config) { -// return supportsWorker(); -// }; - -module.exports = () => {return false} \ No newline at end of file