[browser] javascript build cleanup (#81212)
authorPavel Savara <pavel.savara@gmail.com>
Thu, 2 Feb 2023 08:11:03 +0000 (09:11 +0100)
committerGitHub <noreply@github.com>
Thu, 2 Feb 2023 08:11:03 +0000 (09:11 +0100)
* type definitions
* linked files
* fix fetch imports

15 files changed:
src/mono/wasm/runtime/assets.ts
src/mono/wasm/runtime/dotnet.d.ts
src/mono/wasm/runtime/es6/dotnet.es6.extpost.js
src/mono/wasm/runtime/es6/dotnet.es6.lib.js
src/mono/wasm/runtime/es6/dotnet.es6.pre.js
src/mono/wasm/runtime/export-types.ts
src/mono/wasm/runtime/exports.ts
src/mono/wasm/runtime/http.ts
src/mono/wasm/runtime/logging.ts
src/mono/wasm/runtime/polyfills.ts
src/mono/wasm/runtime/run-outer.ts
src/mono/wasm/runtime/types.ts
src/mono/wasm/runtime/types/consts.d.ts
src/mono/wasm/wasm.proj
src/native/libs/System.Native/pal_random.lib.js

index d6bb4d2..4cb2e76 100644 (file)
@@ -441,7 +441,7 @@ export async function instantiate_wasm_asset(
 ): Promise<void> {
     mono_assert(pendingAsset && pendingAsset.pendingDownloadInternal && pendingAsset.pendingDownloadInternal.response, "Can't load dotnet.wasm");
     const response = await pendingAsset.pendingDownloadInternal.response;
-    const contentType = response.headers ? response.headers.get("Content-Type") : undefined;
+    const contentType = response.headers && response.headers.get ? response.headers.get("Content-Type") : undefined;
     let compiledInstance: WebAssembly.Instance;
     let compiledModule: WebAssembly.Module;
     if (typeof WebAssembly.instantiateStreaming === "function" && contentType === "application/wasm") {
index 80fab37..f8dd4b8 100644 (file)
@@ -270,4 +270,4 @@ declare global {
 declare const dotnet: ModuleAPI["dotnet"];
 declare const exit: ModuleAPI["exit"];
 
-export { CreateDotnetRuntimeType, DotnetModuleConfig, EmscriptenModule, IMemoryView, ModuleAPI, MonoConfig, RuntimeAPI, createDotnetRuntime as default, dotnet, exit };
+export { AssetEntry, CreateDotnetRuntimeType, DotnetModuleConfig, EmscriptenModule, IMemoryView, ModuleAPI, MonoConfig, ResourceRequest, RuntimeAPI, createDotnetRuntime as default, dotnet, exit };
index be0f631..f852ad0 100644 (file)
@@ -1,5 +1,10 @@
+const ENVIRONMENT_IS_WEB = typeof window == "object";
+const ENVIRONMENT_IS_NODE = typeof process == "object" && typeof process.versions == "object" && typeof process.versions.node == "string";
 const MONO = {}, BINDING = {}, INTERNAL = {}, IMPORTS = {};
+var fetch = fetch || undefined; var require = require || undefined; var __dirname = __dirname || '';
 __dotnet_runtime.__setEmscriptenEntrypoint(createDotnetRuntime);
+const __initializeImportsAndExports = __dotnet_runtime.__initializeImportsAndExports;
+const __requirePromise = ENVIRONMENT_IS_NODE ? import(/* webpackIgnore: true */'module').then(mod => mod.createRequire(import.meta.url)) : undefined;
 const dotnet = __dotnet_runtime.moduleExports.dotnet;
 const exit = __dotnet_runtime.moduleExports.exit;
 export { dotnet, exit, INTERNAL };
index ed026d8..28fd116 100644 (file)
@@ -5,16 +5,16 @@
 "use strict";
 
 #if USE_PTHREADS
-const usePThreads = `true`;
+const usePThreads = true;
 const isPThread = `ENVIRONMENT_IS_PTHREAD`;
 #else
-const usePThreads = `false`;
+const usePThreads = false;
 const isPThread = `false`;
 #endif
 
 const DotnetSupportLib = {
     $DOTNET: {},
-    // this line will be placed early on emscripten runtime creation, passing import and export objects into __dotnet_runtime IFFE
+    // this line will be placed early on emscripten runtime creation, passing import and export objects into __dotnet_runtime IIFE
     // Emscripten uses require function for nodeJS even in ES6 module. We need https://nodejs.org/api/module.html#modulecreaterequirefilename
     // We use dynamic import because there is no "module" module in the browser.
     // This is async init of it, note it would become available only after first tick.
@@ -23,21 +23,21 @@ const DotnetSupportLib = {
     // We also replace implementation of fetch
     $DOTNET__postset: `
 let __dotnet_replacement_PThread = ${usePThreads} ? {} : undefined;
-if (${usePThreads}) {
-    __dotnet_replacement_PThread.loadWasmModuleToWorker = PThread.loadWasmModuleToWorker;
-    __dotnet_replacement_PThread.threadInitTLS = PThread.threadInitTLS;
-    __dotnet_replacement_PThread.allocateUnusedWorker = PThread.allocateUnusedWorker;
-}
+${usePThreads ? `
+__dotnet_replacement_PThread.loadWasmModuleToWorker = PThread.loadWasmModuleToWorker;
+__dotnet_replacement_PThread.threadInitTLS = PThread.threadInitTLS;
+__dotnet_replacement_PThread.allocateUnusedWorker = PThread.allocateUnusedWorker;
+` : ''}
 let __dotnet_replacements = {scriptUrl: import.meta.url, fetch: globalThis.fetch, require, updateGlobalBufferAndViews, pthreadReplacements: __dotnet_replacement_PThread};
 if (ENVIRONMENT_IS_NODE) {
-    __dotnet_replacements.requirePromise = import(/* webpackIgnore: true */'module').then(mod => mod.createRequire(import.meta.url));
+    __dotnet_replacements.requirePromise = __requirePromise;
 }
-let __dotnet_exportedAPI = __dotnet_runtime.__initializeImportsAndExports(
+let __dotnet_exportedAPI = __initializeImportsAndExports(
     { isGlobal:false, isNode:ENVIRONMENT_IS_NODE, isWorker:ENVIRONMENT_IS_WORKER, isShell:ENVIRONMENT_IS_SHELL, isWeb:ENVIRONMENT_IS_WEB, isPThread:${isPThread}, quit_, ExitStatus, requirePromise:__dotnet_replacements.requirePromise },
     { mono:MONO, binding:BINDING, internal:INTERNAL, module:Module, marshaled_imports: IMPORTS },
     __dotnet_replacements, __callbackAPI);
 updateGlobalBufferAndViews = __dotnet_replacements.updateGlobalBufferAndViews;
-var fetch = __dotnet_replacements.fetch;
+fetch = __dotnet_replacements.fetch;
 _scriptDir = __dirname = scriptDirectory = __dotnet_replacements.scriptDirectory;
 if (ENVIRONMENT_IS_NODE) {
     __dotnet_replacements.requirePromise.then(someRequire => {
@@ -45,11 +45,11 @@ if (ENVIRONMENT_IS_NODE) {
     });
 }
 var noExitRuntime = __dotnet_replacements.noExitRuntime;
-if (${usePThreads}) {
-    PThread.loadWasmModuleToWorker = __dotnet_replacements.pthreadReplacements.loadWasmModuleToWorker;
-    PThread.threadInitTLS = __dotnet_replacements.pthreadReplacements.threadInitTLS;
-    PThread.allocateUnusedWorker = __dotnet_replacements.pthreadReplacements.allocateUnusedWorker;
-}
+${usePThreads ? `
+PThread.loadWasmModuleToWorker = __dotnet_replacements.pthreadReplacements.loadWasmModuleToWorker;
+PThread.threadInitTLS = __dotnet_replacements.pthreadReplacements.threadInitTLS;
+PThread.allocateUnusedWorker = __dotnet_replacements.pthreadReplacements.allocateUnusedWorker;
+` : ''}
 `,
 };
 
index c7c64de..67102e3 100644 (file)
@@ -1,5 +1,3 @@
-var require = require || undefined;
-var __dirname = __dirname || '';
 var __callbackAPI = { MONO, BINDING, INTERNAL, IMPORTS };
 if (typeof createDotnetRuntime === "function") {
     __callbackAPI.Module = Module = { ready: Module.ready };
index a1ad9df..fecc9ea 100644 (file)
@@ -2,7 +2,7 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 import { IMemoryView } from "./marshal";
-import { createDotnetRuntime, CreateDotnetRuntimeType, DotnetModuleConfig, RuntimeAPI, MonoConfig, ModuleAPI } from "./types";
+import { createDotnetRuntime, CreateDotnetRuntimeType, DotnetModuleConfig, RuntimeAPI, MonoConfig, ModuleAPI, AssetEntry, ResourceRequest } from "./types";
 import { EmscriptenModule } from "./types/emscripten";
 
 // -----------------------------------------------------------
@@ -22,6 +22,6 @@ declare const exit: ModuleAPI["exit"];
 
 export {
     EmscriptenModule,
-    RuntimeAPI, ModuleAPI, DotnetModuleConfig, CreateDotnetRuntimeType, MonoConfig, IMemoryView,
+    RuntimeAPI, ModuleAPI, DotnetModuleConfig, CreateDotnetRuntimeType, MonoConfig, IMemoryView, AssetEntry, ResourceRequest,
     dotnet, exit
 };
index 1950eb7..0b440c0 100644 (file)
@@ -37,7 +37,7 @@ function initializeImportsAndExports(
     const module = exports.module as DotnetModule;
     const globalThisAny = globalThis as any;
 
-    // we want to have same instance of MONO, BINDING and Module in dotnet iffe
+    // we want to have same instance of MONO, BINDING and Module in dotnet iife
     set_imports_exports(imports, exports);
     set_legacy_exports(exports);
     init_polyfills(replacements);
index 73365d3..5b07dac 100644 (file)
@@ -4,6 +4,7 @@
 import { wrap_as_cancelable_promise } from "./cancelable-promise";
 import { Module } from "./imports";
 import { MemoryViewType, Span } from "./marshal";
+import { fetch_like } from "./polyfills";
 import { mono_assert } from "./types";
 import { VoidPtr } from "./types/emscripten";
 
@@ -56,7 +57,7 @@ export function http_wasm_fetch(url: string, header_names: string[], header_valu
     }
 
     return wrap_as_cancelable_promise(async () => {
-        const res = await fetch(url, options) as ResponseExtension;
+        const res = await fetch_like(url, options) as ResponseExtension;
         res.__abort_controller = abort_controller;
         return res;
     });
index 4a2f0e3..fb8cb01 100644 (file)
@@ -1,5 +1,5 @@
-//! Licensed to the .NET Foundation under one or more agreements.
-//! The .NET Foundation licenses this file to you under the MIT license.
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
 
 import BuildConfiguration from "consts:configuration";
 import { INTERNAL, Module, runtimeHelpers } from "./imports";
index 58f1bdd..50e897a 100644 (file)
@@ -162,13 +162,8 @@ export function init_polyfills(replacements: EarlyReplacements): void {
         runtimeHelpers.locateFile = anyModule.locateFile;
     }
 
-    // fetch poly
-    if (imports.fetch) {
-        replacements.fetch = runtimeHelpers.fetch_like = imports.fetch;
-    }
-    else {
-        replacements.fetch = runtimeHelpers.fetch_like = fetch_like;
-    }
+    // prefer fetch_like over global fetch for assets
+    replacements.fetch = runtimeHelpers.fetch_like = imports.fetch || fetch_like;
 
     // misc
     replacements.noExitRuntime = ENVIRONMENT_IS_WEB;
@@ -207,10 +202,10 @@ export async function init_polyfills_async(): Promise<void> {
             } catch (err: any) {
                 // Noop, error throwing polyfill provided bellow
             }
-            
+
             if (!nodeCrypto) {
-                globalThis.crypto.getRandomValues = () => { 
-                    throw new Error("Using node without crypto support. To enable current operation, either provide polyfill for 'globalThis.crypto.getRandomValues' or enable 'node:crypto' module."); 
+                globalThis.crypto.getRandomValues = () => {
+                    throw new Error("Using node without crypto support. To enable current operation, either provide polyfill for 'globalThis.crypto.getRandomValues' or enable 'node:crypto' module.");
                 };
             } else if (nodeCrypto.webcrypto) {
                 globalThis.crypto = nodeCrypto.webcrypto;
@@ -232,26 +227,36 @@ const dummyPerformance = {
 };
 
 export async function fetch_like(url: string, init?: RequestInit): Promise<Response> {
+    const imports = Module.imports as DotnetModuleConfigImports;
+    const hasFetch = typeof (globalThis.fetch) === "function";
     try {
-        if (ENVIRONMENT_IS_NODE) {
+        if (typeof (imports.fetch) === "function") {
+            return imports.fetch(url, init || { credentials: "same-origin" });
+        }
+        else if (ENVIRONMENT_IS_NODE) {
+            const isFileUrl = url.startsWith("file://");
+            if (!isFileUrl && hasFetch) {
+                return globalThis.fetch(url, init || { credentials: "same-origin" });
+            }
             if (!node_fs) {
                 const node_require = await runtimeHelpers.requirePromise;
                 node_url = node_require("url");
                 node_fs = node_require("fs");
             }
-            if (url.startsWith("file://")) {
+            if (isFileUrl) {
                 url = node_url.fileURLToPath(url);
             }
 
             const arrayBuffer = await node_fs.promises.readFile(url);
             return <Response><any>{
                 ok: true,
+                headers: [],
                 url,
                 arrayBuffer: () => arrayBuffer,
                 json: () => JSON.parse(arrayBuffer)
             };
         }
-        else if (typeof (globalThis.fetch) === "function") {
+        else if (hasFetch) {
             return globalThis.fetch(url, init || { credentials: "same-origin" });
         }
         else if (typeof (read) === "function") {
index 6c4115a..7f6902e 100644 (file)
@@ -22,10 +22,6 @@ export interface DotnetHostBuilder {
     run(): Promise<number>
 }
 
-// these constants duplicate detection inside emscripten internals, but happen earlier
-const ENVIRONMENT_IS_WEB = typeof window == "object";
-const ENVIRONMENT_IS_NODE = typeof process == "object" && typeof process.versions == "object" && typeof process.versions.node == "string";
-
 class HostBuilder implements DotnetHostBuilder {
     private instance?: RuntimeAPI;
     private applicationArguments?: string[];
index 81739f9..e55f1ed 100644 (file)
@@ -259,7 +259,7 @@ export type DotnetModuleConfig = {
 
 export type DotnetModuleConfigImports = {
     require?: (name: string) => any;
-    fetch?: (url: string) => Promise<Response>;
+    fetch?: (url: string, options: any | undefined) => Promise<Response>;
     fs?: {
         promises?: {
             readFile?: (path: string) => Promise<string | Buffer>,
index ff10fea..f286d28 100644 (file)
@@ -17,3 +17,7 @@ declare module "consts:monoDiagnosticsMock" {
     const constant: boolean;
     export default constant;
 }
+
+// these constants from dotnet.es6.extpost.js duplicate detection inside emscripten internals, but happen earlier
+declare const ENVIRONMENT_IS_NODE: boolean;
+declare const ENVIRONMENT_IS_WEB: boolean;
\ No newline at end of file
index dd279eb..0ffb7b9 100644 (file)
       <PInvokeTableFile>$(ArtifactsObjDir)wasm/pinvoke-table.h</PInvokeTableFile>
       <InterpToNativeTableFile>$(ArtifactsObjDir)wasm/wasm_m2n_invoke.g.h</InterpToNativeTableFile>
       <CMakeConfigurationEmccFlags Condition="'$(Configuration)' == 'Debug'">-g -Os -s -DDEBUG=1 -DENABLE_AOT_PROFILER=1 -DENABLE_BROWSER_PROFILER=1</CMakeConfigurationEmccFlags>
-      <CMakeConfigurationEmccFlags Condition="'$(Configuration)' == 'Release'">-Oz  -DENABLE_BROWSER_PROFILER=1</CMakeConfigurationEmccFlags>
+      <CMakeConfigurationEmccFlags Condition="'$(Configuration)' == 'Release'">-Oz -DENABLE_BROWSER_PROFILER=1</CMakeConfigurationEmccFlags>
 
       <CMakeConfigurationLinkFlags Condition="'$(Configuration)' == 'Debug'"  >$(CMakeConfigurationEmccFlags)</CMakeConfigurationLinkFlags>
       <CMakeConfigurationLinkFlags Condition="'$(Configuration)' == 'Release'">-O2</CMakeConfigurationLinkFlags>
+
       <CMakeConfigurationLinkFlags>$(CMakeConfigurationLinkFlags) -s EXPORT_ES6=1</CMakeConfigurationLinkFlags>
       <CMakeConfigurationLinkFlags Condition="'$(MonoWasmThreads)' == 'true'">$(CMakeConfigurationLinkFlags) -Wno-pthreads-mem-growth</CMakeConfigurationLinkFlags>
       <CMakeConfigurationLinkFlags                                            >$(CMakeConfigurationLinkFlags) --emit-symbol-map</CMakeConfigurationLinkFlags>
index bcaba4d..66cd390 100644 (file)
@@ -3,11 +3,12 @@
 
 const DotNetEntropyLib = {
     $DOTNETENTROPY: {
-        // batchedQuotaMax is the max number of bytes as specified by the api spec.
-        // If the byteLength of array is greater than 65536, throw a QuotaExceededError and terminate the algorithm.
-        // https://www.w3.org/TR/WebCryptoAPI/#Crypto-method-getRandomValues
-        batchedQuotaMax: 65536,
         getBatchedRandomValues: function (buffer, bufferLength) {
+            // batchedQuotaMax is the max number of bytes as specified by the api spec.
+            // If the byteLength of array is greater than 65536, throw a QuotaExceededError and terminate the algorithm.
+            // https://www.w3.org/TR/WebCryptoAPI/#Crypto-method-getRandomValues
+            const batchedQuotaMax = 65536;
+
             // Chrome doesn't want SharedArrayBuffer to be passed to crypto APIs
             const needTempBuf = typeof SharedArrayBuffer !== 'undefined' && Module.HEAPU8.buffer instanceof SharedArrayBuffer;
             // if we need a temporary buffer, make one that is big enough and write into it from the beginning
@@ -16,14 +17,14 @@ const DotNetEntropyLib = {
             const offset = needTempBuf ? 0 : buffer;
             // for modern web browsers
             // map the work array to the memory buffer passed with the length
-            for (let i = 0; i < bufferLength; i += this.batchedQuotaMax) {
-                const view = new Uint8Array(buf, offset + i, Math.min(bufferLength - i, this.batchedQuotaMax));
+            for (let i = 0; i < bufferLength; i += batchedQuotaMax) {
+                const view = new Uint8Array(buf, offset + i, Math.min(bufferLength - i, batchedQuotaMax));
                 crypto.getRandomValues(view)
             }
             if (needTempBuf) {
                 // copy data out of the temporary buffer into the wasm instance memory
                 const heapView = new Uint8Array(Module.HEAPU8.buffer, buffer, bufferLength);
-                heapView.set(new Uint8Array (buf));
+                heapView.set(new Uint8Array(buf));
             }
         }
     },