如何在ASP.NET Core中使用npm


117

我正在使用npm管理ASP.NET Core应用程序所需的jQuery,Bootstrap,Font Awesome和类似的客户端库。

对我有用的方法是将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不存在,因此我必须进行一些更改才能使此工作生效,第一个:在Startup中的app.UseStaticFiles之前添加app.UseFileServer。 cs文件:

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

app.UseStaticFiles();

第二个,在project.json文件的publishOptions中包括node_modules:

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

这在我的开发环境中有效,当我将其部署到我的Azure App Service实例时也可以使用,可以很好地提供jquery,引导程序和超棒的静态文件,但是我不确定这种实现。

什么是正确的方法?

此解决方案是在从多个来源收集了大量信息并尝试了一些无效的信息之后得出的,而不得不从wwwroot外部提供这些文件似乎有些奇怪。

任何建议将不胜感激。



此链接有一个工作例如ASP.NET核心 W / NPMievangelistblog.wordpress.com/2016/01/13/...
大卫·派恩

2
我发生的一件事是-使用Bundler and Minifier-将源指定为外部wwwroot,并且在构建时将JS内置到wwwroot中。那是正确的方法。您不应该从node_modules提供内容
Piotr Kula

我强烈不鼓励任何人静态提供node_modules文件夹。a)这不是生态系统的设计方式b)这是安全隐患,您安装的软件包之一可能会泄漏敏感信息。正确的方法是建立一个构建管道(grunt / gulp / node / webpack),该管道将文件发布到专门用于服务静态前端文件的srcwhatever文件夹中
CervEd

Answers:


45

通过发布整个node_modules文件夹,您正在部署的文件将远远超过生产中实际需要的文件。

相反,在构建过程中使用任务运行器打包所需的文件,并将其部署到您的 wwwroot文件夹中。这也使您可以同时处理和最小化资产,而不必分别为每个单独的库提供服务。

然后,您也可以完全删除FileServer配置并依靠它UseStaticFiles

目前,gulp是VS任务运行程序的首选。将a添加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/zh-cn/aspnet/core/client-side/using-gulp)所具有的。但是据我所知,这不会从我的node_modules目录中获取内容并将其添加到“ lib”中或使其在我的任何文件中都可用...我对此非常陌生,因此似乎难以置信地令人困惑复杂的Web开发新世界……
Gerard Wilkinson

32
好复杂。我准备完全放弃前端,只使用API​​。
路加·普普利特

12
通常,这是正确的方法,但是答案却没有解决关键步骤:作为Gulp任务将文件从node_modules文件夹复制到wwwroot文件夹。以var nodeRoot ='./node_modules/'开始;并添加一个任务,该任务将所需的子文件夹从nodeRoot复制到webroot的相应子文件夹中。现在没有时间详细说明,但是如果有兴趣,我可以稍后添加细节。
道格

32
为什么没有人提出明显的理由:“为什么我们要问这个问题!” 为什么我们有意将文件安装在无法使用的位置?然后,由于无法访问我们的文件,因此我们安装并配置了详尽的实用程序以将其复制到可以使用它们的位置。它真的很荒谬。
山姆

8
因为这里的工具基本上是废话。就像使用任何东西一样,使用npm就是使用npm 。没有特定于ASP.NET Core的内容。一切都进入了,node_modules因为npm就是这样做的。gulp任务是将事物移到正确位置(即您实际需要的位置)所必需的。我认为问题在于Microsoft提供了与Bower如此完美的集成,但是现在Bower已经死了(或者至少快要死了),并且Microsoft没有提供任何替代工具。
克里斯·普拉特

41

