Skip to content

Commit be2dde3

Browse files
authored
feat(sdk): add template support for project and item templates (#29)
* feat(sdk): add template support for project and item templates Add MSBuild-based support for including VS project and item templates in VSIX packages, bypassing the broken VSIX Manifest Designer. New item types: - VsixProjectTemplate: folder-based project templates - VsixItemTemplate: folder-based item templates - VsixTemplateZip: pre-built template zip files - VsixTemplateReference: reference templates from another project Features: - Auto-discovery of templates in ProjectTemplates/ and ItemTemplates/ - Auto-zip folder-based templates during build - Hook into VSSDK's GetVsixSourceItems for VSIX inclusion - Build warnings for missing manifest Content entries (VSIXSDK010-014) Includes documentation in docs/templates.md. Closes #21 Closes #22 * feat(samples): add SampleExtensionWithTemplates sample project - Add sample extension demonstrating VS template support - Include project template (SampleProjectTemplate) - Include item template (SampleItemTemplate) - Fix VSSDK1079 error by removing invalid InstallRoot metadata Closes #23
1 parent 6a6b4d6 commit be2dde3

13 files changed

Lines changed: 731 additions & 0 deletions

File tree

docs/templates.md

Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
# Template Support
2+
3+
This document explains how to include Visual Studio project templates and item templates in your VSIX extension using CodingWithCalvin.VsixSdk.
4+
5+
## Background
6+
7+
The built-in VSIX Manifest Designer in Visual Studio cannot enumerate SDK-style projects when adding template assets. This is because the designer uses legacy DTE extenders that are registered for the old project system, not the Common Project System (CPS) used by SDK-style projects.
8+
9+
Additionally, SDK-style projects don't define the `TemplateProjectOutputGroup` and `ItemTemplateOutputGroup` MSBuild output groups that VSSDK expects for template assets.
10+
11+
This SDK provides MSBuild-based template support that bypasses these limitations entirely.
12+
13+
## Item Types
14+
15+
The SDK provides four item types for including templates:
16+
17+
| Item Type | Description |
18+
|-----------|-------------|
19+
| `VsixProjectTemplate` | A folder containing a `.vstemplate` file for a project template |
20+
| `VsixItemTemplate` | A folder containing a `.vstemplate` file for an item template |
21+
| `VsixTemplateZip` | A pre-built template zip file |
22+
| `VsixTemplateReference` | Reference a template folder from another project |
23+
24+
## Auto-Discovery
25+
26+
By default, the SDK automatically discovers templates in your project:
27+
28+
- **Project templates**: Any subfolder in `ProjectTemplates/` containing a `.vstemplate` file
29+
- **Item templates**: Any subfolder in `ItemTemplates/` containing a `.vstemplate` file
30+
31+
### Example Project Structure
32+
33+
```
34+
MyExtension/
35+
MyExtension.csproj
36+
source.extension.vsixmanifest
37+
ProjectTemplates/
38+
MyProjectTemplate/
39+
MyProjectTemplate.vstemplate
40+
MyProject.csproj
41+
Class1.cs
42+
ItemTemplates/
43+
MyItemTemplate/
44+
MyItemTemplate.vstemplate
45+
MyClass.cs
46+
```
47+
48+
With this structure, no additional configuration is needed. The SDK will:
49+
1. Find the templates automatically
50+
2. Zip each template folder during build
51+
3. Include the zips in the VSIX at `ProjectTemplates/` and `ItemTemplates/`
52+
53+
### Disabling Auto-Discovery
54+
55+
To disable automatic template discovery:
56+
57+
```xml
58+
<PropertyGroup>
59+
<EnableDefaultVsixTemplateItems>false</EnableDefaultVsixTemplateItems>
60+
</PropertyGroup>
61+
```
62+
63+
### Changing Default Folders
64+
65+
To use different folder names:
66+
67+
```xml
68+
<PropertyGroup>
69+
<VsixProjectTemplatesFolder>Templates\Projects</VsixProjectTemplatesFolder>
70+
<VsixItemTemplatesFolder>Templates\Items</VsixItemTemplatesFolder>
71+
</PropertyGroup>
72+
```
73+
74+
## Manual Template Configuration
75+
76+
### Folder-Based Templates
77+
78+
If your templates are in non-standard locations, add them explicitly:
79+
80+
```xml
81+
<ItemGroup>
82+
<VsixProjectTemplate Include="MyTemplates\ConsoleApp" />
83+
<VsixItemTemplate Include="MyTemplates\NewClass" />
84+
</ItemGroup>
85+
```
86+
87+
### Pre-Built Template Zips
88+
89+
If you have pre-built template zip files:
90+
91+
```xml
92+
<ItemGroup>
93+
<VsixTemplateZip Include="Templates\MyTemplate.zip" TemplateType="Project" />
94+
<VsixTemplateZip Include="Templates\MyItem.zip" TemplateType="Item" />
95+
</ItemGroup>
96+
```
97+
98+
### Template References
99+
100+
To include a template from another project in your solution:
101+
102+
```xml
103+
<ItemGroup>
104+
<VsixTemplateReference Include="..\MyTemplateProject\MyTemplateProject.csproj"
105+
TemplateType="Project"
106+
TemplatePath="Templates\MyProjectTemplate" />
107+
</ItemGroup>
108+
```
109+
110+
The `TemplatePath` is relative to the referenced project's directory.
111+
112+
## Manifest Configuration
113+
114+
Visual Studio requires `<Content>` entries in your `.vsixmanifest` to register templates. Add these to your manifest:
115+
116+
```xml
117+
<Content>
118+
<ProjectTemplate Path="ProjectTemplates" />
119+
<ItemTemplate Path="ItemTemplates" />
120+
</Content>
121+
```
122+
123+
The SDK will emit warnings if you have templates defined but missing manifest entries:
124+
- **VSIXSDK011**: Project templates defined but no `<ProjectTemplate>` in manifest
125+
- **VSIXSDK012**: Item templates defined but no `<ItemTemplate>` in manifest
126+
127+
## Target Subfolders
128+
129+
To organize templates into subfolders within the VSIX:
130+
131+
```xml
132+
<ItemGroup>
133+
<!-- Will be placed at ProjectTemplates/CSharp/ -->
134+
<VsixProjectTemplate Include="ProjectTemplates\MyTemplate" TargetSubPath="CSharp" />
135+
136+
<!-- Will be placed at ItemTemplates/Web/ -->
137+
<VsixItemTemplate Include="ItemTemplates\MyItem" TargetSubPath="Web" />
138+
</ItemGroup>
139+
```
140+
141+
## Complete Example
142+
143+
### Project File
144+
145+
```xml
146+
<Project Sdk="CodingWithCalvin.VsixSdk/1.0.0">
147+
148+
<PropertyGroup>
149+
<Version>1.0.0</Version>
150+
</PropertyGroup>
151+
152+
<!-- Templates are auto-discovered, but you can add more explicitly -->
153+
<ItemGroup>
154+
<VsixTemplateReference Include="..\SharedTemplates\SharedTemplates.csproj"
155+
TemplateType="Project"
156+
TemplatePath="Templates\SharedProject" />
157+
</ItemGroup>
158+
159+
</Project>
160+
```
161+
162+
### Manifest File
163+
164+
```xml
165+
<?xml version="1.0" encoding="utf-8"?>
166+
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011">
167+
<Metadata>
168+
<Identity Id="MyExtension" Version="1.0.0" Language="en-US" Publisher="MyCompany" />
169+
<DisplayName>My Extension</DisplayName>
170+
<Description>Extension with templates</Description>
171+
</Metadata>
172+
<Installation>
173+
<InstallationTarget Id="Microsoft.VisualStudio.Community" Version="[17.0,19.0)">
174+
<ProductArchitecture>amd64</ProductArchitecture>
175+
</InstallationTarget>
176+
</Installation>
177+
<Content>
178+
<ProjectTemplate Path="ProjectTemplates" />
179+
<ItemTemplate Path="ItemTemplates" />
180+
</Content>
181+
</PackageManifest>
182+
```
183+
184+
### Template File (.vstemplate)
185+
186+
```xml
187+
<?xml version="1.0" encoding="utf-8"?>
188+
<VSTemplate Version="3.0.0" Type="Project" xmlns="http://schemas.microsoft.com/developer/vstemplate/2005">
189+
<TemplateData>
190+
<Name>My Project Template</Name>
191+
<Description>A sample project template</Description>
192+
<Icon>__TemplateIcon.ico</Icon>
193+
<ProjectType>CSharp</ProjectType>
194+
<DefaultName>MyProject</DefaultName>
195+
<ProvideDefaultName>true</ProvideDefaultName>
196+
</TemplateData>
197+
<TemplateContent>
198+
<Project File="MyProject.csproj" ReplaceParameters="true">
199+
<ProjectItem ReplaceParameters="true">Class1.cs</ProjectItem>
200+
</Project>
201+
</TemplateContent>
202+
</VSTemplate>
203+
```
204+
205+
## Validation Warnings
206+
207+
| Code | Description |
208+
|------|-------------|
209+
| VSIXSDK010 | `VsixTemplateZip` item missing `TemplateType` metadata |
210+
| VSIXSDK011 | Project templates defined but no `<ProjectTemplate>` in manifest |
211+
| VSIXSDK012 | Item templates defined but no `<ItemTemplate>` in manifest |
212+
| VSIXSDK013 | `VsixTemplateReference` item missing `TemplateType` metadata |
213+
| VSIXSDK014 | `VsixTemplateReference` item missing `TemplatePath` metadata |
214+
215+
## Troubleshooting
216+
217+
### Templates not appearing in Visual Studio
218+
219+
1. Ensure your manifest has the appropriate `<Content>` entries
220+
2. Check that the template zip files are included in the VSIX (open the .vsix as a zip)
221+
3. Verify the `.vstemplate` file has correct `<ProjectType>` or `<TemplateGroupID>`
222+
4. Reset the Visual Studio template cache: delete `%LocalAppData%\Microsoft\VisualStudio\<version>\ComponentModelCache`
223+
224+
### Build errors about missing template folders
225+
226+
Ensure the template folder exists and contains a `.vstemplate` file. For `VsixTemplateReference`, verify the `TemplatePath` is correct relative to the referenced project.
227+
228+
### Templates in wrong location in VSIX
229+
230+
Check the `TargetSubPath` metadata if you're using custom paths. By default, templates are placed directly in `ProjectTemplates/` or `ItemTemplates/`.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
namespace $rootnamespace$;
2+
3+
/// <summary>
4+
/// Sample class created from item template.
5+
/// </summary>
6+
public class $fileinputname$
7+
{
8+
public $fileinputname$()
9+
{
10+
}
11+
12+
public void DoSomething()
13+
{
14+
// TODO: Implement your logic here
15+
}
16+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<VSTemplate Version="3.0.0" Type="Item" xmlns="http://schemas.microsoft.com/developer/vstemplate/2005">
3+
<TemplateData>
4+
<Name>Sample Class</Name>
5+
<Description>A sample class item template</Description>
6+
<ProjectType>CSharp</ProjectType>
7+
<SortOrder>10</SortOrder>
8+
<DefaultName>SampleClass.cs</DefaultName>
9+
</TemplateData>
10+
<TemplateContent>
11+
<ProjectItem ReplaceParameters="true" TargetFileName="$fileinputname$.cs">SampleClass.cs</ProjectItem>
12+
</TemplateContent>
13+
</VSTemplate>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
namespace $safeprojectname$;
2+
3+
class Program
4+
{
5+
static void Main(string[] args)
6+
{
7+
Console.WriteLine("Hello from $safeprojectname$!");
8+
}
9+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net8.0</TargetFramework>
6+
<RootNamespace>$safeprojectname$</RootNamespace>
7+
<AssemblyName>$safeprojectname$</AssemblyName>
8+
<ImplicitUsings>enable</ImplicitUsings>
9+
<Nullable>enable</Nullable>
10+
</PropertyGroup>
11+
12+
</Project>
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<VSTemplate Version="3.0.0" Type="Project" xmlns="http://schemas.microsoft.com/developer/vstemplate/2005">
3+
<TemplateData>
4+
<Name>Sample Console App</Name>
5+
<Description>A sample console application project template</Description>
6+
<ProjectType>CSharp</ProjectType>
7+
<SortOrder>1000</SortOrder>
8+
<DefaultName>SampleConsoleApp</DefaultName>
9+
<ProvideDefaultName>true</ProvideDefaultName>
10+
<CreateNewFolder>true</CreateNewFolder>
11+
<LocationField>Enabled</LocationField>
12+
<EnableLocationBrowseButton>true</EnableLocationBrowseButton>
13+
</TemplateData>
14+
<TemplateContent>
15+
<Project File="SampleProject.csproj" ReplaceParameters="true">
16+
<ProjectItem ReplaceParameters="true" TargetFileName="Program.cs">Class1.cs</ProjectItem>
17+
</Project>
18+
</TemplateContent>
19+
</VSTemplate>
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<!--
2+
For LOCAL DEVELOPMENT, this project uses Microsoft.NET.Sdk with
3+
Directory.Build.props/targets to add VSIX SDK behavior.
4+
5+
When published, users would use:
6+
<Project Sdk="CodingWithCalvin.VsixSdk/1.0.0">
7+
-->
8+
<Project Sdk="Microsoft.NET.Sdk">
9+
10+
<PropertyGroup>
11+
<TargetFramework>net472</TargetFramework>
12+
<Version>1.0.0</Version>
13+
<RootNamespace>SampleExtensionWithTemplates</RootNamespace>
14+
<AssemblyName>SampleExtensionWithTemplates</AssemblyName>
15+
</PropertyGroup>
16+
17+
<ItemGroup>
18+
<PackageReference Include="Microsoft.VisualStudio.SDK" Version="17.*" />
19+
</ItemGroup>
20+
21+
</Project>
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using System;
2+
using System.Runtime.InteropServices;
3+
using System.Threading;
4+
using Microsoft.VisualStudio.Shell;
5+
using Task = System.Threading.Tasks.Task;
6+
7+
namespace SampleExtensionWithTemplates
8+
{
9+
/// <summary>
10+
/// This is the class that implements the package exposed by this assembly.
11+
/// </summary>
12+
[PackageRegistration(UseManagedResourcesOnly = true, AllowsBackgroundLoading = true)]
13+
[Guid(PackageGuidString)]
14+
public sealed class SampleExtensionWithTemplatesPackage : AsyncPackage
15+
{
16+
/// <summary>
17+
/// SampleExtensionWithTemplatesPackage GUID string.
18+
/// </summary>
19+
public const string PackageGuidString = "b2c3d4e5-f6a7-8901-bcde-f23456789012";
20+
21+
/// <summary>
22+
/// Initialization of the package; this method is called right after the package is sited.
23+
/// </summary>
24+
protected override async Task InitializeAsync(CancellationToken cancellationToken, IProgress<ServiceProgressData> progress)
25+
{
26+
await base.InitializeAsync(cancellationToken, progress);
27+
28+
// When initialized asynchronously, switch to the main thread before accessing VS services
29+
await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
30+
31+
// This extension provides project and item templates
32+
// Templates are automatically discovered from ProjectTemplates/ and ItemTemplates/ folders
33+
}
34+
}
35+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011" xmlns:d="http://schemas.microsoft.com/developer/vsx-schema-design/2011">
3+
<Metadata>
4+
<Identity Id="SampleExtensionWithTemplates.b2c3d4e5-f6a7-8901-bcde-f23456789012" Version="1.0.0" Language="en-US" Publisher="Coding With Calvin" />
5+
<DisplayName>Sample Extension With Templates</DisplayName>
6+
<Description xml:space="preserve">A sample Visual Studio extension demonstrating template support with CodingWithCalvin.VsixSdk</Description>
7+
<MoreInfo>https://github.com/CodingWithCalvin/VsixSdk</MoreInfo>
8+
<Tags>sample, templates, vsix</Tags>
9+
</Metadata>
10+
<Installation>
11+
<InstallationTarget Id="Microsoft.VisualStudio.Community" Version="[17.0, 19.0)">
12+
<ProductArchitecture>amd64</ProductArchitecture>
13+
</InstallationTarget>
14+
<InstallationTarget Id="Microsoft.VisualStudio.Professional" Version="[17.0, 19.0)">
15+
<ProductArchitecture>amd64</ProductArchitecture>
16+
</InstallationTarget>
17+
<InstallationTarget Id="Microsoft.VisualStudio.Enterprise" Version="[17.0, 19.0)">
18+
<ProductArchitecture>amd64</ProductArchitecture>
19+
</InstallationTarget>
20+
</Installation>
21+
<Dependencies>
22+
<Dependency Id="Microsoft.Framework.NDP" DisplayName="Microsoft .NET Framework" d:Source="Manual" Version="[4.7.2,)" />
23+
</Dependencies>
24+
<Prerequisites>
25+
<Prerequisite Id="Microsoft.VisualStudio.Component.CoreEditor" Version="[17.0,19.0)" DisplayName="Visual Studio core editor" />
26+
</Prerequisites>
27+
<Assets>
28+
<Asset Type="Microsoft.VisualStudio.VsPackage" d:Source="Project" d:ProjectName="%CurrentProject%" Path="|%CurrentProject%;PkgDefProjectOutputGroup|" />
29+
</Assets>
30+
<Content>
31+
<ProjectTemplate Path="ProjectTemplates" />
32+
<ItemTemplate Path="ItemTemplates" />
33+
</Content>
34+
</PackageManifest>

0 commit comments

Comments
 (0)