Skip to content

Commit

Permalink
[browser] introduce sourcemaps (#86152)
Browse files Browse the repository at this point in the history
  • Loading branch information
pavelsavara authored Jun 28, 2023
1 parent 27979b5 commit cf50b7d
Show file tree
Hide file tree
Showing 15 changed files with 121 additions and 36 deletions.
2 changes: 2 additions & 0 deletions eng/liveBuilds.targets
Original file line number Diff line number Diff line change
Expand Up @@ -195,8 +195,10 @@
<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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,9 @@
<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" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,11 @@ Copyright (c) .NET Foundation. All rights reserved.
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)"
Expand All @@ -222,6 +227,7 @@ Copyright (c) .NET Foundation. All rights reserved.
OutputPath="$(OutputPath)"
FingerprintDotNetJs="$(WasmFingerprintDotnetJs)"
EnableThreads="$(_WasmEnableThreads)"
EmitSourceMap="$(_WasmEmitSourceMapBuild)"
>
<Output TaskParameter="AssetCandidates" ItemName="_BuildAssetsCandidates" />
<Output TaskParameter="FilesToRemove" ItemName="_WasmBuildFilesToRemove" />
Expand Down Expand Up @@ -376,6 +382,11 @@ Copyright (c) .NET Foundation. All rights reserved.
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)"
Expand All @@ -388,6 +399,7 @@ Copyright (c) .NET Foundation. All rights reserved.
DotNetJsVersion="$(_WasmRuntimePackVersion)"
FingerprintDotNetJs="$(WasmFingerprintDotnetJs)"
EnableThreads="$(_WasmEnableThreads)"
EmitSourceMap="$(_WasmEmitSourceMapPublish)"
IsWebCilEnabled="$(_WasmEnableWebcil)"
>
<Output TaskParameter="NewCandidates" ItemName="_NewWasmPublishStaticWebAssets" />
Expand Down
4 changes: 3 additions & 1 deletion src/mono/wasm/Wasm.Build.Tests/BuildTestBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -685,8 +685,10 @@ protected static void AssertBasicAppBundle(string bundleDir,
"_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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,9 @@ internal void CompareStat(IDictionary<string, FileStat> oldStat, IDictionary<str

// 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;
}
Expand Down
5 changes: 5 additions & 0 deletions src/mono/wasm/build/WasmApp.targets
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
- $(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
Expand Down Expand Up @@ -356,6 +357,10 @@
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'">
Expand Down
1 change: 1 addition & 0 deletions src/mono/wasm/runtime/dotnet.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,7 @@ interface BootJsonData {
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[];
Expand Down
3 changes: 2 additions & 1 deletion src/mono/wasm/runtime/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,12 @@
"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",
Expand Down
103 changes: 73 additions & 30 deletions src/mono/wasm/runtime/rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ import dts from "rollup-plugin-dts";
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;
Expand All @@ -38,13 +40,15 @@ const banner_dts = banner + "//!\n//! This is generated file, see src/mono/wasm/
// 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 =
Expand Down Expand Up @@ -78,8 +82,28 @@ const envConstants = {
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,
Expand All @@ -103,7 +127,7 @@ const typescriptConfigOptions = {
};

const outputCodePlugins = [consts(envConstants), typescript(typescriptConfigOptions)];
const externalDependencies = ["module"];
const externalDependencies = ["module", "process"];

const loaderConfig = {
treeshake: !isDebug,
Expand All @@ -114,25 +138,14 @@ const loaderConfig = {
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",
Expand All @@ -142,13 +155,28 @@ const runtimeConfig = {
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: [
{
Expand All @@ -174,7 +202,7 @@ if (isDebug) {
banner: banner_dts,
plugins: [alwaysLF(), writeOnChangePlugin()],
});
legacyConfig.output.push({
legacyTypesConfig.output.push({
format: "es",
file: "./dotnet-legacy.d.ts",
banner: banner_dts,
Expand Down Expand Up @@ -221,7 +249,7 @@ const allConfigs = [
loaderConfig,
runtimeConfig,
typesConfig,
legacyConfig,
legacyTypesConfig,
].concat(workerConfigs)
.concat(diagnosticMockTypesConfig ? [diagnosticMockTypesConfig] : []);
export default defineConfig(allConfigs);
Expand Down Expand Up @@ -336,19 +364,34 @@ function regexReplace(replacements = []) {
}
};

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;
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/mono/wasm/runtime/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@
"esnext",
"dom"
],
"sourceMap": true,
}
}
}
4 changes: 3 additions & 1 deletion src/mono/wasm/wasm.proj
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,9 @@
</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;
Expand Down Expand Up @@ -514,7 +516,7 @@

<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>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public static bool ShouldFilterCandidate(
bool copySymbols,
string customIcuCandidateFilename,
bool enableThreads,
bool emitSourceMap,
out string reason)
{
var extension = candidate.GetMetadata("Extension");
Expand All @@ -55,6 +56,7 @@ public static bool ShouldFilterCandidate(
".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",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ public class ComputeWasmBuildAssets : Task

public bool EnableThreads { get; set; }

public bool EmitSourceMap { get; set; }

[Output]
public ITaskItem[] AssetCandidates { get; set; }

Expand Down Expand Up @@ -84,7 +86,7 @@ public override bool Execute()
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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ public class ComputeWasmPublishAssets : Task

public bool EnableThreads { get; set; }

public bool EmitSourceMap { get; set; }

public bool IsWebCilEnabled { get; set; }

[Output]
Expand Down Expand Up @@ -575,7 +577,7 @@ private void GroupResolvedFilesToPublish(

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))
Expand Down
Loading

0 comments on commit cf50b7d

Please sign in to comment.