Создание шаблона проекта HTML-сайта в Visual Studio
У меня периодически возникает необходимость сделать простой html/js/css сайт, и я для себя сделал шаблон проекта простого html сайта. Этим проектом и методикой его создания хочу с вами поделиться.
Создаём на диске папку под проект будущего шаблона сайта.
Создаём или копируем первичное наполнение. У меня получилась вот такая структура из папок и файлов:

В Visual Studio открываем проект как WEB-сайт: FILE => Open => Web Site и указываем подготовленную папку:

При открытии сайта VS (Visual Studio) может предложить проапгрейдить проект до .NET Framework 4.8 (или другой, какой установлен) - соглашаемся, даже с учётом того, что никакого до этого не было:

На этом этапе в проект студией добавляется файл Web.config.
Сохраняем VS Solution для дальнейшей работы и переходим в проект. Не сохранять solution можно, но я бы строго не рекомендовал, если в дальнейшем планируете работать с этим проектом полноценно.

Наполняем необходимым для шаблона функционалом. Я «натянул» простенький bootstrap 5 html/js/css/ (тут @kustof/SimpleSiteTemplate всё видно )).
Можно добавить необходимый файл средствами VS. Давайте добавим файл стилей. Add=>Add New Item. Набор шаблонов в этом режиме ограничен, поэтому просто пишем имя файла сразу с расширением, или можно переключиться на компактный вид:


Также на этом этапе рекомендую добавить папки, которые вы планируете использовать в будущих проектах.
Преимущество такого типа шаблона проекта HTML-сайта, как я писал выше, что можно, как и с любым другим типом компилируемого проекта осуществлять сборку (Build), отладку (Debug) и т.д. Поэтому смело жмём Ctrl+F5. Сайт откроется в браузере по умолчанию, убеждаемся, что для шаблона всё работает хорошо, и переходим к следующему шагу.
Сейчас у нас только одна конфигурация проекта - Debug. Я обычно добавляю Release и Publish. Добавим для примера Release. BUILD => Configuration Manager, далее Active Solution Configuration => New => Добавляем конфигурацию с копированием настроек:

И получаем:

Добавим публикацию BUILD => Publish Web App. Я в итоге, пришёл к следующей конфигурации:

После первой публикации создаётся следующая ветка в solution’е:

