博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
前端快速自动化构建
阅读量:6544 次
发布时间:2019-06-24

本文共 10104 字,大约阅读时间需要 33 分钟。

我们先来设定一个简单的需求:

  • 一个本地开发环境,具备监控文件变化并实时更新的功能;
  • 修改代码,保存之后浏览器自动刷新
  • 实时编译各种预编译格式文件
  • 压缩合并静态资源,打包输出
  • 部署上传

一言不合就上图:

自动化构建(入门).png

好,有了这个规划之后,我们开始着手来实现它。

二、源码

首先新建一个项目文件夹project,接着我们打开命令行工具,切换到这个目录下,开始初始化这个项目:

cd projectnpm init

按照提示完成初始化,打开项目我们会得到一个package.json文件像这样:

// package.json{  "name": "project",  "version": "1.0.0", "description": "a test project", "main": "index.js", "scripts": { "test": "node ./build/test.js" }, "author": "jack lo", "license": "ISC" }

紧接着我们先来创造一份源码,结构如下:

- project  |- src  // 源文件夹  | |- tpl  | | `- index.html  | |- css  | | `- index.css  | |- js  | | `- index.js  |- dist  // 打包文件夹  `- package.json

三、编译打包

一切材料就绪,我们开始安装工具包,这一次我们主要使用gulp来构建,不需要用到webpack,同时,为了实现浏览器自动刷新的功能,我们还需要用到。

npm install gulp browser-sync --save-dev

这需要花点时间。

---------- 虚度光阴中 ---------

事实上,这里有个小坑需要我们提前准备一下,因为我们接下来会用到gulp的cli,所以这里我们需要全局安装gulp,没错,我就是设套让你装两遍!

这是个好习惯,请务必以后也坚持这么做。把开发时候用到的所有npm包都记录在package.json文件中,可以方便日后自己以及他人的使用。

npm install gulp -g

mac用户可能还要sudo一下:

sudo npm install gulp -g

回车后按提示输入密码,继续回车,就可以正常安装了。

---------- 再一次虚度光阴中 ---------

ok,安装完后,我们可以开始做点有意义的事了。

gulp的用法其实相当简单,api也就那么几个。简单来说,就是写好一个配置文件gulpfile.js,然后在命令行里执行它。

首先在根目录下新建一个gulpfile.js,然后随便建一个叫做test的任务:

// gulpfile.jsvar gulp = require('gulp') // 创建一个名为test的任务,任务内容只是简单地在控制台输出一段文本 gulp.task('test', function () { return console.log('this is a test') })

ok,保存。然后我们回到命令行,输入以下命令然后回车

gulp test

gulp后面跟的是你所要执行的任务名,于是我们得到了这样一个结果

[22:56:35] Using gulpfile ~/project/gulpfile.js[22:56:35] Starting 'test'... this is a test [22:56:35] Finished 'test' after 149 μs

成功输出文本!恭喜,你已经掌握了gulp一半以上的用法。

现在我们尝试着来操作文件,我们将src/html里面的html文件给拷贝到dist文件夹(如果不存在则新建)里面去,怎么做?

// 创建一个copy的任务gulp.task('copy', function () { return gulp.src('src/tpl/*.html') .pipe(gulp.dest('dist')) })

这里的pipe其实是一种管道,你可以一直pipe连着pipe下去,也就是这个工作流可以一直这样一层层执行下去,随便你定义多少个处理任务都行,这就是gulp的特点,简单明了的工作流程。很多人不明白gulp到底是做什么的,其实到这里,就可以有个大概的认识了:

gulp是以定义并执行一个个任务的形式来工作的流程管理工具,它的作用在于提供一套简单易用的工作方式。

在gulp以前,处理一份sass文件,你可能需要先执行一次编译的任务,编译成css之后,再执行一遍压缩css的任务,压缩完之后,再手动拷贝到打包文件夹里。原本需要分三步来操作的一件事情,在gulp里面就是一个任务的sei而已:

// 创建一个css的处理任务gulp.task('sass', function () { return gulp.src('src/sass/*.scss') .pipe(sass()) .pipe(minifycss()) .pipe(gulp.dest('dist/static')) })

甚至我们可以同时执行多个任务,我可以定义好coffee、sass、image、html的四个任务,再把他们合并到一个任务当中去,一次性执行完:

// 创建一个build的处理任务gulp.task('build', ['coffee', 'sass', 'image', 'html'])

我只需要:

gulp build

回车,这酸爽。

好了,介绍了这么多内容,最后我们还是回到最开始那份需求的实现上来。

我们来建几个任务,分别处理js、css、html文件,把js和css文件放到dist/static目录下,把html文件放到dist下:

