Как использовать npm с ASP.NET Core

119

Я использую npm для управления jQuery, Bootstrap, Font Awesome и аналогичными клиентскими библиотеками, которые мне нужны для моего приложения ASP.NET Core.

Подход, который сработал для меня, начался с добавления в проект файла package.json, который выглядит так:

{
    "version": "1.0.0",
    "name": "myapp",
    "private": true,
    "devDependencies": {
  },
  "dependencies": {
    "bootstrap": "^3.3.6",
    "font-awesome": "^4.6.1",
    "jquery": "^2.2.3"
  }
}

npm восстанавливает эти пакеты в папку node_modules, которая находится на том же уровне, что и wwwroot в каталоге проекта:

введите описание изображения здесь

Поскольку ASP.NET Core обслуживает статические файлы из папки wwwroot, а node_modules там нет, мне пришлось внести пару изменений, чтобы заставить эту работу, первое: добавление app.UseFileServer прямо перед app.UseStaticFiles в моем Startup. cs файл:

app.UseFileServer(new FileServerOptions()
{
    FileProvider = new PhysicalFileProvider(
        Path.Combine(Directory.GetCurrentDirectory(), @"node_modules")), 
    RequestPath = new PathString("/node_modules"),
    EnableDirectoryBrowsing = true
});

app.UseStaticFiles();

и второй, включая node_modules в моих publishOptions в файле project.json:

"publishOptions": {
  "include": [
    "web.config",
    "wwwroot",
    "Views",
    "node_modules"
  ]
},

Это работает в моей среде разработки, и это также работает, когда я развертываю его в своем экземпляре службы приложений Azure, статические файлы jquery, bootstrap и font-awesome обрабатываются хорошо, но я не уверен в этой реализации.

Как правильно это сделать?

Это решение появилось после сбора большого количества информации из нескольких источников и проверки некоторых из них, которые не работали, и кажется немного странным обслуживать эти файлы извне wwwroot.

Мы будем благодарны за любые советы.

Карлос Фигероа
источник
Может быть полезна ссылка: blog.nbellocam.me/2016/03/14/asp-net-core-and-angular-2
adem caglin
По этой ссылке есть рабочий пример на ASP.NET Core с npm : ievangelistblog.wordpress.com/2016/01/13/…
Дэвид Пайн,
2
Одна вещь, которая пришла мне в голову, - это использовать Bundler and Minifier- Укажите, что источник находится вне wwwroot, и когда вы создаете, он встраивает JS в wwwroot. Это правильный путь .. Вы не должны обслуживать контент из node_modules
Петр Кула,
Я бы настоятельно не рекомендовал никому статически обслуживать node_modulesпапку. а) экосистема спроектирована не так. б) это угроза безопасности, один из установленных пакетов может привести к утечке конфиденциальной информации. Правильный способ - настроить конвейер сборки (grunt / gulp / node / webpack), который публикует файлы в папку srcили, whateverпредназначенную для обслуживания статических файлов
внешнего интерфейса

Ответы:

45

Публикуя всю свою node_modulesпапку, вы развертываете гораздо больше файлов, чем вам действительно нужно в производственной среде.

Вместо этого используйте средство выполнения задач как часть процесса сборки, чтобы упаковать нужные файлы и развернуть их в своей wwwrootпапке. Это также позволит вам объединять и минимизировать ваши активы одновременно, вместо того, чтобы обслуживать каждую отдельную библиотеку отдельно.

Затем вы также можете полностью удалить FileServerконфигурацию и полагаться на UseStaticFilesнее.

В настоящее время предпочтительным средством выполнения задач VS является gulp. Добавьте gulpfile.jsв корень вашего проекта и настройте его для обработки ваших статических файлов при публикации.

Например, вы можете добавить следующий scriptsраздел в свой project.json:

 "scripts": {
    "prepublish": [ "npm install", "bower install", "gulp clean", "gulp min" ]
  },

Что будет работать со следующим gulpfile (по умолчанию при построении с помощью yo):

/// <binding Clean='clean'/>
"use strict";