Мы к ней ещё вернёмся.
Создаём шаблон из проекта (https://learn.microsoft.com/ru-ru/visualstudio/ide/how-to-create-project-templates?view=vs-2022). Делаем экспорт шаблона: PROJECT => EXPORT TEMPLATE, заполняем необходимые поля:

Если по первому скрину всё понятно, то по заполнению второго прокомментирую скрином ниже. Этот скрин сделал при добавлении нового проекта, выбора шаблона:
Template name - имя шаблона. При создании проекта отображается в поле под номером 1;
Template description - необязательное поле. Краткое описание шаблона. В скрине создания проекта под номером 2.
Icon Image-иконка шаблона. На скрине под номером 3.
Preview Image-иконка, символизирующая шаблон. Необязательное поле. Есть в старых версиях студии.
Automatically import the template into Visual Studio и Display an explorer window on the output files folder-соответственно автоматически импортировать шаблон, и открыть папку с готовым шаблоном.

Проект будет экспортирован в ZIP-файл и помещен в указанное выходное расположение, а также (если установлен соответствующий флажок) импортирован в Visual Studio.
Чтобы найти шаблон в диалоговом окне создания проекта, можно использовать поиск по имени или прокрутку списка.
Microsoft говорит: "Фильтрация на основе языка или типа проекта в настоящее время невозможна для пользовательских шаблонов". Но, есть нюансы.
Открываем ZIP-архив экспортированного шаблона и видим среди всего прочего файл MyTemplate.vstemplate. Переименовываем с названием шаблона - SimpleSite.vstemplate. Открываем, и видим среди прочего раздел такого вида:
<TemplateData>
<Name>SimpleSite</Name>
<Description>Simple HTML, CSS, JS Web Site. With Bootstrap template</Description>
<ProjectType>Web</ProjectType>
<ProjectSubType>CSharp</ProjectSubType>
<SortOrder>1000</SortOrder>
<CreateNewFolder>true</CreateNewFolder>
<DefaultName>SimpleSite</DefaultName>
<ProvideDefaultName>true</ProvideDefaultName>
<LocationField>Enabled</LocationField>
<EnableLocationBrowseButton>true</EnableLocationBrowseButton>
<Icon>__TemplateIcon.ico</Icon>
</TemplateData>
Такой он получается сгенерированный VS. Вносим в него свои коррективы:
<TemplateData>
<Name>SimpleSite</Name>
<Description>Simple HTML, CSS, JS Web Site. With Bootstrap template</Description>
<ProjectType>CSharp</ProjectType>
<ProjectSubType>Web</ProjectSubType>
<TemplateGroupID>Web</TemplateGroupID>
<SortOrder>1000</SortOrder>
<CreateNewFolder>true</CreateNewFolder>
<DefaultName>SimpleSite</DefaultName>
<ProvideDefaultName>true</ProvideDefaultName>
<LanguageTag>csharp</LanguageTag>
<PlatformTag>linux</PlatformTag>
<PlatformTag>macos</PlatformTag>
<ProjectTypeTag>web</ProjectTypeTag>
<LocationField>Enabled</LocationField>
<EnableLocationBrowseButton>true</EnableLocationBrowseButton>
<Icon>__TemplateIcon.ico</Icon>
<PreviewImage>__PreviewImage.jpeg</PreviewImage>
</TemplateData>
Теперь фильтрация на основе языка или типа проекта работает.
Есть несколько путей импортировать шаблон проекта в студию. Например:
Поставить галочку при экспорте шаблона (см. выше); Просто положить архив шаблона в папку \Documents\Visual Studio 2022\Templates\ProjectTemplates. Как тут указано;

Причём, в какую из вложенных папок вы положите, разницы на мой взгляд, нет. Я размещаю архив в корне.
Пробуем создать проект по шаблону:



Как видим всё создаётся, компилируется, в нужную папку публикуется, в браузере через IIS Express отображается:

Чего хотели, сделали!
Но делаем для себя же ). Само-собой разумеющееся работа сайта с JavaScript - значит будет разумным добавить поддержку TypeScript из коробки. Устанавливаем nuget пакет Microsoft.TypeScript.MSBuild, добавляем в корень проекта tsconfig.json, я добавил такое содержимое:
{
"compilerOptions": {
"noImplicitAny": false,
"noEmitOnError": true,
"removeComments": false,
"sourceMap": true,
"target": "ES2022",
"module": "ESNext",
"allowJs": false,
"moduleResolution": "Node",
"typeRoots": [ "wwwroot/lib/@types/" ],
"lib": [ "esnext", "dom" ]
},
"exclude": [
"node_modules",
"obj",
"bin"
],
"compileOnSave": true
}
Добавим ветку с TS файлом, добавим пару функций, компилируем, и убеждаемся, что JS файл генерируется:

