热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

在ASP.NETCore项目中使用npm管理你的前端组件包

 一、前言

  在项目的前端开发中,对于绝大多数的小伙伴来说,当然,也包括我,不可避免的需要在项目中使用到一些第三方的组件包。这时,团队中的小伙伴是选择直接去组件的官网上下载,还是图省事直接在网上搜索,然后从一些来源不明的地方下载,我们就无法管控了。同时,我们添加的组件间可能存在各种依赖关系,如果我们没有正确下载引用的话,到最后可能还是无法正常使用。

  因此,如何从可信的源下载组件包,以及如何轻松的解决各个组件间的依赖关系就成了我们需要解决的问题,那么,有没有一种工具可以帮我们解决这一问题?你好,有的,npm 了解一下。

  代码仓储:https://github.com/Lanesra712/ingos-common/tree/master/sample/aspnetcore/aspnetcore-npm-tutorial

 二、Step by Step

  在 .NET Framework 的项目中,我们可以在项目中通过 Nuget 下载安装前端的组件包。但是 Nuget 更多的是作为 .NET 后端项目中的包管理器,在这里管理前端的组件包显得有些不太合适。

  于是,在 .NET Core 的时代到来后,伴随着前端的发展,微软在创建的示例项目中开始推荐我们使用 bower 来管理我们项目中的前端组件包,然后,bower is dead。。。。

  所以这里,我采用 npm 作为我们的 ASP.NET Core 项目中的前端包管理器。

  1、安装 Node 环境

  Node.js 是一个能够在服务端运行 Javascript 的执行环境,也就是说,Javascript 不仅可以用于前端,也可以构建后端服务了。而 npm 则是 Node.js 官方提供的包管理工具,所以在使用 npm 之前,需要在我们的电脑上安装 Node.js 环境。

  当然,如果你之前有开发过 Vue、Angular 这类的前端项目,你肯定已经安装好了。如果没有,打开 Node.js 的官网(https://nodejs.org/en/download),根据你正在使用的操作系统信息,选择安装包下载就可以了。

  如果你使用的是 window 系统,很简单,下载 msi 安装包,一路 next 即可。在最新版本的 Node.js 安装包中,npm 是随着 Node.js 的安装一起完成的。我们可以使用下面的命令进行验证,当可以打印出你安装的版本信息,则说明安装已经完成了。

//1、node.js 版本
node -v

//2、npm 版本
npm -v

在 ASP.NET Core 项目中使用 npm 管理你的前端组件包

  2、使用 npm 安装包

  这篇文章的示例项目,我采用的是 ASP.NET Core 2.2 默认生成的 MVC 项目,因为在写文章的过程中有过更换解决方案,所以文章中的截图可能会出现名称前后不对应的情况,还请见谅。

  当示例项目创建完成后,会自动在项目中引用 bootstrap 和 jquery,所以,我们就在这个项目的基础上,尝试采用 npm 来管理我们的前端组件包。

  右击我们的项目,添加一个 package.json 配置文件。在这个 json 文件中定义了这个项目所需要的各种前端模块,以及项目的配置信息(比如名称、版本、许可证等等)。当我们从别处拷贝这个项目后,通过执行 npm install 命令,就会根据这个配置文件,自动下载项目中所需要引用的前端组件包。

在 ASP.NET Core 项目中使用 npm 管理你的前端组件包

  打开 package.json 文件,如果你选择使用 VS 进行编辑的话,可以看到 VS 会自动帮我们出现代码补齐提示。这里我添加了一个 dependencies 节点,它与 devDependencies 节点都代表我们项目中需要安装的插件。不同的是,devDependencies 里面的插件只用于开发环境,不用于生产环境,而 dependencies 中引用的则是需要发布到生产环境中的。

  例如,这里我们需要在项目中添加 bootstrap 和 jquery,因为在正式发布时如果缺少这两个组件,就会导致我们的程序报错,所以这里我们需要添加到 dependencies 节点下,而像后面我们使用到的 gulp 的一系列插件,只有在我们进行项目开发时才会使用到,所以我们只需要添加到 devDependencies 即可。

在 ASP.NET Core 项目中使用 npm 管理你的前端组件包

  这里我推荐使用命令行的方式添加组件,可以更好地展示出我们添加的组件需要添加哪些依赖。右键选中我们的示例项目,选择 Open Command Line,打开控制台,输入下列的命令,将 bootstrap 添加到我们的项目中。

  在 install 命令中我们添加了 --save 修饰,表示需要将 bootstrap 添加到 dependencies 节点下面。如果,你需要将引用到的 package 安装到 devDependencies 节点下,则需要使用 --save-dev 修饰。

npm install bootstrap --save

在 ASP.NET Core 项目中使用 npm 管理你的前端组件包

  可以看到,安装完成后,npm 提示我们 bootstrap 依赖于 jquery 和 popper.js,所以这里我们手动添加上这两个依赖的组件。

  当我们安装 jquery 的 1.9.1 版本后,因为之前的 jquery 版本存在一些安全隐患,所以 npm 会提示我们执行 npm audit 命令来查看当前项目中可能存在的安全隐患,以及对于如何解决这些隐患的建议。

在 ASP.NET Core 项目中使用 npm 管理你的前端组件包

  这里我进行了版本升级,你可以根据自己的需求进行操作。请特别注意,当你在完成项目的基础包加载后,后续对于包版本的升级一定要谨慎、谨慎、再谨慎。升级完成后的 package.json 文件如下所示。

{
  "version": "1.0.0",
  "name": "aspnetcore.npm.tutorial",
  "private": true,
  "devDependencies": {},
  "dependencies": {
    "bootstrap": "^4.3.1",
    "jquery": "^3.4.1",
    "popper.js": "^1.14.7"
  }
}

  在我们第一次执行 npm install 命令时,系统自动为我们创建了 package-lock.json 这个文件,用来记录当前状态下实际安装的各个 npm package 的具体来源和版本号,当前项目下的 package-lock.json 文件如下。

{
  "name": "aspnetcore.npm.tutorial",
  "version": "1.0.0",
  "lockfileVersion": 1,
  "requires": true,
  "dependencies": {
    "bootstrap": {
      "version": "4.3.1",
      "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.3.1.tgz",
      "integrity": "sha512-rXqOmH1VilAt2DyPzluTi2blhk17bO7ef+zLLPlWvG494pDxcM234pJ8wTc/6R40UWizAIIMgxjvxZg5kmsbag=="
    },
    "jquery": {
      "version": "3.4.1",
      "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.4.1.tgz",
      "integrity": "sha512-36+AdBzCL+y6qjw5Tx7HgzeGCzC81MDDgaUP8ld2zhx58HdqXGoBd+tHdrBMiyjGQs0Hxs/MLZTu/eHNJJuWPw=="
    },
    "popper.js": {
      "version": "1.14.7",
      "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.14.7.tgz",
      "integrity": "sha512-4q1hNvoUre/8srWsH7hnoSJ5xVmIL4qgz+s4qf2TnJIMyZFUFMGH+9vE7mXynAlHSZ/NdTmmow86muD0myUkVQ=="
    }
  }
}

  那么 package-lock.json 这个文件到底有什么用呢?

  因为我们在 npm 上下载的包遵循了大版本.次要版本.小版本的版本定义。例如,在上面的示例中,我们使用 npm install 命令安装的 bootstrap 版本为 4.3.1,而在安装插件包的时候,package.json 一般指定的是包的范围,即只对插件包的大版本进行限定。因此,当别人拷贝了你的代码,准备还原引用的包时,可能此时的 bootstrap 已经有 4.4.4 版本的了,这时,如果你使用了某些 4.3.1 版本中的特性,而在 4.4.4 版本中已经被移除的话,毫无疑问,你的代码就会出 bug。

  而当项目中存在了 package-lock.json 文件之后,因为项目中引用的组件包版本和来源信息已经锁定在了这个文件中了,此时,当别人拷贝了代码,准备还原时,就可以准确的加载到你开发时使用的组件版本。当然,如果你修改了引用的包信息,当执行 npm install 命令时,package-lock.json 文件会同步更新。

  对于包的版本限定条件如下所示。

  指定版本:比如此例中 bootstrap 的版本为 4.3.1,当重新安装时只安装指定的 4.3.1 版本。

  波浪号(tilde) + 指定版本:比如 ~1.2.2,表示安装1.2.x 的最新版本(不低于1.2.2),但是不安装 1.3.x,也就是说安装时不改变大版本号和次要版本号。

  插入号(caret) + 指定版本:比如 ˆ1.2.2,表示安装1.x.x 的最新版本(不低于1.2.2),但是不安装 2.x.x,也就是说安装时不改变大版本号。需要注意的是,如果大版本号为0,则插入号的行为与波浪号相同。

  latest:始终安装包的最新版本。

  3、gulp 配置

  当我们通过 npm 添加好需要使用的组件包后,就需要考虑如何在项目中使用。

  我们知道,在 ASP.NET Core 项目中,对于 web 项目中的静态文件的获取,通常是使用 StaticFileMiddleware 这个中间件。而 “{contentroot}/wwwroot” 这个目录是对外发布项目中的静态文件默认使用的根目录,也就是说,我们需要将使用到的 npm 包移动到 wwwroot 文件下。

  手动复制?em,工作量似乎有点大。

  不过,既然这里我们使用到了 node.js,那么这里就可以使用 gulp.js 这个自动化任务执行器来帮我们实现这一功能,当然,你也可以根据自己的习惯使用别的工具。

  通过使用 gulp.js,我们就可以自动的执行移动文件,打包压缩 js、css、image、删除文件等等,帮我们省了再通过 bundle 去打包压缩 css 和 js 文件的过程。

  在项目中使用 gulp.js 的前提,需要我们作为项目的开发依赖(devDependencies)安装 gulp 和一些用到的 gulp 插件,因为会下载很多的东西,整个安装的过程长短依据你的网络情况而定,嗯,请坐和放宽。

  在这个项目中使用到的 gulp 插件如下所示,如果你需要拷贝下面的命令行的话,在执行时请删除注释内容。

//gulp.js
npm install gulp --save-dev

//压缩 css
npm install gulp-clean-css --save-dev

//合并文件
npm install gulp-concat --save-dev

//压缩 js
npm install gulp-uglify --save-dev

//重命名
npm install gulp-rename --save-dev

//删除文件、文件夹
npm install rimraf --save-dev

//监听文件变化
npm install gulp-changed --save-dev

  安装完成后的 package.json 文件如下所示。

{
  "version": "1.0.0",
  "name": "aspnetcore.npm.tutorial",
  "private": true,
  "devDependencies": {
    "gulp": "^4.0.1",
    "gulp-changed": "^3.2.0",
    "gulp-clean-css": "^4.2.0",
    "gulp-concat": "^2.6.1",
    "gulp-rename": "^1.4.0",
    "gulp-uglify": "^3.0.2",
    "rimraf": "^2.6.3"
  },
  "dependencies": {
    "bootstrap": "^4.3.1",
    "jquery": "^3.4.1",
    "popper.js": "^1.14.7"
  }
}

  当我们安装好所有的 gulp 组件包之后,在我们的项目根路径下创建一个 gulpfile.js 文件,文件的内容如下所示。

/// 
"use strict";

//加载使用到的 gulp 插件
const gulp = require("gulp"),
    rimraf = require("rimraf"),
    concat = require("gulp-concat"),
    cssmin = require("gulp-clean-css"),
    rename = require("gulp-rename"),
    uglify = require("gulp-uglify"),
    changed = require("gulp-changed");


//定义 wwwroot 下的各文件存放路径
const paths = {
    root: "./wwwroot/",
    css: './wwwroot/css/',
    js: './wwwroot/js/',
    lib: './wwwroot/lib/'
};

//css
paths.cssDist = paths.css + "**/*.css";//匹配所有 css 的文件所在路径
paths.minCssDist = paths.css + "**/*.min.css";//匹配所有 css 对应压缩后的文件所在路径
paths.cOncatCssDist= paths.css + "app.min.css";//将所有的 css 压缩到一个 css 文件后的路径

//js
paths.jsDist = paths.js + "**/*.js";//匹配所有 js 的文件所在路径
paths.minJsDist = paths.js + "**/*.min.js";//匹配所有 js 对应压缩后的文件所在路径
paths.cOncatJsDist= paths.js + "app.min.js";//将所有的 js 压缩到一个 js 文件后的路径


//使用 npm 下载的前端组件包
const libs = [
    { name: "jquery", dist: "./node_modules/jquery/dist/**/*.*" },
    { name: "popper", dist: "./node_modules/popper.js/dist/**/*.*" },
    { name: "bootstrap", dist: "./node_modules/bootstrap/dist/**/*.*" },
];

//清除压缩后的文件
gulp.task("clean:css", dOne=> rimraf(paths.minCssDist, done));
gulp.task("clean:js", dOne=> rimraf(paths.minJsDist, done));

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

//移动 npm 下载的前端组件包到 wwwroot 路径下
gulp.task("move", dOne=> {
    libs.forEach(function (item) {
        gulp.src(item.dist)
            .pipe(gulp.dest(paths.lib + item.name + "/dist"));
    });
    done()
});

//每一个 css 文件压缩到对应的 min.css
gulp.task("min:css", () => {
    return gulp.src([paths.cssDist, "!" + paths.minCssDist], { base: "." })
        .pipe(rename({ suffix: '.min' }))
        .pipe(changed('.'))
        .pipe(cssmin())
        .pipe(gulp.dest('.'));
});

//将所有的 css 文件合并打包压缩到 app.min.css 中
gulp.task("concatmin:css", () => {
    return gulp.src([paths.cssDist, "!" + paths.minCssDist], { base: "." })
        .pipe(concat(paths.concatCssDist))
        .pipe(changed('.'))
        .pipe(cssmin())
        .pipe(gulp.dest("."));
});

//每一个 js 文件压缩到对应的 min.js
gulp.task("min:js", () => {
    return gulp.src([paths.jsDist, "!" + paths.minJsDist], { base: "." })
        .pipe(rename({ suffix: '.min' }))
        .pipe(changed('.'))
        .pipe(uglify())
        .pipe(gulp.dest('.'));
});

//将所有的 js 文件合并打包压缩到 app.min.js 中
gulp.task("concatmin:js", () => {
    return gulp.src([paths.jsDist, "!" + paths.minJsDist], { base: "." })
        .pipe(concat(paths.concatJsDist))
        .pipe(changed('.'))
        .pipe(uglify())
        .pipe(gulp.dest("."));
});

gulp.task("min", gulp.series(["min:js", "min:css"]));
gulp.task("concatmin", gulp.series(["concatmin:js", "concatmin:css"]));


//监听文件变化后自动执行
gulp.task("auto", () => {
    gulp.watch(paths.css, gulp.series(["min:css", "concatmin:css"]));
    gulp.watch(paths.js, gulp.series(["min:js", "concatmin:js"]));
});

  在 gulp.js 中主要有四个 API,就像我们项目中的 gulpfile 更多的是对于第三方插件的使用,而我们只需要通过 pipe 将任务中的每一步操作添加到任务队列中即可。完整的 API 文档,大家可以去官网去详细查看 => https://gulpjs.com/docs/en/api/concepts

  gulp.src:根据匹配、或是路径加载文件;

  gulp.dest:输出文件到指定路径;

  gulp.task:定义一个任务;

  gulp.watch:监听文件变化。

  当我们创建好任务后,删除 wwwroot 路径下的引用的第三方组件包,运行我们的示例项目,毫无疑问,整个页面的样式都已经丢失了。

在 ASP.NET Core 项目中使用 npm 管理你的前端组件包

  选中 gulpfile.js,右键打开任务运行程序资源管理器。可以看到,系统会自动显示出我们定义的所有任务,这时,我们可以鼠标右键点击任务,选中运行,即可执行我们的任务。

在 ASP.NET Core 项目中使用 npm 管理你的前端组件包

  然而,我们手动去执行似乎有些不智能,我们能不能自动执行某些任务呢?答案当然是可以,同样是鼠标右键点击任务,点击绑定菜单选项,我们就将定义好的任务绑定事件上。

在 ASP.NET Core 项目中使用 npm 管理你的前端组件包

  例如,在我的 gulpfile 中,我绑定了三个事件:生成解决方案前执行 min task,清理解决方案时执行 clean task,打开项目时执行 auto task,而 VS 也自动帮我们生成了如下的绑定脚本到我们的 gulpfile 上。

/// 

  通过将绑定事件与 gulp API 进行结合,就可以很好的实现我们的需求。就像这里,我在项目打开时绑定了自动监听文件变化的任务,这时,只要我修改了 css、js 文件,gulp 就会自动帮我们实现对于文件的压缩。

  PS:如果你将任务绑定到项目打开的事件上,则是需要下一次打开项目时才能自动执行。

在 ASP.NET Core 项目中使用 npm 管理你的前端组件包

 三、总结

    这一章主要是介绍了如何在我们的 ASP.NET Core 项目中通过 npm 管理我们的前端组件包,同时,使用 gulp 去执行一些移动文件、压缩文件的任务。随着这些年前端的发展,前端的开发越来越规范化,也越来越朝后端靠拢了,我们作为传统意义上的后端程序猿,在涉及到前端的开发时,如果可以用到这些可以规范化我们的前端项目的特性,还是极好的。因为自己水平也很菜,很多东西并没有很详细的涉及到,可能还需要你在实际使用中进行进一步的探究,毕竟,实践出真知。

 

推荐阅读
  • jQuery Flot 数据可视化插件:高效绘制图表的专业工具
    jQuery Flot 是一款高效的数据可视化插件,专为绘制各种图表而设计。该工具支持丰富的图表类型和自定义选项,适用于多种应用场景。用户可以通过其官方网站获取示例代码和下载资源,以便快速上手和使用。 ... [详细]
  • 作为140字符的开创者,Twitter看似简单却异常复杂。其简洁之处在于仅用140个字符就能实现信息的高效传播,甚至在多次全球性事件中超越传统媒体的速度。然而,为了支持2亿用户的高效使用,其背后的技术架构和系统设计则极为复杂,涉及高并发处理、数据存储和实时传输等多个技术挑战。 ... [详细]
  • 本文详细介绍了如何在Linux系统中搭建51单片机的开发与编程环境,重点讲解了使用Makefile进行项目管理的方法。首先,文章指导读者安装SDCC(Small Device C Compiler),这是一个专为小型设备设计的C语言编译器,适合用于51单片机的开发。随后,通过具体的实例演示了如何配置Makefile文件,以实现代码的自动化编译与链接过程,从而提高开发效率。此外,还提供了常见问题的解决方案及优化建议,帮助开发者快速上手并解决实际开发中可能遇到的技术难题。 ... [详细]
  • 【前端开发】深入探讨 RequireJS 与性能优化策略
    随着前端技术的迅速发展,RequireJS虽然不再像以往那样吸引关注,但其在模块化加载方面的优势仍然值得深入探讨。本文将详细介绍RequireJS的基本概念及其作为模块加载工具的核心功能,并重点分析其性能优化策略,帮助开发者更好地理解和应用这一工具,提升前端项目的加载速度和整体性能。 ... [详细]
  • 当前,众多初创企业对全栈工程师的需求日益增长,但市场中却存在大量所谓的“伪全栈工程师”,尤其是那些仅掌握了Node.js技能的前端开发人员。本文旨在深入探讨全栈工程师在现代技术生态中的真实角色与价值,澄清对这一角色的误解,并强调真正的全栈工程师应具备全面的技术栈和综合解决问题的能力。 ... [详细]
  • 使用 Vue 集成 iScroll 实现移动端表格横向滚动与固定列功能 ... [详细]
  • 基于Node.js、EJSExcel、Express与Vue.js构建Excel转JSON工具:首阶段——Vue.js项目初始化及开发环境配置
    在近期的一个H5游戏开发项目中,需要将Excel数据转换为JSON格式。经过调研,市面上缺乏合适的工具满足需求。因此,决定利用Node.js、EJSExcel、Express和Vue.js自行构建这一工具。本文主要介绍项目的第一阶段,即Vue.js项目的初始化及开发环境的配置过程,详细阐述了如何搭建高效的前端开发环境,确保后续功能开发的顺利进行。 ... [详细]
  • 全面解析:安检利器的高效应用与技术特点
    全面解析:安检利器的高效应用与技术特点 ... [详细]
  • 在本教程中,我们将详细介绍如何使用 ArcGIS API 3.x for JavaScript 绘制风向流动图。如果您对所涉及的 API 类不熟悉,建议参考 Esri 官方网站上的 ArcGIS API 3.x for JavaScript 文档,其中提供了详尽的类介绍和使用说明。此外,我们还将提供完整的源代码,帮助您更好地理解和实现这一功能。 ... [详细]
  • 理工科男女不容错过的神奇资源网站
    十一长假即将结束,你的假期学习计划进展如何?无论你是在家中、思念家乡,还是身处异国他乡,理工科学生都不容错过一些神奇的资源网站。这些网站提供了丰富的学术资料、实验数据和技术文档,能够帮助你在假期中高效学习和提升专业技能。 ... [详细]
  • 从零起步:使用IntelliJ IDEA搭建Spring Boot应用的详细指南
    从零起步:使用IntelliJ IDEA搭建Spring Boot应用的详细指南 ... [详细]
  • Django框架进阶教程:掌握Ajax请求的基础知识与应用技巧
    本教程深入探讨了Django框架中Ajax请求的核心概念与实用技巧,帮助开发者掌握异步数据交互的方法,提升Web应用的响应速度和用户体验。通过实例解析,详细介绍了如何在Django项目中高效实现Ajax请求,涵盖从基础配置到复杂场景的应用。 ... [详细]
  • 本文精选了几个结合 Vue 和 Spring Boot 的优质开源项目,适合开发者学习和参考。这些项目不仅涵盖了前后端分离的最佳实践,还提供了丰富的功能示例和详细的文档,有助于提升开发效率和技术水平。项目地址:https://github.com/ 示例链接。 ... [详细]
  • IT企业通常配置多少Java开发者及Java岗位的发展前景分析
    在IT企业中,Java开发者的配置数量通常较多,反映了该语言在后端开发中的重要地位。与前端开发相比,Java的学习曲线可能更为平缓,但深度掌握仍需大量实践。Web前端开发则侧重于用户体验和浏览器兼容性,要求开发者具备扎实的技术基础和良好的审美观。从北上广深等一线城市的薪资水平来看,Java开发者普遍享有较高的薪酬待遇,且随着经验的积累,职业发展空间广阔。 ... [详细]
  • 在Vite项目优化过程中,通过使用rollup-plugin-visualizer插件,可以有效地对Rollup打包结果进行可视化分析,帮助开发者清晰地了解各个模块的占用情况,从而进行更有针对性的优化。此外,结合其他常用插件,如vite-plugin-compression和vite-plugin-inspect,可以进一步提升项目的性能和可维护性。 ... [详细]
author-avatar
彭德利
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有