Castie!

正态分布, 优劣伴生

北冥有鱼,其名为鲲(kūn)。鲲之大,不知其几千里也;化而为鸟,其名为鹏。鹏之背,不知其几千里也;怒而飞,其翼若垂天之云。是鸟也,海运则将徙于南冥。南冥者,天池也。


北海若曰:“井鼃不可以语于海者,拘于虚也;夏虫不可以语于冰者,笃于时也;曲士不可以语于道者,束于教也。今尔出于崖涘,观于大海,乃知尔丑,尔将可与语大理矣。

Web 使用gulp构建前端项目

对于现在的前端开发来说, 比起之前jQuery时期真心方便很多, 自从ES6的更新后, 更是进一步加快了前端开发的脚步, 并有统一天下的趋势, 随之而出的React / React-Native, Vue / Weex (Vue-Native)之流的框架兴起更是降低了前端开发的门槛, 以至于开发者们对大前端时代趋之若鹜.

对于现在的前端开发已经不想以前仅靠切图加上HTML+CSS+JS三件套就能够轻松搞定了, 现在三方提供的工具层出不穷, jQuery, Angular, BootStrap到现在的Grunt, Gulp, Webpack, Babel, Node.js掌握这些只能算是刚刚入了前端的大门. 相比起iOS这样的移动端有条不紊的技术栈, 略显松散的前端技术对初学者并不是那么的友好.

对于现在的前端开发来说, React和Vue可能已经是必须要掌握的技能了, 通过官方对应的脚手架工具就能够快速的搭建项目框架了. 其实搭建项目框架并不是一个很神奇的事情, 使用grunt或者gulp就能够轻松搞定. 使用哪种工具并不重要关键是要了解其中的原理.

本文我们就通过搭建前端项目框架来进行理解一些容易被忽视的知识点.

npm

npm 是Node Package Manage的缩写, 是Node.js的官方包管理器, 目前已经是世界上最大的包管理器了, 如果你会iOS, 就理解成cocoapods就好了.

要使用npm, 我们就必须要配置Node环境, 好在现在只需要在Node官网上下载就可以了. 如果速度慢的话可以切换淘宝镜像

Express

$ npm install express-generator -g $ express -e .

使用npm 先进行全局安装, 并进行server的脚手架创建.

package.json

package.json就是npm的包配置文件了, 通过终端npm init进行生成, 和cocoapods的Pods.profile是一个类型的东西.

我们先把需要配置的东西配置好:

{
  "name": "gulp",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "babel": "^6.23.0",
    "babel-core": "^6.26.0",
    "babel-loader": "^7.1.2",
    "babel-preset-env": "^1.6.0",
    "babel-preset-es2015": "^6.24.1",
    "connect-livereload": "^0.6.0",
    "del": "^3.0.0",
    "gulp": "^3.9.1",
    "gulp-concat": "^2.6.1",
    "gulp-if": "^2.0.2",
    "gulp-live-server": "0.0.31",
    "gulp-livereload": "^3.8.1",
    "gulp-plumber": "^1.1.0",
    "gulp-rename": "^1.2.2",
    "gulp-sequence": "^0.4.6",
    "gulp-uglify": "^3.0.0",
    "gulp-util": "^3.0.8",
    "require-dir": "^0.3.2",
    "vinyl-named": "^1.1.0",
    "webpack": "^3.5.5",
    "webpack-stream": "^4.0.0",
    "yargs": "^8.0.2"
  }
}

配好的项目依赖可以通过 npm install进行加载, 或则手动 npm xxx –save-dev进行配置.

gulpfile.babel.js

使用gulp必须创建这样一个文件, 对于使用的Demo可以从Google的github/web-starter-kit上查看.

对于gulp的API也可以在官方文档上查找 –> 官网文档

我们要做的就是读取文件夹下的配置文件默认读取default.js

import requireDir from 'require-dir';

requireDir('./tasks');

default.js

import gulp from 'gulp';

gulp.task('default', ['build']);

gulp.task(name[, deps], fn)

定义一个使用 Orchestrator 实现的任务(task)

name 任务的名字,如果你需要在命令行中运行你的某些任务,那么,请不要在名字中使用空格。

deps 类型: Array 一个包含任务列表的数组,这些任务会在你当前任务运行之前完成。

注意: 默认的,task 将以最大的并发数执行,也就是说,gulp 会一次性运行所有的 task 并且不做任何等待。如果你想要创建一个序列化的 task 队列,并以特定的顺序执行,你需要做两件事:

给出一个提示,来告知 task 什么时候执行完毕, 并且再给出一个提示,来告知一个 task 依赖另一个 task 的完成。

build.js

import gulp from 'gulp';
import gulpSequence from 'gulp-sequence';

gulp.task('build', gulpSequence('clean', 'css', 'pages', 'scripts', ['browser', 'serve']));

通过gulp-sequence进行任务的排序, 按顺序执行.

args.js

yargs是一个命令行工具集, 我们可以配置以下参数:

import yargs from 'yargs';

const args = yargs

  .option('production', {
    boolean: true,
    default: false,
    describe: 'min all scripts'
  })

  .option('watch', {
    boolean: true,
    default: false,
    describe: 'watch all files'
  })

  .option('verbose', {
    boolean: true,
    default: false,
    describe: 'log'
  })

  .option('sourcemaps', {
    describe: 'force the creation of sroucemaps'
  })

  .option('port', {
    string: true,
    default: 8080,
    describe: 'server port'
  })

  .argv

export default args;

clean.js