var gulp = require("gulp"),
    rimraf = require("rimraf"),
    concat = require("gulp-concat"),
    cssmin = require("gulp-cssmin"),
    uglify = require("gulp-uglify");

var webroot = "./wwwroot/";

var paths = {
    js: webroot + "js/**/*.js",
    minJs: webroot + "js/**/*.min.js",
    css: webroot + "css/**/*.css",
    minCss: webroot + "css/**/*.min.css",
    concatJsDest: webroot + "js/site.min.js",
    concatCssDest: webroot + "css/site.min.css"
};

gulp.task("clean:js", function (cb) {
    rimraf(paths.concatJsDest, cb);
});

gulp.task("clean:css", function (cb) {
    rimraf(paths.concatCssDest, cb);
});

gulp.task("clean", ["clean:js", "clean:css"]);

gulp.task("min:js", function () {
    return gulp.src([paths.js, "!" + paths.minJs], { base: "." })
        .pipe(concat(paths.concatJsDest))
        .pipe(uglify())
        .pipe(gulp.dest("."));
});

gulp.task("min:css", function () {
    return gulp.src([paths.css, "!" + paths.minCss])
        .pipe(concat(paths.concatCssDest))
        .pipe(cssmin())
        .pipe(gulp.dest("."));
});

gulp.task("min", ["min:js", "min:css"]);
Носок
источник
36
Я немного запутался в том, как это ответ на вопрос. Это почти то же самое, что у Microsoft для настройки Gulp здесь ( docs.microsoft.com/en-us/aspnet/core/client-side/using-gulp ). Однако, насколько я могу судить, это не берет контент из моего каталога node_modules и не добавляет его в 'lib' или делает его пригодным для использования в любом из моих файлов ... Я очень новичок в этом, поэтому невероятно сбит с толку кажущимся невероятным новый сложный мир веб-разработки ...
Джерард Уилкинсон
34
Сложно хорошо. Готов вообще отказаться от фронтенда и просто работать над API.
Люк Пуплетт
12
В целом это правильный подход, но ответ не учитывает важный шаг: копирование файлов из папки node_modules в папку wwwroot в качестве задачи Gulp. Начните с var nodeRoot = './node_modules/'; и добавьте задачу, которая копирует нужную подпапку из nodeRoot в соответствующую подпапку webroot. Сейчас нет времени вдаваться в подробности, но, если есть интерес, я могу добавить подробности позже.
Дуг,
33
Почему никто не поднял очевидного: «Почему мы должны задавать этот вопрос!» Почему мы намеренно устанавливаем файлы в место, где их нельзя использовать? Затем, поскольку наши файлы недоступны, мы устанавливаем и настраиваем сложную утилиту, чтобы скопировать их в место, где они могут быть использованы. Это действительно смешно.
Сэм
8
Потому что инструменты здесь, по сути, дерьмо. Использование npm - это просто использование npm, как и все остальное . Нет ничего специфического для ASP.NET Core. Все идет, node_modulesпотому что это то, что делает npm. Задача gulp необходима для перемещения вещей в нужное место, то есть там, где они вам действительно нужны. Я думаю, проблема в том, что Microsoft предоставила такую ​​прекрасную интеграцию с Bower, но теперь Bower мертв (или, по крайней мере, умирает), а Microsoft не предоставила никаких альтернативных инструментов.
Крис Пратт
41

