diff --git a/eng/testing/scenarios/BuildWasmAppsJobsList.txt b/eng/testing/scenarios/BuildWasmAppsJobsList.txt index 51bb6bcbb3f293..e16c74fe4f0750 100644 --- a/eng/testing/scenarios/BuildWasmAppsJobsList.txt +++ b/eng/testing/scenarios/BuildWasmAppsJobsList.txt @@ -41,5 +41,5 @@ Wasm.Build.Tests.WasmRunOutOfAppBundleTests Wasm.Build.Tests.WasmSIMDTests Wasm.Build.Tests.WasmTemplateTests Wasm.Build.Tests.WorkloadTests -Wasm.Build.Tests.TestAppScenarios.DownloadResourceProgressTests +Wasm.Build.Tests.TestAppScenarios.ModuleConfigTests Wasm.Build.Tests.MT.Blazor.SimpleMultiThreadedTests diff --git a/src/mono/sample/wasm/browser-advanced/main.js b/src/mono/sample/wasm/browser-advanced/main.js index b5c414322fefd0..85b1a64e8e4228 100644 --- a/src/mono/sample/wasm/browser-advanced/main.js +++ b/src/mono/sample/wasm/browser-advanced/main.js @@ -59,6 +59,7 @@ try { console.log('user code Module.onDotnetReady'); }, postRun: () => { console.log('user code Module.postRun'); }, + out: (text) => { console.log("ADVANCED:" + text) }, }) .withResourceLoader((type, name, defaultUri, integrity, behavior) => { // loadBootResource could return string with unqualified name of resource. It assumes that we resolve it with document.baseURI diff --git a/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/DownloadResourceProgressTests.cs b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/ModuleConfigTests.cs similarity index 68% rename from src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/DownloadResourceProgressTests.cs rename to src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/ModuleConfigTests.cs index 70f9b4f1507d28..1b8c43ecea77b0 100644 --- a/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/DownloadResourceProgressTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/TestAppScenarios/ModuleConfigTests.cs @@ -13,9 +13,9 @@ namespace Wasm.Build.Tests.TestAppScenarios; -public class DownloadResourceProgressTests : AppTestBase +public class ModuleConfigTests : AppTestBase { - public DownloadResourceProgressTests(ITestOutputHelper output, SharedBuildPerTestClassFixture buildContext) + public ModuleConfigTests(ITestOutputHelper output, SharedBuildPerTestClassFixture buildContext) : base(output, buildContext) { } @@ -25,7 +25,7 @@ public DownloadResourceProgressTests(ITestOutputHelper output, SharedBuildPerTes [InlineData(true)] public async Task DownloadProgressFinishes(bool failAssemblyDownload) { - CopyTestAsset("WasmBasicTestApp", $"DownloadResourceProgressTests_{failAssemblyDownload}"); + CopyTestAsset("WasmBasicTestApp", $"ModuleConfigTests_DownloadProgressFinishes_{failAssemblyDownload}"); PublishProject("Debug"); var result = await RunSdkStyleApp(new( @@ -54,4 +54,24 @@ public async Task DownloadProgressFinishes(bool failAssemblyDownload) : "The download progress test did emit unexpected message about failing download" ); } + + [Fact] + public async Task OutErrOverrideWorks() + { + CopyTestAsset("WasmBasicTestApp", $"ModuleConfigTests_OutErrOverrideWorks"); + PublishProject("Debug"); + + var result = await RunSdkStyleApp(new( + Configuration: "Debug", + TestScenario: "OutErrOverrideWorks" + )); + Assert.True( + result.ConsoleOutput.Any(m => m.Contains("Emscripten out override works!")), + "Emscripten out override doesn't work" + ); + Assert.True( + result.ConsoleOutput.Any(m => m.Contains("Emscripten err override works!")), + "Emscripten err override doesn't work" + ); + } } diff --git a/src/mono/wasm/runtime/loader/assets.ts b/src/mono/wasm/runtime/loader/assets.ts index 8730988193ffd0..5e9eb8a8d3b75b 100644 --- a/src/mono/wasm/runtime/loader/assets.ts +++ b/src/mono/wasm/runtime/loader/assets.ts @@ -12,6 +12,7 @@ import { mono_exit } from "./exit"; import { addCachedReponse, findCachedResponse } from "./assetsCache"; import { getIcuResourceName } from "./icu"; import { makeURLAbsoluteWithApplicationBase } from "./polyfills"; +import { mono_log_info } from "./logging"; let throttlingPromise: PromiseAndController | undefined; @@ -545,7 +546,7 @@ async function start_asset_download_sources(asset: AssetEntryInternal): Promise< err.status = response.status; throw err; } else { - loaderHelpers.out(`optional download '${response.url}' for ${asset.name} failed ${response.status} ${response.statusText}`); + mono_log_info(`optional download '${response.url}' for ${asset.name} failed ${response.status} ${response.statusText}`); return undefined; } } diff --git a/src/mono/wasm/runtime/loader/icu.ts b/src/mono/wasm/runtime/loader/icu.ts index 927672f5db99d6..bb7213b22a88e8 100644 --- a/src/mono/wasm/runtime/loader/icu.ts +++ b/src/mono/wasm/runtime/loader/icu.ts @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +import { mono_log_error } from "./logging"; import { GlobalizationMode, MonoConfig } from "../types"; import { ENVIRONMENT_IS_WEB, loaderHelpers } from "./globals"; import { mono_log_info, mono_log_debug } from "./logging"; @@ -18,7 +19,7 @@ export function init_globalization() { loaderHelpers.preferredIcuAsset = null; } else { const msg = "invariant globalization mode is inactive and no ICU data archives are available"; - loaderHelpers.err(`ERROR: ${msg}`); + mono_log_error(`ERROR: ${msg}`); throw new Error(msg); } } diff --git a/src/mono/wasm/runtime/loader/run.ts b/src/mono/wasm/runtime/loader/run.ts index b3437a5a81d61b..112d66edab945d 100644 --- a/src/mono/wasm/runtime/loader/run.ts +++ b/src/mono/wasm/runtime/loader/run.ts @@ -458,7 +458,7 @@ async function initializeModules(es6Modules: [RuntimeModuleExportsInternal, Nati const { default: emscriptenFactory } = es6Modules[1]; setRuntimeGlobals(globalObjectsRoot); initializeExports(globalObjectsRoot); - await configureRuntimeStartup(); + await configureRuntimeStartup(globalObjectsRoot.module); loaderHelpers.runtimeModuleLoaded.promise_control.resolve(); emscriptenFactory((originalModule: EmscriptenModuleInternal) => { diff --git a/src/mono/wasm/runtime/startup.ts b/src/mono/wasm/runtime/startup.ts index c385844dfd30bb..324bdc78b0435d 100644 --- a/src/mono/wasm/runtime/startup.ts +++ b/src/mono/wasm/runtime/startup.ts @@ -39,7 +39,23 @@ import { assertNoProxies } from "./gc-handles"; // default size if MonoConfig.pthreadPoolSize is undefined const MONO_PTHREAD_POOL_SIZE = 4; -export async function configureRuntimeStartup(): Promise { +export async function configureRuntimeStartup (module: DotnetModuleInternal): Promise { + if (!module.out) { + // eslint-disable-next-line no-console + module.out = console.log.bind(console); + } + if (!module.err) { + // eslint-disable-next-line no-console + module.err = console.error.bind(console); + } + if (!module.print) { + module.print = module.out; + } + if (!module.printErr) { + module.printErr = module.err; + } + loaderHelpers.out = module.print; + loaderHelpers.err = module.printErr; await init_polyfills_async(); await checkMemorySnapshotSize(); } @@ -54,17 +70,6 @@ export function configureEmscriptenStartup(module: DotnetModuleInternal): void { module.locateFile = module.__locateFile = (path) => loaderHelpers.scriptDirectory + path; } - if (!module.out) { - // eslint-disable-next-line no-console - module.out = console.log.bind(console); - } - - if (!module.err) { - // eslint-disable-next-line no-console - module.err = console.error.bind(console); - } - loaderHelpers.out = module.out; - loaderHelpers.err = module.err; module.mainScriptUrlOrBlob = loaderHelpers.scriptUrl;// this is needed by worker threads // these all could be overridden on DotnetModuleConfig, we are chaing them to async below, as opposed to emscripten diff --git a/src/mono/wasm/runtime/types/internal.ts b/src/mono/wasm/runtime/types/internal.ts index a91b21973c8d5e..c43443a48da6bc 100644 --- a/src/mono/wasm/runtime/types/internal.ts +++ b/src/mono/wasm/runtime/types/internal.ts @@ -464,6 +464,8 @@ export declare interface EmscriptenModuleInternal { runtimeKeepalivePush(): void; runtimeKeepalivePop(): void; maybeExit(): void; + print(message: string): void; + printErr(message: string): void; } /// A PromiseController encapsulates a Promise together with easy access to its resolve and reject functions. @@ -492,7 +494,7 @@ export type setGlobalObjectsType = (globalObjects: GlobalObjects) => void; export type initializeExportsType = (globalObjects: GlobalObjects) => RuntimeAPI; export type initializeReplacementsType = (replacements: EmscriptenReplacements) => void; export type configureEmscriptenStartupType = (module: DotnetModuleInternal) => void; -export type configureRuntimeStartupType = () => Promise; +export type configureRuntimeStartupType = (module: DotnetModuleInternal) => Promise; export type configureWorkerStartupType = (module: DotnetModuleInternal) => Promise @@ -508,4 +510,4 @@ export type RuntimeModuleExportsInternal = { export type NativeModuleExportsInternal = { default: (unificator: Function) => EmscriptenModuleInternal -} \ No newline at end of file +} diff --git a/src/mono/wasm/testassets/WasmBasicTestApp/App/Common/Program.cs b/src/mono/wasm/testassets/WasmBasicTestApp/App/Common/Program.cs index 4f38c02031c7ec..eda19b81f506eb 100644 --- a/src/mono/wasm/testassets/WasmBasicTestApp/App/Common/Program.cs +++ b/src/mono/wasm/testassets/WasmBasicTestApp/App/Common/Program.cs @@ -2,3 +2,4 @@ // The .NET Foundation licenses this file to you under the MIT license. System.Console.WriteLine("WasmBasicTestApp"); +System.Console.Error.WriteLine("WasmBasicTestApp stderr"); diff --git a/src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/main.js b/src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/main.js index 076f37a62a6d87..8e3485bc2e67cd 100644 --- a/src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/main.js +++ b/src/mono/wasm/testassets/WasmBasicTestApp/App/wwwroot/main.js @@ -63,6 +63,18 @@ switch (testCase) { } }); break; + case "OutErrOverrideWorks": + dotnet.withModuleConfig({ + out: (message) => { + console.log("Emscripten out override works!"); + console.log(message) + }, + err: (message) => { + console.error("Emscripten err override works!"); + console.error(message) + }, + }); + break; } const { getAssemblyExports, getConfig, INTERNAL } = await dotnet.create(); @@ -94,6 +106,9 @@ try { case "DownloadResourceProgressTest": exit(0); break; + case "OutErrOverrideWorks": + dotnet.run(); + break; default: console.error(`Unknown test case: ${testCase}`); exit(3);