Asp-Net-Core开发笔记:使用NPM和gulp管理前端静态文件
前言 本文介绍的是AspNetCore的MVC项目,WebApi+独立前端这种前后端分离的项目就不需要多此一举了~默认前端小伙伴是懂得使用前端工具链的。 为啥要用MVC这种服务端渲染技术呢? 简单项目不需要强行分离增加复杂度(如:我正在开发的博客项目) 后端渲染利于SEO,对博客网站友好 OK,虽然MVC的技术老了点,但依然可以结合现代前端工具链来提高效率 本文的食用需要先安装好Node.js环境
目录8 个章节
前言
本文介绍的是AspNetCore的MVC项目,WebApi+独立前端这种前后端分离的项目就不需要多此一举了~默认前端小伙伴是懂得使用前端工具链的。
为啥要用MVC这种服务端渲染技术呢?
- 简单项目不需要强行分离增加复杂度(如:我正在开发的博客项目)
- 后端渲染利于SEO,对博客网站友好
OK,虽然MVC的技术老了点,但依然可以结合现代前端工具链来提高效率
本文的食用需要先安装好Node.js环境,下载地址:https://nodejs.org/en/download
在开始前,先看看我们的项目文件结构
- Blog/
- Blog.Web/
- Program.cs
- Blog.Web.csproj
- Blog.Data/
- Blog.sln
- Blog.Web/
使用NPM安装依赖
首先在项目根目录(也就是Blog/Blog.Web)执行
npm init
生成package.json文件
完成之后项目结构应该类似这样
- Blog/
- Blog.Web/
- Program.cs
- Blog.Web.csproj
- package.json (npm init 命令创建的文件)
- Blog.Web/
然后编辑package.json或者使用命令行npm install bootstrap来添加需要的前端库
安装的前端库会保存在Blog/Blog.Web/node_modules这个目录下,但我们的静态文件需要放在Blog/Blog.Web/wwwroot里才行,也就是说,我们需要将使用到的 npm 包移动到 wwwroot 文件下。
怎么搞?手动移动或复制是不可能的,太麻烦了。
这时候就要借助自动化工具,这里选择了gulp.js,用于实现自动移动文件,打包压缩 js、css、image、删除文件等操作。提高生产力~
安装gulp
首先安装gulp全局工具
npm install --global gulp-cli
然后在项目中安装gulp以及几个插件作为开发依赖(devDependencies)
//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文件应该类似下面这样:
{
"name": "star-blog",
"devDependencies": {
"gulp": "^4.0.2",
"gulp-changed": "^4.0.3",
"gulp-clean-css": "^4.3.0",
"gulp-concat": "^2.6.1",
"gulp-rename": "^2.0.0",
"gulp-uglify": "^3.0.2",
"rimraf": "^3.0.2"
},
"dependencies": {
...
}
}
配置gulp
继续在根目录(和package.json同级目录)下新建gulpfile.js文件
/// <binding BeforeBuild='min' Clean='clean' ProjectOpened='auto' />
"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/**/*.*"},
{name:"bootswatch",dist: "./node_modules/bootswatch/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"]));
});
执行任务
上面定义这几个任务:
- move:把在
libs常量里配置的node_modules包的dist文件夹移动到wwwroot/lib里 - min:把我们在
wwwroot/css和wwwroot/js里写的css和js,每一个都压缩成xxx.min.css/xxx.min.js - concatmin:把上面
min压缩的所有css和js,合成一个app.min.css和app.min.js - auto:自动监听文件变化后自动执行上面的
min和concatmin任务
在终端中输入gulp --tasks,可以查看我们定义的这些任务
> gulp --tasks
[17:37:44] Tasks for /home/da/Code/StarBlog/StarBlog.Web/gulpfile.js
[17:37:44] ├── clean:css
[17:37:44] ├── clean:js
[17:37:44] ├─┬ clean
[17:37:44] │ └─┬ <series>
[17:37:44] │ ├── clean:js
[17:37:44] │ └── clean:css
[17:37:44] ├── move
[17:37:44] ├── min:css
[17:37:44] ├── concatmin:css
[17:37:44] ├── min:js
[17:37:44] ├── concatmin:js
[17:37:44] ├─┬ min
[17:37:44] │ └─┬ <series>
[17:37:44] │ ├── min:js
[17:37:44] │ └── min:css
[17:37:44] ├─┬ concatmin
[17:37:44] │ └─┬ <series>
[17:37:44] │ ├── concatmin:js
[17:37:44] │ └── concatmin:css
[17:37:44] └── auto
使用gulp task-name的命令可以执行任务,例如:
> gulp min
[17:41:41] Using gulpfile /home/da/Code/StarBlog/StarBlog.Web/gulpfile.js
[17:41:41] Starting 'min'...
[17:41:41] Starting 'min:js'...
[17:41:41] Finished 'min:js' after 19 ms
[17:41:41] Starting 'min:css'...
[17:41:41] Finished 'min:css' after 21 ms
[17:41:41] Finished 'min' after 44 ms
这就完成了把我们在wwwroot/css和wwwroot/js里写的css和js,每一个都压缩成xxx.min.css/xxx.min.js的任务。方便!
结合IDE
VS我没有用过,我是用Rider做开发的,所以只介绍一下rider的
很简单,打开 Run/Debug Configuration,在添加配置里面选择 JavaScript Build Tools 里的 Gulp.js
然后选择项目里的GulpFile,Tasks栏下拉可以看到我们定义好的任务,直接添加就完事了