gulp.task('css', function () { return gulp.src('src/css/*.css') .pipe(gulp.dest('dist/static')) }) gulp.task('js', function () { return gulp.src('src/js/*.js') .pipe(gulp.dest('dist/static')) }) gulp.task('html', function () { return gulp.src('src/tpl/*.html') .pipe(gulp.dest('dist')) }) gulp.task('build', ['css', 'js', 'html'])

命令行gulp build一下,回车!再看看dist文件夹,done!

咋一看,好像没什么问题,但好像又有哪里不太对劲。不对啊,除了复制到dist文件夹,好像没啥功能啊,说好的压缩合并呢?说好的处理预编译呢?嗯,有了这个框架,这些功能我们想加多少加多少。

这样简单的项目,我们没法玩出花样,我们来点预编译语言,css用sass代替,html用swig代替:

- project  |- src  // 源文件夹  | |- tpl  | | `- index.swig  | |- sass  | | `- index.scss  | |- js  | | `- index.js  |- dist  // 打包文件夹  `- package.json

编译sass需要安装gulp-sass模块,编译swig需要gulp-swig。注意到了吗?基本上gulp的模块都以gulp-*的形式出现,所以如果以后你使用gulp的时候想用什么模块,可以试试在npm搜gulp-模块名

npm install gulp-sass gulp-swig --save-dev

---------- 虚度光阴中 ---------

安装完后,我们再来修改一下配置文件gulpfile.js

