<LibrariesRuntimeFiles Condition="'$(TargetOS)' == 'browser'"
Include="
$(LibrariesNativeArtifactsPath)dotnet.js;
+ $(LibrariesNativeArtifactsPath)dotnet.js.map;
$(LibrariesNativeArtifactsPath)dotnet.native.js;
$(LibrariesNativeArtifactsPath)dotnet.runtime.js;
+ $(LibrariesNativeArtifactsPath)dotnet.runtime.js.map;
$(LibrariesNativeArtifactsPath)dotnet.d.ts;
$(LibrariesNativeArtifactsPath)dotnet-legacy.d.ts;
$(LibrariesNativeArtifactsPath)package.json;
<PlatformManifestFileEntry Include="libmono-wasm-eh-wasm.a" IsNative="true" />
<PlatformManifestFileEntry Include="wasm-bundled-timezones.a" IsNative="true" />
<PlatformManifestFileEntry Include="dotnet.js" IsNative="true" />
+ <PlatformManifestFileEntry Include="dotnet.js.map" IsNative="true" />
<PlatformManifestFileEntry Include="dotnet.runtime.js" IsNative="true" />
+ <PlatformManifestFileEntry Include="dotnet.runtime.js.map" IsNative="true" />
<PlatformManifestFileEntry Include="dotnet.native.js" IsNative="true" />
<PlatformManifestFileEntry Include="dotnet.native.worker.js" IsNative="true" />
<PlatformManifestFileEntry Include="dotnet.native.js.symbols" IsNative="true" />
Condition="@(WasmNativeAsset->Count()) > 0 and ( '%(FileName)' == 'dotnet' or '%(FileName)' == 'dotnet.native' ) and ('%(Extension)' == '.wasm' or '%(Extension)' == '.js')" />
</ItemGroup>
+ <PropertyGroup>
+ <_WasmEmitSourceMapBuild>$(WasmEmitSourceMap)</_WasmEmitSourceMapBuild>
+ <_WasmEmitSourceMapBuild Condition="'$(_WasmEmitSourceMapBuild)' == ''">true</_WasmEmitSourceMapBuild>
+ </PropertyGroup>
+
<ComputeWasmBuildAssets
Candidates="@(ReferenceCopyLocalPaths->Distinct());@(WasmNativeAsset)"
CustomIcuCandidate="$(_BlazorIcuDataFileName)"
OutputPath="$(OutputPath)"
FingerprintDotNetJs="$(WasmFingerprintDotnetJs)"
EnableThreads="$(_WasmEnableThreads)"
+ EmitSourceMap="$(_WasmEmitSourceMapBuild)"
>
<Output TaskParameter="AssetCandidates" ItemName="_BuildAssetsCandidates" />
<Output TaskParameter="FilesToRemove" ItemName="_WasmBuildFilesToRemove" />
Condition="'%(StaticWebAsset.AssetTraitName)' == 'WasmResource' or '%(StaticWebAsset.AssetTraitName)' == 'Culture' or '%(AssetRole)' == 'Alternative'" />
</ItemGroup>
+ <PropertyGroup>
+ <_WasmEmitSourceMapPublish>$(WasmEmitSourceMap)</_WasmEmitSourceMapPublish>
+ <_WasmEmitSourceMapPublish Condition="'$(_WasmEmitSourceMapPublish)' == ''">false</_WasmEmitSourceMapPublish>
+ </PropertyGroup>
+
<ComputeWasmPublishAssets
ResolvedFilesToPublish="@(ResolvedFileToPublish)"
CustomIcuCandidate="$(_BlazorIcuDataFileName)"
DotNetJsVersion="$(_WasmRuntimePackVersion)"
FingerprintDotNetJs="$(WasmFingerprintDotnetJs)"
EnableThreads="$(_WasmEnableThreads)"
+ EmitSourceMap="$(_WasmEmitSourceMapPublish)"
IsWebCilEnabled="$(_WasmEnableWebcil)"
>
<Output TaskParameter="NewCandidates" ItemName="_NewWasmPublishStaticWebAssets" />
"_framework/dotnet.native.wasm",
"_framework/blazor.boot.json",
"_framework/dotnet.js",
+ "_framework/dotnet.js.map",
"_framework/dotnet.native.js",
- "_framework/dotnet.runtime.js"
+ "_framework/dotnet.runtime.js",
+ "_framework/dotnet.runtime.js.map",
};
if (isBrowserProject)
// those files do not change on re-link
dict["dotnet.js"]=(Path.Combine(paths.BundleDir, "_framework", "dotnet.js"), true);
+ dict["dotnet.js.map"]=(Path.Combine(paths.BundleDir, "_framework", "dotnet.js.map"), true);
dict["dotnet.runtime.js"]=(Path.Combine(paths.BundleDir, "_framework", "dotnet.runtime.js"), true);
+ dict["dotnet.runtime.js.map"]=(Path.Combine(paths.BundleDir, "_framework", "dotnet.runtime.js.map"), true);
return dict;
}
- $(WasmNativeDebugSymbols) - Build with native debug symbols, useful only with `$(RunAOTCompilation)`, or `$(WasmBuildNative)`
Defaults to true.
- $(WasmEmitSymbolMap) - Generates a `dotnet.native.js.symbols` file with a map of wasm function number to name.
+ - $(WasmEmitSourceMap) - Generates `dotnet.runtime.js.map` and `dotnet.js.map` files with a TypeScript source map.
- $(WasmDedup) - Whenever to dedup generic instances when using AOT. Defaults to true.
- $(WasmProfilers) - Profilers to use
Condition="'$(WasmEmitSymbolMap)' == 'true' and
'$(_HasDotnetJsSymbols)' != 'true' and
Exists('$(MicrosoftNetCoreAppRuntimePackRidNativeDir)dotnet.native.js.symbols')" />
+ <WasmNativeAsset Include="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)dotnet.js.map"
+ Condition="'$(WasmEmitSourceMap)' != 'false'" />
+ <WasmNativeAsset Include="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)dotnet.runtime.js.map"
+ Condition="'$(WasmEmitSourceMap)' != 'false'" />
</ItemGroup>
<ItemGroup Condition="'$(InvariantGlobalization)' != 'true'">
readonly resources: ResourceGroups;
/** Gets a value that determines if this boot config was produced from a non-published build (i.e. dotnet build or dotnet run) */
readonly debugBuild: boolean;
+ readonly debugLevel: number;
readonly linkerEnabled: boolean;
readonly cacheBootResources: boolean;
readonly config: string[];
"author": "Microsoft",
"license": "MIT",
"devDependencies": {
+ "@rollup/plugin-terser": "0.4.1",
"@rollup/plugin-typescript": "11.1.0",
"@rollup/plugin-virtual": "3.0.1",
- "@rollup/plugin-terser": "0.4.1",
"@typescript-eslint/eslint-plugin": "5.59.1",
"@typescript-eslint/parser": "5.59.1",
+ "magic-string": "0.30.0",
"eslint": "8.39.0",
"fast-glob": "3.2.12",
"git-commit-info": "2.0.1",
import { createFilter } from "@rollup/pluginutils";
import fast_glob from "fast-glob";
import gitCommitInfo from "git-commit-info";
+import MagicString from "magic-string";
const configuration = process.env.Configuration;
const isDebug = configuration !== "Release";
+const isContinuousIntegrationBuild = process.env.ContinuousIntegrationBuild === "true" ? true : false;
const productVersion = process.env.ProductVersion || "8.0.0-dev";
const nativeBinDir = process.env.NativeBinDir ? process.env.NativeBinDir.replace(/"/g, "") : "bin";
const monoWasmThreads = process.env.MonoWasmThreads === "true" ? true : false;
// emcc doesn't know how to load ES6 module, that's why we need the whole rollup.js
const inlineAssert = [
{
- pattern: /mono_assert\(([^,]*), *"([^"]*)"\);/gm,
// eslint-disable-next-line quotes
- replacement: 'if (!($1)) throw new Error("Assert failed: $2"); // inlined mono_assert'
+ pattern: 'mono_assert\\(([^,]*), *"([^"]*)"\\);',
+ // eslint-disable-next-line quotes
+ replacement: (match) => `if (!(${match[1]})) throw new Error("Assert failed: ${match[2]}"); // inlined mono_assert`
},
{
- pattern: /mono_assert\(([^,]*), \(\) => *`([^`]*)`\);/gm,
- replacement: "if (!($1)) throw new Error(`Assert failed: $2`); // inlined mono_assert"
+ // eslint-disable-next-line quotes
+ pattern: 'mono_assert\\(([^,]*), \\(\\) => *`([^`]*)`\\);',
+ replacement: (match) => `if (!(${match[1]})) throw new Error(\`Assert failed: ${match[2]}\`); // inlined mono_assert`
}
];
const checkAssert =
monoDiagnosticsMock,
gitHash,
wasmEnableLegacyJsInterop,
+ isContinuousIntegrationBuild,
};
+const locationCache = {};
+function sourcemapPathTransform(relativeSourcePath, sourcemapPath) {
+ let res = locationCache[relativeSourcePath];
+ if (res === undefined) {
+ if (!isContinuousIntegrationBuild) {
+ const sourcePath = path.resolve(
+ path.dirname(sourcemapPath),
+ relativeSourcePath
+ );
+ res = `file:///${sourcePath.replace(/\\/g, "/")}`;
+ } else {
+ relativeSourcePath = relativeSourcePath.substring(12);
+ res = `https://raw.githubusercontent.com/dotnet/runtime/${gitHash}/${relativeSourcePath}`;
+ }
+ locationCache[relativeSourcePath] = res;
+ }
+ return res;
+}
+
function consts(dict) {
// implement rollup-plugin-const in terms of @rollup/plugin-virtual
// It's basically the same thing except "consts" names all its modules with a "consts:" prefix,
};
const outputCodePlugins = [consts(envConstants), typescript(typescriptConfigOptions)];
-const externalDependencies = ["module"];
+const externalDependencies = ["module", "process"];
const loaderConfig = {
treeshake: !isDebug,
file: nativeBinDir + "/dotnet.js",
banner,
plugins,
+ sourcemap: true,
+ sourcemapPathTransform,
}
],
external: externalDependencies,
plugins: [regexReplace(inlineAssert), regexCheck([checkAssert, checkNoRuntime]), ...outputCodePlugins],
onwarn: onwarn
};
-const typesConfig = {
- input: "./types/export-types.ts",
- output: [
- {
- format: "es",
- file: nativeBinDir + "/dotnet.d.ts",
- banner: banner_dts,
- plugins: [writeOnChangePlugin()],
- }
- ],
- external: externalDependencies,
- plugins: [dts()],
-};
const runtimeConfig = {
treeshake: !isDebug,
input: "exports.ts",
file: nativeBinDir + "/dotnet.runtime.js",
banner,
plugins,
+ sourcemap: true,
+ sourcemapPathTransform,
}
],
external: externalDependencies,
plugins: [regexReplace(inlineAssert), regexCheck([checkAssert, checkNoLoader]), ...outputCodePlugins],
onwarn: onwarn
};
-const legacyConfig = {
+const typesConfig = {
+ input: "./types/export-types.ts",
+ output: [
+ {
+ format: "es",
+ file: nativeBinDir + "/dotnet.d.ts",
+ banner: banner_dts,
+ plugins: [writeOnChangePlugin()],
+ }
+ ],
+ external: externalDependencies,
+ plugins: [dts()],
+};
+const legacyTypesConfig = {
input: "./net6-legacy/export-types.ts",
output: [
{
banner: banner_dts,
plugins: [alwaysLF(), writeOnChangePlugin()],
});
- legacyConfig.output.push({
+ legacyTypesConfig.output.push({
format: "es",
file: "./dotnet-legacy.d.ts",
banner: banner_dts,
loaderConfig,
runtimeConfig,
typesConfig,
- legacyConfig,
+ legacyTypesConfig,
].concat(workerConfigs)
.concat(diagnosticMockTypesConfig ? [diagnosticMockTypesConfig] : []);
export default defineConfig(allConfigs);
}
};
- function executeReplacement(_, code) {
- // TODO use MagicString for sourcemap support
- let fixed = code;
- for (const rep of replacements) {
- const { pattern, replacement } = rep;
- fixed = fixed.replace(pattern, replacement);
+ function executeReplacement(_, code, id) {
+ const magicString = new MagicString(code);
+ if (!codeHasReplacements(code, id, magicString)) {
+ return null;
}
- if (fixed == code) {
- return null;
+ const result = { code: magicString.toString() };
+ result.map = magicString.generateMap({ hires: true });
+ return result;
+ }
+
+ function codeHasReplacements(code, id, magicString) {
+ let result = false;
+ let match;
+ for (const rep of replacements) {
+ const { pattern, replacement } = rep;
+ const rx = new RegExp(pattern, "gm");
+ while ((match = rx.exec(code))) {
+ result = true;
+ const updated = replacement(match);
+ const start = match.index;
+ const end = start + match[0].length;
+ magicString.overwrite(start, end, updated);
+ }
}
- return { code: fixed };
+ // eslint-disable-next-line no-cond-assign
+ return result;
}
}
"esnext",
"dom"
],
+ "sourceMap": true,
}
-}
+}
\ No newline at end of file
</ItemGroup>
<Copy SourceFiles="$(NativeBinDir)dotnet.js;
+ $(NativeBinDir)dotnet.js.map;
$(NativeBinDir)dotnet.runtime.js;
+ $(NativeBinDir)dotnet.runtime.js.map;
$(NativeBinDir)dotnet.native.js;
$(NativeBinDir)dotnet.d.ts;
$(NativeBinDir)dotnet-legacy.d.ts;
<Target Name="SetMonoRollupEnvironment" DependsOnTargets="GetProductVersions">
<PropertyGroup>
- <MonoRollupEnvironment>Configuration:$(Configuration),NativeBinDir:$(NativeBinDir),ProductVersion:$(ProductVersion),MonoWasmThreads:$(MonoWasmThreads),DISABLE_LEGACY_JS_INTEROP:$(_DisableLegacyJsInterop),MonoDiagnosticsMock:$(MonoDiagnosticsMock)</MonoRollupEnvironment>
+ <MonoRollupEnvironment>Configuration:$(Configuration),NativeBinDir:$(NativeBinDir),ProductVersion:$(ProductVersion),MonoWasmThreads:$(MonoWasmThreads),DISABLE_LEGACY_JS_INTEROP:$(_DisableLegacyJsInterop),MonoDiagnosticsMock:$(MonoDiagnosticsMock),ContinuousIntegrationBuild:$(ContinuousIntegrationBuild)</MonoRollupEnvironment>
</PropertyGroup>
<PropertyGroup>
bool copySymbols,
string customIcuCandidateFilename,
bool enableThreads,
+ bool emitSourceMap,
out string reason)
{
var extension = candidate.GetMetadata("Extension");
".dat" when !string.IsNullOrEmpty(customIcuCandidateFilename) && fileName != customIcuCandidateFilename => "custom icu file will be used instead of icu from the runtime pack",
".json" when fromMonoPackage && (fileName == "emcc-props" || fileName == "package") => $"{fileName}{extension} is not used by Blazor",
".ts" when fromMonoPackage && fileName == "dotnet.d" => "dotnet type definition is not used by Blazor",
+ ".map" when !emitSourceMap && fromMonoPackage && (fileName == "dotnet.js" || fileName == "dotnet.runtime.js") => "source map file is not published",
".ts" when fromMonoPackage && fileName == "dotnet-legacy.d" => "dotnet type definition is not used by Blazor",
".js" when assetType == "native" && !(dotnetJsSingleThreadNames.Contains(fileName) || (enableThreads && fileName == "dotnet.native.worker")) => $"{fileName}{extension} is not used by Blazor",
".pdb" when !copySymbols => "copying symbols is disabled",
public bool EnableThreads { get; set; }
+ public bool EmitSourceMap { get; set; }
+
[Output]
public ITaskItem[] AssetCandidates { get; set; }
for (int i = 0; i < Candidates.Length; i++)
{
var candidate = Candidates[i];
- if (AssetsComputingHelper.ShouldFilterCandidate(candidate, TimeZoneSupport, InvariantGlobalization, CopySymbols, customIcuCandidateFilename, EnableThreads, out var reason))
+ if (AssetsComputingHelper.ShouldFilterCandidate(candidate, TimeZoneSupport, InvariantGlobalization, CopySymbols, customIcuCandidateFilename, EnableThreads, EmitSourceMap, out var reason))
{
Log.LogMessage(MessageImportance.Low, "Skipping asset '{0}' because '{1}'", candidate.ItemSpec, reason);
filesToRemove.Add(candidate);
public bool EnableThreads { get; set; }
+ public bool EmitSourceMap { get; set; }
+
public bool IsWebCilEnabled { get; set; }
[Output]
foreach (var candidate in resolvedFilesToPublish)
{
- if (AssetsComputingHelper.ShouldFilterCandidate(candidate, TimeZoneSupport, InvariantGlobalization, CopySymbols, customIcuCandidateFilename, EnableThreads, out var reason))
+ if (AssetsComputingHelper.ShouldFilterCandidate(candidate, TimeZoneSupport, InvariantGlobalization, CopySymbols, customIcuCandidateFilename, EnableThreads, EmitSourceMap, out var reason))
{
Log.LogMessage(MessageImportance.Low, "Skipping asset '{0}' because '{1}'", candidate.ItemSpec, reason);
if (!resolvedFilesToPublishToRemove.ContainsKey(candidate.ItemSpec))
if (!IncludeThreadsWorker && name == "dotnet.native.worker.js")
continue;
+ if (name == "dotnet.runtime.js.map" || name == "dotnet.js.map")
+ {
+ Log.LogMessage(MessageImportance.Low, $"Skipping {item.ItemSpec} from boot config");
+ continue;
+ }
+
var itemHash = Utils.ComputeIntegrity(item.ItemSpec);
if (name.StartsWith("dotnet", StringComparison.OrdinalIgnoreCase) && string.Equals(Path.GetExtension(name), ".wasm", StringComparison.OrdinalIgnoreCase))