import gulp from 'gulp';
import del from 'del';
import args from './util/args';

gulp.task('clean', () => {
  return del(['server/public', 'server/views']);
})

通过 del模块进行制定路径的清空操作.

scripts.js

import gulp from 'gulp';
import gulpif from 'gulp-if';
import concat from 'gulp-concat';
import webpack from 'webpack';
import gulpWebpack from 'webpack-stream';
import named from 'vinyl-named';
import livereload from 'gulp-livereload';
import plumber from 'gulp-plumber';
import rename from 'gulp-rename';
import uglify from 'gulp-uglify';
import {log,colors} from 'gulp-util';
import args from './util/args';

gulp.task('scripts',()=>{ //执行scripts任务
  return gulp.src(['app/js/index.js']) //读取资源文件
    .pipe(plumber({ //处理错误
      errorHandle:function(){

      }
    }))
    .pipe(named()) 
    .pipe(gulpWebpack({ //Webpack配置
      module:{
        loaders:[{
          test:/\.js$/,
          loader:'babel-loader' //Babel
        }]
      }
    }),null,(err,stats)=>{
      log(`Finished '${colors.cyan('scripts')}'`,stats.toString({
        chunks:false
      }))
    })
    .pipe(gulp.dest('server/public/js')) //重置备份
    .pipe(rename({ //重命名
      basename:'cp',
      extname:'.min.js'
    }))
    .pipe(uglify({compress: //压缩{properties:false},output:{'quote_keys':true}}))
    .pipe(gulp.dest('server/public/js')) //重置备份
    .pipe(gulpif(args.watch,livereload())) //热更新
})

gulp.src(globs[, options])

输出(Emits)符合所提供的匹配模式(glob)或者匹配模式的数组(array of globs)的文件。 将返回一个 Vinyl files 的 stream 它可以被 piped 到别的插件中。

gulp.dest(path[, options])

能被 pipe 进来,并且将会写文件。并且重新输出(emits)所有数据,因此你可以将它 pipe 到多个文件夹。如果某文件夹不存在,将会自动创建它。

具体请参考文档.

browser.js

import gulp from 'gulp';
import gulpif from 'gulp-if';
import gutil from 'gulp-util';
import args from './util/args';

gulp.task('browser', (cb) => {
  if (!args.watch) return cb();

  gulp.watch('app/**/*.js', ['scripts']);
  gulp.watch('app/**/*.ejs', ['pages']);
  gulp.watch('app/**/*.css', ['css']);
});

gulp.watch(glob [, opts], tasks)gulp.watch(glob [, opts, cb])

监视文件,并且可以在文件发生改动时候做一些事情。它总会返回一个 EventEmitter 来发射(emit) change 事件。

注意点: 路径中的/**/*代表任意路径.

server.js

import gulp from 'gulp';
import gulpif from 'gulp-if';
import liveserver from 'gulp-live-server';
import args from './util/args';

gulp.task('serve', (cb) => {
  if (!args.watch) return cb();

  var server = liveserver.new(['--harmony', 'server/bin/www']);
  server.start();
  gulp.watch(['server/public/**/*.js', 'server/views/**/*.ejs'], function(file) {
    server.notify.apply(server, [file]);
  })

  gulp.watch(['server/routes/**/*.js', 'server/app.js'], function() {
    server.start.bind(server)();
  })
})

开启服务器, 当路径文件监听到有改变时, 告知服务器进行自动刷新页面.

.babelrc

为了能让文件跑起来我们先简陋的配置如下:

{
  "presets" : ["es2015"]
}

Babel 是一个 JavaScript 编译器,没什么复杂的 可以直接官网学习

Terminal

这样我们的架构就算是搭建成功了, 最后我们看着终端的代码来总结一下流程:

  • 1 执行了build任务,
  • 2 执行了clean任务, 清空了指定路径的文件,
  • 3 执行了css & pages & scripts任务, 将在书写路径的文件保存至服务器路径中, 并在scripts任务中使用webpack进行babel-loader及压缩, 热更新等操作.
  • 4 执行了browser任务, 对相关路径进行监听,
  • 5 执行了serve任务, 开启服务器并监测是否需要热更新及重启.

由于流程过于简单就不上传github, 需要的可以私信要源码哦.

最近的文章

Web 使用webpack构建前端项目

好久没写技术博客了, 原因在于最近在学习前端方面的技术, 熟悉我的同学都知道, 之前我有使用Vue搭建了一个个人简历, 体验了一把最新的前端技术, 但之前我们使用的是vue-cli脚手架工具, 对于如何自己实现前端构建工具, 当下最为流行的就是webpack和gulp了, 之前一篇我们讲了gulp, 这一篇我们来好好讨论webpack.说起webpack, 想必做前端的同学肯定不会陌生, 其实之前我们使用gulp构建的时候, 也使用了webpack的打包技术, 其实gulp和webpa...…

前端开发继续阅读
更早的文章

iOS 移动端生成工具开发

上个月的一篇移动端面向文档开发一文久违的被编辑推荐到了首页, 也引来了饿了么大神的关注, 虽然最后实力不济未被录用, 但也指明了我前进的方向. 从4月到现在从一个想法到一步步的实现, 感觉自己还是有充足的长进的, 今天我们继续来完善这个项目.参考链接: iOS 执行.py脚本生成解耦架构 iOS 执行.py脚本生成UI层结构 iOS 移动端面向文档开发之前有写过一个python脚本的生成工具, 通过读取json文件进行代码的生成, 实际操作中部分使用者反映, json文件的可读性...…

移动开发继续阅读