введите описание изображения здесь

  • Использование npmдля управления клиентскими библиотеками - хороший выбор (в отличие от Bower или NuGet), вы думаете в правильном направлении :)
  • Разделите серверные (ASP.NET Core) и клиентские (например, Angular 2, Ember, React) проекты на отдельные папки (в противном случае ваш проект ASP.NET может иметь много шума - модульные тесты для клиентского кода, node_modules папку, артефакты сборки и т. д.). Front-end разработчики, работающие в одной команде с вами, будут вам за это благодарны :)
  • Восстановите модули npm на уровне решения (аналогично тому, как вы восстанавливаете пакеты через NuGet, а не в папку проекта), таким образом вы можете иметь модульные и интеграционные тесты также в отдельной папке (в отличие от клиентских тестов JavaScript внутри вашего Проект ASP.NET Core).
  • Использование может не понадобиться FileServer, его StaticFilesдолжно быть достаточно для обслуживания статических файлов (.js, изображений и т. Д.)
  • Используйте Webpack для объединения вашего клиентского кода в один или несколько фрагментов (пакетов)
  • Вам может не понадобиться Gulp / Grunt, если вы используете сборщик модулей, такой как Webpack
  • Пишите сценарии автоматизации сборки на ES2015 + JavaScript (в отличие от Bash или PowerShell), они будут работать кросс-платформенно и будут более доступны для множества веб-разработчиков (в настоящее время все говорят на JavaScript)
  • Переименуйте wwwrootв public, иначе структура папок в веб-приложениях Azure будет запутанной ( D:\Home\site\wwwroot\wwwrootvs D:\Home\site\wwwroot\public)
  • Публикуйте только скомпилированные выходные данные в веб-приложениях Azure (никогда не отправляйте node_modulesна сервер веб-хостинга). См. tools/deploy.jsПример.

Посетите стартовый комплект ASP.NET Core на GitHub (отказ от ответственности: я автор)

Константин Таркус
источник
2
Хороший ответ, спасибо за вашу работу по предоставлению сообществу стартового набора!
Дэвид Пайн
7
В начале этого года я успешно создал огромное общедоступное приложение Angular для крупного британского бренда, но я даже не смог понять большую часть этого ответа. Я даже не могу начать изучать его, так как он повсюду. Буквально карьерный кризис.
Люк Пуплетт
это хорошее резюме того, что можно и чего нельзя делать при написании и управлении клиентскими скриптами и файлами. Сэкономил мое время и исследования. Престижность вам!
Sangeeta
К сожалению, Visual Studio (глупо ИМХО) обрабатывает каталог «wwwroot» специально, основываясь только на его имени, давая ему специальный значок «веб-корень» в обозревателе решений и помечая его содержимое как «Нет» по умолчанию, а не «Содержимое». . Если вы намерены поместить туда статически обслуживаемые файлы, и вы используете Visual Studio, вам, вероятно, следует оставить имя как «wwwroot». Я согласен, что это плохая репутация.
Jez
27

Установите Bundler и Minifier в расширения Visual Studio

Затем вы создаете bundleconfig.jsonи вводите следующее, например:

// Configure bundling and minification for the project.
// More info at https://go.microsoft.com/fwlink/?LinkId=808241
[
 {
    "outputFileName": "wwwroot/js/jquery.min.js",
    "inputFiles": [
      "node_modules/jquery/dist/jquery.js"
    ],
    // Optionally specify minification options
    "minify": {
      "enabled": true,
      "renameLocals": false
    },
    // Optionally generate .map file
    "sourceMap": false
  }
]

Таким образом, сборщик и минификатор (на основе gulp) имеют доступ к исходным файлам (которые должны быть исключены из Visual Studio, а также из GIT) и помещают их в wwwroot, как указано

только побочный эффект каждый раз, когда вы сохраняете, он запускает это (но вы можете настроить его для запуска вручную)

Петр Кула
источник
4
После того, как я увидел, что Бауэр мертв, и я больше не могу обновлять Bootstrap, не переключившись на NPM, это, похоже, мой любимый подход. Gulp или Webpack кажутся излишними по сравнению с этим простым решением, которое уже есть в последних шаблонах проектов MVC. Спасибо, что поделились!
Мэтт Сандерс
1
Как здесь обрабатывать изображения, на которые есть ссылки в css? У меня проблема с изображениями, которые все еще находятся в папке node_modules, где CSS и js были перемещены на www. Есть идеи, как это исправить?
VPP
1
Это IDE-агностик? Как это будет работать, если кто-то из вашей команды использует VS Code, и как это повлияет на конвейер сборки CD?
Джейкоб Штамм
Когда вы устанавливаете NuGet-пакет Bundler и Minifier, в документации говорится, что он внедряет цели сборки, которые запускаются во время сборки и очистки. Я полагаю, как только он будет установлен, он будет работать нормально независимо от того, какая IDE используется, верно? См. Больше: docs.microsoft.com/en-gb/aspnet/core/client-side/…
Ciaran Gallagher,
Сборщик полезен только для указания этих скриптов вне среды разработки. На моей странице _Layout мне все еще нужно вручную ссылаться на файлы JS и CSS, которые мне нужны, но папка node_modules находится за пределами веб-сайта ... поэтому я не думаю, что это решает проблему должным образом, вам все равно нужен сценарий Gulp для копирования над необходимыми файлами в мою папку wwwroot.
Ciaran Gallagher
21