添加完就像C#项目一样,可以直接执行
razor里使用
使用Gulp.js收集静态文件到wwwroot目录后,razor文件里的引用需要小小的改一下,如下:
引用CSS文件
<link rel="stylesheet" href="~/lib/fontawesome-free-6.0.0-web/css/all.css">
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="~/lib/bootswatch/dist/united/bootstrap.min.css">
<link rel="stylesheet" href="~/css/app.min.css">
引用JS文件
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
<script src="~/js/app.min.js"></script>
大功告成!
参考资料
_EOF_
Asp-Net-Core开发笔记:使用NPM和gulp管理前端静态文件
- 本文作者:
- 程序设计实验室
- 版权声明:
- 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
相关文章
Asp-Net-Core开发笔记:FrameworkDependent搭配docker部署
之前我写过一篇使用 docker 部署 AspNetCore 应用的文章,这种方式搭配 CICD 非常方便, build 之后 push 到私有的 dockerhub ,在生产服务器上 pull 下来镜像就可以直接运行了。 然而,有时需要一种更传统的部署方式,比如在本地打包可执行文件之后直接放到服务器上执行。 这种方式配置完成之后,每次更新只需要重新本地重新 publish 后把可执行文件上传
2023-09-08 · Asp-Net-Core开发笔记 · 约 1 分钟
Asp-Net-Core开发笔记:给SwaggerUI加上登录保护功能
既要在项目发布后访问 SwaggerUI ,又要保证一定的安全性,本文提供的思路或许是一种比较简单又有效的解决方案。
2024-05-21 · Asp-Net-Core开发笔记 · 约 1 分钟
Asp-Net-Core开发笔记:接口返回json对象出现套娃递归问题
前言 看了下推送记录,一个月前,OK,我又变成月更了o(╯□╰)o,这绝对不行![○・`Д´・ ○] 所以今天来更新了 其实不是我懒得更新或者是太忙,其实是最近在写一篇很长的博客,一直没写完( Ĭ ^ Ĭ ) 好吧,先进入正题…… 有一个关于WebApi序列化的问题,跟设计有关,但在涉及到关联字段的时候经常会遇到。 实体类 先看看实体类定义,限于篇幅,只保留几个关键字段。 public class
2022-02-16 · Asp-Net-Core开发笔记 · 约 1 分钟
Asp-Net-Core开发笔记:进一步实现非侵入性审计日志功能
现在已经可以实现对业务代码完全无侵入的审计日志了,在需要审计的接口上加上 `[AuditLog]` 特性,就可以记录这个接口的操作日志,还有相关的实体变化记录,还算是方便。
2024-04-29 · Asp-Net-Core开发笔记 · 约 1 分钟
讨论
共 0 条加载评论中…