Здорово! Облегчили себе жизнь при создании проектов HTML-сайтов.
Что мы можем сделать ещё? Использовать разрозненные и не минифицированные файлы js и css в настоящее время не комильфо, да и любой PageSpeed сразу заругается... Исправляем.
Ставим из магазина, если ещё не установлено расширение «Bundler & Minifier 2022+» (https://marketplace.visualstudio.com/items?itemName=Failwyn.BundlerMinifier64).
Правой кнопкой в solution на любом css или js файле => Bundler & Minifier => Minify File

Будет сгенерирована минифицированная версия файла, и добавлен файл bundleconfig.json с примерным содержимым:
[
{
"outputFileName": "assets/js/bundle.js",
"inputFiles": [
"assets/js/site.js",
"assets/js/site1.js"
],
"minify": {
"enabled": true,
"renameLocals": true
}
},
{
"outputFileName": "assets/css/bundle.css",
"inputFiles": [
"assets/css/site.css",
"assets/css/site1.css"
],
"minify": {
"enabled": true,
"renameLocals": true
}
}
]

А дальше делаем как нам требуется (читаем руководство).
Продолжаем совершенствовать наш шаблон.
При публикации убеждаемся, что всё компилируется, объединяется, минифицируется и падает в нужную папку, с нужными путями. Но! Падает всё подряд, что есть в проекте - служебные папки и файлы, файлы проекта и сборки, исходники... И даже если при публикации включена опция Delete Existing Files в папке Publish создаётся рекурсивная вложенность. А публикация подразумевает готовое приложение - только рабочие оптимизированные файлы и ничего лишнего. Займёмся тюнингом публикации. Открываем файл "App_Data\PublishProfiles\FolderProfile.pubxml". По умолчанию он выглядит примерно так:
<?xml version="1.0" encoding="utf-8"?>
<!-- https://go.microsoft.com/fwlink/?LinkID=208121. -->
<Project>
<PropertyGroup>
<DeleteExistingFiles>true</DeleteExistingFiles>
<ExcludeApp_Data>true</ExcludeApp_Data>
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
<LastUsedPlatform>Any CPU</LastUsedPlatform>
<LaunchSiteAfterPublish>true</LaunchSiteAfterPublish>
<PublishProvider>FileSystem</PublishProvider>
<PublishUrl>bin\Publish</PublishUrl>
<WebPublishMethod>FileSystem</WebPublishMethod>
<_TargetId>Folder</_TargetId>
<SiteUrlToLaunchAfterPublish />
<PrecompileBeforePublish>true</PrecompileBeforePublish>
<EnableUpdateable>true</EnableUpdateable>
<DebugSymbols>false</DebugSymbols>
<WDPMergeOption>DonotMerge</WDPMergeOption>
</PropertyGroup>
</Project>
В принципе то, что мы задали в диалоге настройки публикации. Сильно вдаваться не буду в детали, но методом «научного тыка» я пришёл к такому содержимому:
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project>
<PropertyGroup>
<DeleteExistingFiles>true</DeleteExistingFiles>
<ExcludeApp_Data>false</ExcludeApp_Data>
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
<LastUsedPlatform>Any CPU</LastUsedPlatform>
<LaunchSiteAfterPublish>true</LaunchSiteAfterPublish>
<PublishProvider>FileSystem</PublishProvider>
<PublishUrl>Publish</PublishUrl>
<WebPublishMethod>FileSystem</WebPublishMethod>
<_TargetId>Folder</_TargetId>
<SiteUrlToLaunchAfterPublish />
<!--Excluding-->
<ExcludeFilesFromDeployment>*.config;*.json;*.sln;**\*.ts;**\*.map;assets\js\site.js;assets\js\site1.js;assets\js\bundle.js;assets\css\site.css;assets\css\site1.css;assets\css\bundle.css;_vstemplate;SimpleSite.zip;</ExcludeFilesFromDeployment>
<ExcludeFoldersFromDeployment>packages;App_Data;Publish;</ExcludeFoldersFromDeployment>
<PrecompileBeforePublish>true</PrecompileBeforePublish>
<EnableUpdateable>true</EnableUpdateable>
<DebugSymbols>false</DebugSymbols>
<WDPMergeOption>DonotMerge</WDPMergeOption>
</PropertyGroup>
</Project>
В принципе всё понятно из тегов и директив. Единого полного руководства не нашёл, либо не работает, либо противоречит друг другу. Кто что посоветует - буду только рад.
Пробовал разные варианты публикации, остановился на этой схеме. Хочу обратить внимание - порядок имеет значение.
Собираем всё. Делаем экспорт шаблона. Любым способом редактируем файл *.vstemplate, импортируем в Visual Studio и наслаждаемся СВОИМ шаблоном проекта.
А мой вариант проекта разместил здесь. Там ещё до кучи накидал всего... кому будет интересно увидит. Также смотрите комментарии в файлах.