Даю вам два ответа. npm в сочетании с другими инструментами является мощным средством, но требует некоторой работы для настройки. Если вы просто хотите загрузить некоторые библиотеки, вы можете вместо этого использовать диспетчер библиотек (выпущенный в Visual Studio 15.8).

NPM (продвинутый)

Сначала добавьте package.json в корень вашего проекта. Добавьте следующий контент:

{
  "version": "1.0.0",
  "name": "asp.net",
  "private": true,
  "devDependencies": {
    "gulp": "3.9.1",
    "del": "3.0.0"
  },
  "dependencies": {
    "jquery": "3.3.1",
    "jquery-validation": "1.17.0",
    "jquery-validation-unobtrusive": "3.2.10",
    "bootstrap": "3.3.7"
  }
}

Это заставит NPM загрузить Bootstrap, JQuery и другие библиотеки, которые используются в новом основном проекте asp.net, в папку с именем node_modules. Следующим шагом является копирование файлов в подходящее место. Для этого мы будем использовать gulp, который также был загружен NPM. Затем добавьте новый файл в корень вашего проекта с именем gulpfile.js . Добавьте следующий контент:

/// <binding AfterBuild='default' Clean='clean' />
/*
This file is the main entry point for defining Gulp tasks and using Gulp plugins.
Click here to learn more. http://go.microsoft.com/fwlink/?LinkId=518007
*/

var gulp = require('gulp');
var del = require('del');

var nodeRoot = './node_modules/';
var targetPath = './wwwroot/lib/';

gulp.task('clean', function () {
    return del([targetPath + '/**/*']);
});

gulp.task('default', function () {
    gulp.src(nodeRoot + "bootstrap/dist/js/*").pipe(gulp.dest(targetPath + "/bootstrap/dist/js"));
    gulp.src(nodeRoot + "bootstrap/dist/css/*").pipe(gulp.dest(targetPath + "/bootstrap/dist/css"));
    gulp.src(nodeRoot + "bootstrap/dist/fonts/*").pipe(gulp.dest(targetPath + "/bootstrap/dist/fonts"));

    gulp.src(nodeRoot + "jquery/dist/jquery.js").pipe(gulp.dest(targetPath + "/jquery/dist"));
    gulp.src(nodeRoot + "jquery/dist/jquery.min.js").pipe(gulp.dest(targetPath + "/jquery/dist"));
    gulp.src(nodeRoot + "jquery/dist/jquery.min.map").pipe(gulp.dest(targetPath + "/jquery/dist"));

    gulp.src(nodeRoot + "jquery-validation/dist/*.js").pipe(gulp.dest(targetPath + "/jquery-validation/dist"));

    gulp.src(nodeRoot + "jquery-validation-unobtrusive/dist/*.js").pipe(gulp.dest(targetPath + "/jquery-validation-unobtrusive"));
});

Этот файл содержит код JavaScript, который выполняется при сборке и очистке проекта. Он скопирует все необходимые файлы в lib2 ( не в lib - вы можете легко это изменить ). Я использовал ту же структуру, что и в новом проекте, но легко изменить файлы в другое место. Если вы перемещаете файлы, убедитесь, что вы также обновили _Layout.cshtml . Обратите внимание, что все файлы в каталоге lib2 будут удалены при очистке проекта.

Если вы щелкнете правой кнопкой мыши на gulpfile.js , вы можете выбрать Task Runner Explorer . Отсюда вы можете запустить gulp вручную, чтобы скопировать или очистить файлы.

