Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions src/mono/browser/build/BrowserWasmApp.targets
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
$(WasmGenerateAppBundleDependsOn);
GenerateBuildRuntimeConfigurationFiles;
_GetWasmGenerateAppBundleDependencies;
_CopyDotnetTypeScriptDefinitions;
_WasmGenerateAppBundle;
_WasmGenerateRunV8Script;
</WasmGenerateAppBundleDependsOn>
Expand Down Expand Up @@ -609,4 +610,29 @@

<Exec Condition="'$(OS)' != 'Windows_NT'" Command="chmod a+x &quot;$(WasmRunV8ScriptPath)&quot;" />
</Target>

<!-- Copy dotnet.d.ts to wwwroot for TypeScript development experience -->
<Target Name="_CopyDotnetTypeScriptDefinitions"
Condition="Exists('$(MSBuildProjectDirectory)\wwwroot') and Exists('$(MicrosoftNetCoreAppRuntimePackRidNativeDir)dotnet.d.ts')">

<PropertyGroup>
<_DotnetTypesSourcePath>$(MicrosoftNetCoreAppRuntimePackRidNativeDir)dotnet.d.ts</_DotnetTypesSourcePath>
<_DotnetTypesDestPath>$(MSBuildProjectDirectory)\wwwroot\dotnet.d.ts</_DotnetTypesDestPath>
</PropertyGroup>

<!-- Only copy if source exists and is newer than destination or destination doesn't exist -->
<Copy SourceFiles="$(_DotnetTypesSourcePath)"
DestinationFiles="$(_DotnetTypesDestPath)"
Condition="!Exists('$(_DotnetTypesDestPath)') Or '$([System.IO.File]::GetLastWriteTime($(_DotnetTypesSourcePath)))' &gt; '$([System.IO.File]::GetLastWriteTime($(_DotnetTypesDestPath)))'"
SkipUnchangedFiles="true" />

<Message Text="Copied dotnet.d.ts to wwwroot directory for TypeScript IntelliSense"
Condition="Exists('$(_DotnetTypesSourcePath)')"
Importance="low" />

<!-- Add the file as Content so it gets included in the project -->
<ItemGroup Condition="Exists('$(_DotnetTypesDestPath)')">
<Content Include="wwwroot\dotnet.d.ts" Condition="'@(Content)' == '' Or !(@(Content->AnyHaveMetadataValue('Identity', 'wwwroot\dotnet.d.ts')))" />
</ItemGroup>
</Target>
</Project>
8 changes: 8 additions & 0 deletions src/mono/browser/runtime/rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,14 @@ if (isDebug) {
});
}

// Always copy to the wasmbrowser template so it stays in sync
typesConfig.output.push({
format: "es",
file: "../../wasm/templates/templates/browser/wwwroot/dotnet.d.ts",
banner: banner_dts,
plugins: [alwaysLF(), writeOnChangePlugin()],
});

const allConfigs = [
loaderConfig,
runtimeConfig,
Expand Down
59 changes: 59 additions & 0 deletions src/mono/wasm/Wasm.Build.Tests/Templates/WasmTemplateTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -317,5 +317,64 @@
}

}

[Theory]
[InlineData(Configuration.Debug)]
[InlineData(Configuration.Release)]
public void TypeScriptDefinitionsCopiedToWwwroot(Configuration config)
{
ProjectInfo info = CreateWasmTemplateProject(Template.WasmBrowser, config, aot: false, "tsdefs");

// Build the project to trigger the _CopyDotnetTypeScriptDefinitions target
BuildProject(info, config, new BuildOptions());

// Verify that dotnet.d.ts exists in wwwroot
string projectDirectory = Path.GetDirectoryName(info.ProjectFilePath)!;
string dotnetDtsPath = Path.Combine(projectDirectory, "wwwroot", "dotnet.d.ts");

Assert.True(File.Exists(dotnetDtsPath), $"dotnet.d.ts should exist at {dotnetDtsPath}");

// Verify that the file contains expected TypeScript definitions
string content = File.ReadAllText(dotnetDtsPath);
Assert.Contains("interface DotnetHostBuilder", content);
Assert.Contains("RuntimeAPI", content);
Assert.Contains("Licensed to the .NET Foundation", content);
}

[Fact]
public void TypeScriptDefinitionsUpdatedWhenNewer()
{
Configuration config = Configuration.Debug;
ProjectInfo info = CreateWasmTemplateProject(Template.WasmBrowser, config, aot: false, "tsupdate");

string projectDirectory = Path.GetDirectoryName(info.ProjectFilePath)!;
string dotnetDtsPath = Path.Combine(projectDirectory, "wwwroot", "dotnet.d.ts");

// First build
BuildProject(info, config, new BuildOptions());
Assert.True(File.Exists(dotnetDtsPath), $"dotnet.d.ts should exist at {dotnetDtsPath}");

DateTime firstWriteTime = File.GetLastWriteTime(dotnetDtsPath);

// Wait a moment to ensure different timestamps
Thread.Sleep(1100);

Check failure on line 360 in src/mono/wasm/Wasm.Build.Tests/Templates/WasmTemplateTests.cs

View check run for this annotation

Azure Pipelines / runtime (Build browser-wasm linux Release SingleThreaded_BuildOnly)

src/mono/wasm/Wasm.Build.Tests/Templates/WasmTemplateTests.cs#L360

src/mono/wasm/Wasm.Build.Tests/Templates/WasmTemplateTests.cs(360,13): error CS0103: (NETCORE_ENGINEERING_TELEMETRY=Build) The name 'Thread' does not exist in the current context

Check failure on line 360 in src/mono/wasm/Wasm.Build.Tests/Templates/WasmTemplateTests.cs

View check run for this annotation

Azure Pipelines / runtime

src/mono/wasm/Wasm.Build.Tests/Templates/WasmTemplateTests.cs#L360

src/mono/wasm/Wasm.Build.Tests/Templates/WasmTemplateTests.cs(360,13): error CS0103: (NETCORE_ENGINEERING_TELEMETRY=Build) The name 'Thread' does not exist in the current context

// Modify the template file to simulate an older version
File.WriteAllText(dotnetDtsPath, "// Old version\ninterface OldAPI { }");
DateTime modifiedTime = File.GetLastWriteTime(dotnetDtsPath);

// Second build should update the file
BuildProject(info, config, new BuildOptions());
DateTime secondWriteTime = File.GetLastWriteTime(dotnetDtsPath);

// Verify the file was updated (should be newer than our manual modification)
Assert.True(secondWriteTime > modifiedTime,
$"File should have been updated. First: {firstWriteTime}, Modified: {modifiedTime}, Second: {secondWriteTime}");

// Verify content was restored to proper TypeScript definitions
string content = File.ReadAllText(dotnetDtsPath);
Assert.Contains("interface DotnetHostBuilder", content);
Assert.DoesNotContain("Old version", content);
}
}
}
Loading
Loading