var gulp = require('gulp')var sass = require('gulp-sass') var swig = require('gulp-swig') gulp.task('sass', function () { return gulp.src('src/sass/*.scss') .pipe(sass({ outputStyle: 'compressed' // 此配置使文件编译并输出压缩过的文件 })) .pipe(gulp.dest('dist/static')) }) gulp.task('js', function () { return gulp.src('src/js/*.js') .pipe(gulp.dest('dist/static')) }) gulp.task('tpl', function () { return gulp.src('src/tpl/*.swig') .pipe(swig({ defaults: { cache: false // 此配置强制编译文件不缓存 } })) .pipe(gulp.dest('dist')) }) gulp.task('build', ['sass', 'js', 'tpl'])

再接着gulp build一下,编译结束,可以看看dist下是不是有index.html,dist/static下是不是有编译完成且压缩过的index.css,没有你找我!这里就不分别展示源文件和打包后文件的内容了,因为并不重要,想看演示项目内容的朋友,可以在文章结尾处找到本次演示项目的git仓库链接。各种预编语言和前端模板大家可以根据自己的喜好选择,笔者只是选择自己熟悉的几种来做演示。

到这里我们基本上已经完成打包的工作了,我们来试着搭建开发环境。

四、搭建开发环境

前文我们提到一个工具browser-sync,还记得吗?现在用得上了!我们先创建一个开发任务,像gulp build一样简单的任务,我们的目标是:没有蛀牙 一句话搞定。

gulp.task('dev', ['js:dev', 'sass:dev', 'tpl:dev'], function () { // do something here... })

看着好像稍有不同。这一次我们创建一个叫做dev的任务,这个任务先执行js:devsass:devtpl:dev三个任务,然后再执行回调里的内容,我们的本地服务器就是要在回调里去定义并且启动。

在这之前,我们先来了解一下browser-sync:

Browsersync能让浏览器实时、快速响应您的文件更改(html、js、css、sass、less等)并自动刷新页面。 ——Browsersync中文网

事实上Browsersync可以理解为一个本地服务器,类似于Apache,不同的是,Browsersync只提供很简单的http功能,它的主要功能,是通过搭建一个本地服务器,并且监听文件的更改,自动刷新浏览器,实时地呈现最新内容。

browser-sync的用法:

var browserSync = require('browser-sync').create()browserSync.init({  server: {    baseDir: "./" // 设置服务器的根目录 } })

其实也很简单,没有太多内容,现在我们要将它整合进我们的gulp任务里,捣鼓几下,我们得到:

gulp.task('dev', ['js:dev', 'sass:dev', 'tpl:dev'], function () { browserSync.init({ server: { baseDir: "./dist" // 设置服务器的根目录为dist目录 }, notify: false // 开启静默模式 }) // 我们使用gulp的文件监听功能,来实时编译修改过后的文件 gulp.watch('src/js/*.js', ['js:dev']) gulp.watch('src/sass/*.scss', ['sass:dev']) gulp.watch('src/tpl/*.swig', ['tpl:dev']) })

这里的watch行为可以简单理解为:我(gulp)就这么盯着你(src/js/*.js文件),只要你被改动了,我就马上执行js:dev任务来处理你,产生最新的文件。

那么,我们现在还需要补充一下js:devsass:devtpl:dev这三个任务,与原来的jssasstpl三个任务大同小异,这里笼统地过一遍就好,我们直接看代码:

var browserSync = require('browser-sync').create()var reload = browserSync.reload gulp.task('sass:dev', function () { return gulp.src('src/sass/*.scss') .pipe(sass()) .pipe(gulp.dest('dist/static')) .pipe(reload({stream: true})) }) gulp.task('js:dev', function () { return gulp.src('src/js/*.js') .pipe(gulp.dest('dist/static')) .pipe(reload({stream: true})) }) gulp.task('tpl:dev', function () { return gulp.src('src/tpl/*.swig') .pipe(swig({ defaults: { cache: false // 此配置强制编译文件不缓存 } })) .pipe(gulp.dest('dist')) .pipe(reload({stream: true})) })

这里的reload方法,我们不需要过多了解,只要知道,通过执行它就可以刷新浏览器。这里的stream用法可以查阅官方文档,这里不重要所以不细讲。

值得留意的是:这里的sass:dev任务,我们并没有像sass任务一样配置编译模式为compressed,也就是不使用压缩功能,为什么呢?事实上,我们在开发的时候,并不需要压缩静态资源文件,可以说我们不在意它的体积是大一点还是小一点,我们在意的是样式是否写得符合期望,我们在乎的是功能是否实现,所以不需要启用压缩或者其他的什么优化功能,这样可以减轻编译的负担,加快编译速度。如果你对js或者图片也使用了压缩功能,建议在开发模式下去掉,只在打包模式下使用。

最终我们整理得到一份gulpfile.js文件:

var gulp = require('gulp')var sass = require('gulp-sass') var swig = require('gulp-swig') var browserSync = require('browser-sync').create() var reload = browserSync.reload gulp.task('sass', function () { return gulp.src('src/sass/*.scss') .pipe(sass({ outputStyle: 'compressed' // 此配置使文件编译并输出压缩过的文件 })) .pipe(gulp.dest('dist/static')) }) gulp.task('js', function () { return gulp.src('src/js/*.js') .pipe(gulp.dest('dist/static')) }) gulp.task('tpl', function () { return gulp.src('src/tpl/*.swig') .pipe(swig({ defaults: { cache: false // 此配置强制编译文件不缓存 } })) .pipe(gulp.dest('dist')) }) gulp.task('sass:dev', function () { return gulp.src('src/sass/*.scss') .pipe(sass()) .pipe(gulp.dest('dist/static')) .pipe(reload({stream: true})) }) gulp.task('js:dev', function () { return gulp.src('src/js/*.js') .pipe(gulp.dest('dist/static')) .pipe(reload({stream: true})) }) gulp.task('tpl:dev', function () { return gulp.src('src/tpl/*.swig') .pipe(swig({ defaults: { cache: false // 此配置强制编译文件不缓存 } })) .pipe(gulp.dest('dist')) .pipe(reload({stream: true})) }) gulp.task('dev', ['js:dev', 'sass:dev', 'tpl:dev'], function () { browserSync.init({ server: { baseDir: "./dist" }, notify: false }) gulp.watch('src/js/*.js', ['js:dev']) gulp.watch('src/sass/*.scss', ['sass:dev']) gulp.watch('src/tpl/*.swig', ['tpl:dev']) }) gulp.task('build', ['sass', 'js', 'tpl'])

嗯,完美,到这一步,我们这个自动化构建已经基本完成了,而且还算是完整。现在,我们开发的时候,就执行gulp dev,打包的时候就执行gulp build,是不是很方便?

注意:gulp dev任务启动以后是一直保持工作状态的,也就是它不像gulp build一样一次性执行完,它是keep alive的,所以我们如果要停止这个任务,需要手动按ctrl+c组合键,结束这个任务。

五、补充

然而事情还没完,我们的目标是:装逼 尽善尽美!

有三个地方其实我们还没做到位:

  • 对命令进行包装,尽量简洁。gulp dev和gulp build其实已经很简洁了,但事实上这只是因为这个项目很简单,用到的命令很少,在开发复杂的项目时,我们通常要输入复杂的一长串的命令行。gulp dev其实也是gulp --gulpfile gulpfile.js dev的缺省写法而已,具体情况可以去gulp官网了解。所以我们需要有更简洁的方式去执行这些预先准备好的脚本,就好像windows系统下的快捷方式;
  • 目前的情况是,我们每次执行,都会将文件拷贝到dist目录下,但是却没有删除的工作,也就是说文件数量只增不减,这样多次下来,随着文件的增删改动,必然会遗留很多没有用的文件。我们需要每次启动编译或者打包之前,先把整个dist文件夹删除,然后再重新生成dist;
  • 上传的功能还没做呢?!

二话不说就开工!

第一点很好解决,我们可以把脚本作为一项配置存放在package.json文件中:

{  "name": "project",  "version": "1.0.0", "description": "a test project", "main": "index.js", "scripts": { "dev": "gulp dev", // 开发脚本 "build": "gulp build", // 打包脚本 "test": "node ./build/test.js" }, "author": "jack lo", "license": "ISC", "devDependencies": { "browser-sync": "^2.13.0", "gulp": "^3.9.1", "gulp-sass": "^2.3.2", "gulp-swig": "^0.8.0" } }

注意到了吗?scripts项就是用来预定义脚本的地方,我们可以很方便地把脚本按照上面的形式封装好,然后执行的方式就变成了:

npm run dev  // 执行开发npm run build  // 执行打包

搞定!

我们接着看第二点,删除dist文件夹,多简单的事啊!鼠标右键,删除,搞定!

……

哪有这么low的事,我们的目标是:懒癌晚期 能不自己做的事情,绝不自己动手。

有一个叫做rimraf的包,可以帮我们做这事,我们需要用到它的cli,所以跟gulp一样,我们全局安装它:

npm install rimraf -g

安装完后,我们再重新修改一下package.json文件中的scripts内容:

{  "name": "project",  "version": "1.0.0", "description": "a test project", "main": "index.js", "scripts": { "dev": "gulp dev", // 开发脚本 "build": "rimraf dist && gulp build", // 打包脚本 "test": "node ./build/test.js" }, "author": "jack lo", "license": "ISC", "devDependencies": { "browser-sync": "^2.13.0", "gulp": "^3.9.1", "gulp-sass": "^2.3.2", "gulp-swig": "^0.8.0" } }

ok,现在试试执行npm run build,dist文件夹是不是先被删除,然后再重新生成了?

完美。

第三点放到最后才补充,主要是考虑到它并不是必要的,因为有些项目并不需要ftp上传,一般是提交svn,然后再由后端或者运维去部署,笔者是需要将静态资源上传到cdn服务器进行加速的,所以需要这样一个任务,在此我们简单介绍一下。

举一反三一下,我们再创建一个upload任务:

var ftp = require('gulp-ftp')var gutil = require('gulp-util') gulp.task('upload', function () { return gulp.src('dist/**') .pipe(ftp({ host: '8.8.8.8', // 远程主机ip port: 22, // 端口 user: 'username', // 帐号 pass: 'password', // 密码 remotePath: '/project' // 上传路径,不存在则新建 })) .pipe(gutil.noop()) })

自行安装一下gulp-ftp和gulp-util两个包,然后在package.json文件中的scripts补充一个脚本npm run upload来执行gulp upload。

笔者通常都是打包之后顺便上传,命令行直接输入npm run build && npm run upload,回车,然后就可以愉快地去跟旁边的妹纸聊天了。

六、总结

到这里,我们已经完整搭完了这一套简易自动化工具,好像讲了很多东西,其实总结起来内容非常少:我们只不过分别用三个小任务(sass、js、tpl),组成了build和dev这两个大任务,仅此而已。

由于时间和篇幅关系,我们只简单处理了css、js和html,事实上,你还可以在这个基础上继续完善下去,js可以由coffeejs编译得到,而且还可以继续压缩,甚至可以把全部js文件合并成一个!html也一样可以继续压缩。而且,你完全可以自己创建一个任务去处理其他诸如图片、字体等等。

本次演示项目的git地址:

 

转载于:https://www.cnblogs.com/axl234/p/5776206.html

你可能感兴趣的文章
高清摄像头MIPI CSI2接口浅解【转】
查看>>
C# CancellationTokenSource和CancellationToken的实现
查看>>
PCIE BAR空间
查看>>
如何用数学课件制作工具画角平分线
查看>>
VS2015 中统计整个项目的代码行数
查看>>
UWP控件与DataBind
查看>>
bash: php: command not found
查看>>
XVIII Open Cup named after E.V. Pankratiev. Eastern Grand Prix
查看>>
数据恢复软件如何换机使用?
查看>>
《高性能mysql》到手
查看>>
(转)关于如何学好游戏3D引擎编程的一些经验
查看>>
使用Kotlin为你的APP自定义一个统一的标题栏
查看>>
EF各版本增删查改及执行Sql语句
查看>>
拓扑排序
查看>>
jQGrid API
查看>>
Bzoj1758: [Wc2010]重建计划
查看>>
redis集群部署及踩过的坑
查看>>
j2EE监听器-listener
查看>>
使用pip命令报You are using pip version 9.0.3, however version 18.0 is available pip版本过期.解决方案...
查看>>
(转)LINQ之路
查看>>