Gulp также может быть полезен для других задач, таких как минимизация файлов JavaScript и CSS:

https://docs.microsoft.com/en-us/aspnet/core/client-side/using-gulp?view=aspnetcore-2.1

Менеджер библиотеки (простой)

Щелкните правой кнопкой мыши проект и выберите « Управление клиентскими библиотеками» . Теперь открыт файл libman.json . В этом файле вы указываете, какую библиотеку и файлы использовать и где они должны храниться локально. Действительно просто! Следующий файл копирует библиотеки по умолчанию, которые используются при создании нового проекта ASP.NET Core 2.1:

{
  "version": "1.0",
  "defaultProvider": "cdnjs",
  "libraries": [
    {
      "library": "jquery@3.3.1",
      "files": [ "jquery.js", "jquery.min.map", "jquery.min.js" ],
      "destination": "wwwroot/lib/jquery/dist/"
    },
    {
      "library": "jquery-validate@1.17.0",
      "files": [ "additional-methods.js", "additional-methods.min.js", "jquery.validate.js", "jquery.validate.min.js" ],
      "destination": "wwwroot/lib/jquery-validation/dist/"
    },
    {
      "library": "jquery-validation-unobtrusive@3.2.10",
      "files": [ "jquery.validate.unobtrusive.js", "jquery.validate.unobtrusive.min.js" ],
      "destination": "wwwroot/lib/jquery-validation-unobtrusive/"
    },
    {
      "library": "twitter-bootstrap@3.3.7",
      "files": [
        "css/bootstrap.css",
        "css/bootstrap.css.map",
        "css/bootstrap.min.css",
        "css/bootstrap.min.css.map",
        "css/bootstrap-theme.css",
        "css/bootstrap-theme.css.map",
        "css/bootstrap-theme.min.css",
        "css/bootstrap-theme.min.css.map",
        "fonts/glyphicons-halflings-regular.eot",
        "fonts/glyphicons-halflings-regular.svg",
        "fonts/glyphicons-halflings-regular.ttf",
        "fonts/glyphicons-halflings-regular.woff",
        "fonts/glyphicons-halflings-regular.woff2",
        "js/bootstrap.js",
        "js/bootstrap.min.js",
        "js/npm.js"
      ],
      "destination": "wwwroot/lib/bootstrap/dist"
    },
    {
      "library": "list.js@1.5.0",
      "files": [ "list.js", "list.min.js" ],
      "destination": "wwwroot/lib/listjs"
    }
  ]
}

Если вы перемещаете файлы, убедитесь, что вы также обновили _Layout.cshtml .