在此处输入图片说明

  • 使用 npm管理客户端库是一个不错的选择(而不是鲍尔或的NuGet),你是在正确的方向思考:)
  • 将服务器端(ASP.NET Core)和客户端(例如Angular 2,Ember,React)项目拆分到单独的文件夹中(否则您的ASP.NET项目可能会有很多干扰-客户端代码,node_modules的单元测试文件夹,构建文物等)。与您在同一团队中工作的前端开发人员将对此表示感谢:)
  • 在解决方案级别还原npm模块(类似于通过NuGet还原软件包的方式-不在项目的文件夹中),通过这种方式,您还可以在单​​独的文件夹中进行单元和集成测试(而不是在您的内部进行客户端JavaScript测试) ASP.NET Core项目)。
  • 使用可能不需要FileServer,有StaticFiles只要提供静态文件(.js,图像等)就足够了
  • 使用Webpack将您的客户端代码捆绑为一个或多个块(捆绑)
  • 您可能不需要Gulp / Grunt如果使用的是Webpack等模块捆绑器,则
  • 使用ES2015 + JavaScript(与Bash或PowerShell相对)编写构建自动化脚本,它们将跨平台工作,并且可供各种Web开发人员访问(如今,每个人都讲JavaScript)
  • 重命名wwwrootpublic,否则Azure Web Apps中的文件夹结构将令人困惑(D:\Home\site\wwwroot\wwwrootvs D:\Home\site\wwwroot\public
  • 仅将编译后的输出发布到Azure Web Apps(永远不要推node_modules送到Web托管服务器)。参见tools/deploy.js示例。

在GitHub上访问ASP.NET Core入门工具包(免责声明:我是作者)


2
很好的答案,在为社区提供入门工具包方面所做的工作很荣幸!
David Pine

7
我今年早些时候成功为英国的一个主要品牌成功构建了一个大型公共Angular应用,但我什至无法理解大部分答案。我什至无法开始在各处学习它。从字面上看有职业危机。
路加·普普利特

这是在编写和管理客户端脚本和文件时做与不做的一个很好的总结。节省了我的时间和研究。恭喜您!
Sangeeta

不幸的是,Visual Studio(愚蠢的恕我直言)仅根据其名称对“ wwwroot”目录进行了特殊处理,在解决方案资源管理器中为其赋予了特殊的“ web root”图标,并默认将其内容标记为“ None”而不是“ Content” 。如果打算在其中放置静态提供的文件,并且您正在使用Visual Studio,则可能应将名称保留为“ wwwroot”。我同意这是一个坏名字。
耶斯,

27

安装捆绑器和粉碎机到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
在看到Bower死了并且无法切换到NPM之后我无法再更新Bootstrap之后,这似乎是我最喜欢的方法。与最新的MVC项目模板中已经存在的这种简单解决方案相比,Gulp或Webpack似乎过于矫kill过正。感谢你的分享!
马特·桑德斯

1
CSS中引用的图像如何在这里处理?我面临的问题是,图像仍保留在node_modules文件夹中,其中css和js已移至www。任何想法如何解决这个问题?
VPP

1
这与IDE无关吗?如果您的团队中的某些人正在使用VS Code,这将如何工作?它如何在CD制作管道中发挥作用?
Jacob Stamm '18

当您安装Bundler和Minifier NuGet软件包时,文档说它注入了在构建和清理时运行的构建目标。我想一旦安装到位,无论使用哪种IDE,它都可以正常工作,对吗?查看更多:docs.microsoft.com/en-gb/aspnet/core/client-side/...
夏兰加拉格尔

捆绑程序仅对在开发环境之外指定这些脚本有用。在我的_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将在新的asp.net核心项目中使用的Bootstrap,JQuery和其他库下载到名为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/zh-cn/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
为了避免产生错误,我必须将文件中默认任务的第一行更改gulpfile.jsgulp.task('default', function (done) {,然后在该函数中添加以下内容:done();否则,我将收到错误消息The following tasks did not complete: Did you forget to signal async completion?
Manfred

7

除了尝试提供节点模块文件夹之外,您还可以使用Gulp将所需的内容复制到wwwroot。

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

这可能也有帮助

Visual Studio 2015 ASP.NET 5,Gulp任务无法从node_modules复制文件


4
我真的很喜欢第二个链接,似乎有点陌生。;)
David Pine

1
将ASP.NET Core Web应用程序源文件与npm模块和客户端代码生成输出混合使用时,这不是很方便。这就是ASP.NET团队从默认ASP.NET MVC项目模板中删除Gulp,package.json的原因。
康斯坦丁·塔尔库斯

我不知道。当我在三月份参加VS Live时,他们都在关注它,但是自那时以来,它发生了很大变化。
Dave_750 '16

6

什么是正确的方法?

有很多“正确”的方法,您只需确定最适合您的需求的方法即可。似乎您误会了如何使用node_modules...

如果您熟悉NuGet,则应将npm视为其客户端对应对象。该node_modules目录类似于NuGetbin目录。想法是,该目录只是用于存储软件包的公共位置,我认为最好像上那样处理需要的软件包。然后,例如使用任务运行程序将所需的文件复制到所需的位置。dependencypackage.jsonGulpwwwroot

我在一月份写了一篇关于此的博客文章,其中详细介绍了npmGulp以及今天仍然有用的许多其他细节。此外,有人呼吁关注我提出的我的SO问题,并最终在这里回答了我自己,这可能会有所帮助。

我创建了一个Gist以显示gulpfile.js为例。

在您中Startup.cs,使用静态文件仍然很重要:

app.UseStaticFiles();

这将确保您的应用程序可以访问所需的内容。


3
“我在一月份写了一篇有关此事的博客文章,其中详细介绍了npm,Gulp以及今天仍然有用的许多其他细节。” 从一月到六月,您仍然要提到的事实仍然是有意义的,这正是我不愿学习任何这种夜间学习的问题。我已经学到了太多东西,又不浪费时间在时装上。不是您的错,大卫,您提供的帮助很大,但是我不喜欢这个短暂的新世界。
路加·普普利特

5

更简单的方法是使用OdeToCode.UseNodeModules Nuget包。我刚刚使用.Net Core 3.0进行了测试。您需要做的就是将包添加到解决方案中,并在Startup类的Configure方法中引用它:

app.UseNodeModules();

我从Shawn Wildermuth撰写的出色的《使用ASP.NET Core,MVC,Entity Framework Core,Bootstrap和Angular Pluralsight构建课程》中了解到了这一点。


1
以及如何添加npm软件包?
卡·齐格勒

有几种方法可以将npm软件包添加到您的项目中。我更喜欢只在依赖关系节点下的package.json文件中键入它们,如下所述:stackoverflow.com/a/49264424/5301317
Mariusz Bialobrzeski

@MariuszBialobrzeski感谢您的分享。这是一个很好的解决方案。
Sau001

@MariuszBialobrzeski是否需要执行其他任何操作才能从DevOps管道中的node_modules部署静态内容?还是您签入了node_modules文件夹?
Sau001,

1
@ Sau001不幸的是,我从未有过使用DevOps管道的机会。node_modules文件夹往往会变得很大,因此,如果可能的话,我绝对会避免将其检入。
Mariusz Bialobrzeski


1

我找到了一种更好的方法来与NPM Gulp / Grunt任务运行器一起管理项目中的JS软件包。我不喜欢让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工具)是什么让我的项目干净简单。

python方式:

https://pypi.python.org/pyp ...但是在这种情况下,您需要手动维护源


1

请原谅这篇文章的长度。

这是使用ASP.NET Core 2.5版的有效示例。

需要注意的是project.json已过时(请参阅此处),而支持.csproj.csproj的问题。文件是大量功能,并且其文档没有中心位置(请参阅此处))。

还有一件事,该示例在Docker Linux(alpine 3.9)容器中运行ASP.NET内核。因此路径将反映出这一点。它还使用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运行时,它还将安装和构建节点模块。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.