ПЭК
источник
2
Менеджер библиотеки - никогда о нем не слышал, но это именно то, что мне нужно! Это должен быть правильный ответ.
codeMonkey
1
Чтобы избежать ошибки gulp, мне пришлось изменить первую строку задачи по умолчанию в файле gulpfile.jsна, gulp.task('default', function (done) {а затем добавить в качестве последней строки в этой функции следующее: done();В противном случае я бы получил сообщение об ошибкеThe following tasks did not complete: Did you forget to signal async completion?
Манфред
7

Вместо того, чтобы пытаться обслуживать папку модулей узлов, вы также можете использовать Gulp для копирования того, что вам нужно, в wwwroot.

https://docs.asp.net/en/latest/client-side/using-gulp.html

Это тоже может помочь

Visual Studio 2015 ASP.NET 5, задача Gulp не копирует файлы из node_modules

Dave_750
источник
4
Мне вторая ссылка очень нравится, вроде как-то знакомо. ;)
Дэвид Пайн
1
Это не очень удобно, когда вы смешиваете исходные файлы веб-приложения ASP.NET Core с модулями npm и выводом сборки кода на стороне клиента. Вот почему команда ASP.NET удаляет Gulp, package.json из стандартных шаблонов проектов ASP.NET MVC.
Константин Таркус
Я не знал этого. Когда я был в VS Live в марте, они все были об этом, но с тех пор многое изменилось.
Dave_750
6

Как правильно это сделать?

Существует множество «правильных» подходов, вам просто нужно решить, какой из них лучше всего соответствует вашим потребностям. Похоже, вы не понимаете, как использовать node_modules...

Если вы знакомы с NuGet, вам следует рассматривать npm как его клиентскую копию. Где node_modulesкаталог похож на binкаталог для NuGet . Идея состоит в том, что этот каталог - просто обычное место для хранения пакетов, на мой взгляд, лучше взять dependencyнужные вам пакеты, как вы это сделали в каталоге package.json. Затем используйте средство запуска задач, Gulpнапример, чтобы скопировать нужные файлы в желаемое wwwrootместо.

Еще в январе я написал в блоге об этом сообщение, в котором подробно описаны npm , Gulp и множество других деталей, которые актуальны и сегодня. Вдобавок кто-то обратил внимание на мой вопрос SO, который я задал, и в конечном итоге ответил себе здесь , что, вероятно, полезно.

Я создал файл, Gistкоторый показывает в gulpfile.jsкачестве примера.

В вашем Startup.csпо-прежнему важно использовать статические файлы:

app.UseStaticFiles();

Это гарантирует, что ваше приложение сможет получить доступ к тому, что ему нужно.

Дэвид Пайн
источник
3
«В январе я написал об этом сообщение в блоге, в котором подробно описаны npm, Gulp и множество других деталей, которые актуальны и сегодня». тот факт, что с января по июнь, и вы должны упомянуть, по-прежнему актуален, как раз и является моей проблемой с потрудиться над изучением чего-либо из этих однодневок. Я уже слишком многому научился, не тратя время на моду. Не твоя вина, Дэвид, ты мне очень помог, но мне не нравится этот эфемерный новый мир.
Люк Пуплетт,
5

Намного более простой подход - использовать пакет Nuget OdeToCode.UseNodeModules. Я только что тестировал его с .Net Core 3.0. Все, что вам нужно сделать, это добавить пакет в решение и указать его в методе Configure класса Startup:

app.UseNodeModules();

Я узнал об этом из отличного курса « Создание веб-приложения с ASP.NET Core, MVC, Entity Framework Core, Bootstrap и Angular Pluralsight» Шона Вильдермута.

Мариуш Бялобжески
источник
1
А как добавить пакеты npm?
Luca Ziegler
Есть несколько способов добавить в проект пакеты npm. Я предпочитаю просто вводить их в файл package.json в узле dependencies, как описано здесь: stackoverflow.com/a/49264424/5301317
Мариуш
@MariuszBialobrzeski Спасибо, что поделились. Это отличное решение.
Sau001
@MariuszBialobrzeski Приходилось ли вам делать что-нибудь дополнительно для развертывания статического контента из node_modules в ваших конвейерах DevOps? Или вы проверяли папку node_modules?
Sau001
1
@ Sau001 К сожалению, мне не довелось поработать с конвейерами DevOps. Папка node_modules имеет тенденцию становиться довольно большой, поэтому я бы определенно избегал ее проверки, если это возможно.
Мариуш Бялобжески
1

У Шона Вильдермута есть хорошее руководство: https://wildermuth.com/2017/11/19/ASP-NET-Core-2-0-and-the-End-of-Bower

В статье есть ссылка на gulpfile на GitHub, где он реализовал стратегию, описанную в статье. Вы можете просто скопировать и вставить большую часть содержимого gulpfile в свой, но обязательно добавьте соответствующие пакеты в package.json в devDependencies: gulp gulp-uglify gulp-concat rimraf merge-stream

Эндрю Боза
источник
1

Я нашел лучший способ управления пакетами JS в моем проекте с помощью средств запуска задач NPM Gulp / Grunt. Мне не нравится идея иметь NPM с другим уровнем библиотеки javascript для обработки «автоматизации», и мое требование номер один - просто запустить обновление npm без каких-либо других забот, если мне нужно запустить gulp. если он успешно все скопировал и наоборот.

Способ NPM:

  • Минификатор JS уже включен в ядро ​​ASP.net, ищите bundleconfig.json, так что для меня это не проблема (не компилировать что-то нестандартное)
  • Преимущество NPM в том, что у него хорошая файловая структура, поэтому я всегда могу найти предварительно скомпилированные / минифицированные версии зависимостей в node_modules / module / dist.
  • Я использую сценарий NPM node_modules / .hooks / {eventname}, который обрабатывает копирование / обновление / удаление файлов Project / wwwroot / lib / module / dist / .js, вы можете найти документацию здесь https: // docs.npmjs.com/misc/scriptsобновлю скрипт, который использую, до git, когда он станет более доработанным) Мне не нужны дополнительные средства выполнения задач ( инструменты .js, которые мне не нравятся) что делает мой проект чистым и простым.

Путь питона:

https://pypi.python.org/pyp ... но в этом случае вам нужно поддерживать источники вручную

Питер Хубек
источник
1

Прошу прощения за объем этой публикации.

Это рабочий пример с использованием ASP.NET Core версии 2.5.

Следует отметить, что project.json устарел ( см. Здесь ) в пользу .csproj . Проблема с .csproj . file - это большое количество функций и тот факт, что для его документации нет централизованного расположения ( см. здесь ).

Еще одна вещь: в этом примере выполняется ядро ​​ASP.NET в контейнере Docker Linux (alpine 3.9); так что пути будут отражать это. Он также использует gulp ^ 4.0. Однако с некоторыми изменениями он должен работать со старыми версиями ASP.NET Core, Gulp, NodeJS, а также без Docker.

Но вот ответ:

gulpfile.js см. реальный рабочий пример здесь

// ROOT and OUT_DIR are defined in the file above. The OUT_DIR value comes from .NET Core when ASP.net us built.
const paths = {
    styles: {
        src: `${ROOT}/scss/**/*.scss`,
        dest: `${OUT_DIR}/css`
    },
    bootstrap: {
        src: [
            `${ROOT}/node_modules/bootstrap/dist/css/bootstrap.min.css`,
            `${ROOT}/node_modules/startbootstrap-creative/css/creative.min.css`
        ],
        dest: `${OUT_DIR}/css`
    },
    fonts: {// enter correct paths for font-awsome here.
        src: [
            `${ROOT}/node_modules/fontawesome/...`,
        ],
        dest: `${OUT_DIR}/fonts`
    },
    js: {
        src: `${ROOT}/js/**/*.js`,
        dest: `${OUT_DIR}/js`
    },
    vendorJs: {
        src: [
            `${ROOT}/node_modules/jquery/dist/jquery.min.js`
            `${ROOT}/node_modules/bootstrap/dist/js/bootstrap.min.js`
        ],
        dest: `${OUT_DIR}/js`
    }
};

// Copy files from node_modules folder to the OUT_DIR.
let fonts = () => {
    return gulp
        .src(paths.styles.src)
        .pipe(gulp.dest(paths.styles.dest));
};

// This compiles all the vendor JS files into one, jsut remove the concat to keep them seperate.
let vendorJs = () => {
    return gulp
        .src(paths.vendorJs.src)
        .pipe(concat('vendor.js'))
        .pipe(gulp.dest(paths.vendorJs.dest));
}

// Build vendorJs before my other files, then build all other files in parallel to save time.
let build = gulp.series(vendorJs, gulp.parallel(js, styles, bootstrap));

module.exports = {// Only add what we intend to use externally.
    default: build,
    watch
};

Добавьте цель в файл .csproj . Обратите внимание, что мы также добавили Watch, чтобы отслеживать и исключать, если мы воспользуемся dotnet run watchкомандой.

app.csprod

  <ItemGroup>
    <Watch Include="gulpfile.js;js/**/*.js;scss/**/*.scss" Exclude="node_modules/**/*;bin/**/*;obj/**/*" />
  </ItemGroup>

  <Target Name="BuildFrontend" BeforeTargets="Build">
    <Exec Command="yarn install" />
    <Exec Command="yarn run build -o $(OutputPath)" />
  </Target>

Теперь, когда dotnet run buildон запущен, он также установит и построит модули узлов.

b01
источник