es6运行在浏览器的前端项目工作流, 基于gulp,express,webpack构建

项目自动化构建思路

image.png

自动化构建逻辑

  1. 若app文件夹(前端静. 态页面)资源发生改变 ->
  2. 调用browser.js脚本 ->
  3. browser.js运行script脚本 ->
  4. 将新的js文件打包后写入server目录public目录下 ->
  5. 此行为触发server.js监听到服务端js静态资源文件被修改 ->
  6. 执行服务器重启重新渲染页面 ->
  7. 前台看到浏览器热更新

构建目录结构,安装服务端脚手架工具

  1. 创建项目目录 app(放置静态页面资源),server(用express脚手架初始化,将来放入热更新后的静态资源),tasks放置所有上述过程的脚本文件
  2. 初始化服务端express
    npm install -g express-generator //安装express脚手架
    express -e . //使用express脚手架命令,初始化脚手架,-e代表使用ejs模板引擎
  3. 在根目录创建 .babelrc文件,此为babel转码器
  4. 在根目录创建gulpfile.js, 若用es6语法写gulpfile文件就创建gulpfile.babel.js

gulp工作流代码构建流程


处理命令行参数

import yargs from 'yargs'; //处理命令行参数的包
//区分开发环境和线上环境
const args = yargs  
  //提取--production参数
  .option('production',{ 
    boolean:true,//选项是布尔类型
    default:false,//默认是false
    describe:'min all scripts' //只是给人看的描述
  })
  //用来监听文件改变的选项
  .option('watch',{
    boolean:true,
    default:false,
    describe:'watch all files'
  })
  //要不要输出命令行详细监视的日志
  .option('verbose',{
    boolean:true,
    default:false,
    describe:'log'
  })
  //强制生成sourcemaps映射
  .option('sourcemaps',{
    describe:'force the creation of sroucemaps'
  })
  //端口号
  .option('port',{
    string:true,
    default:8080,
    describe:'server port'
  })
  //表示把输入的命令以字符串的方式进行解析
  .argv

export default args;

处理js

import gulp from 'gulp';
import gulpif from 'gulp-if'; //gulp语句中做if判断
import concat from 'gulp-concat'; //gulp中处理文件拼接
import webpack from 'webpack';
import gulpWebpack from 'webpack-stream'; //支持webpack在gulp stream中的功能
import named from 'vinyl-named'; //保证webpack生成的文件名能够和原文件对上
import livereload from 'gulp-livereload'; //浏览器热更新
import plumber from 'gulp-plumber'; //处理文件信息流
import rename from 'gulp-rename'; //对文件重命名
import uglify from 'gulp-uglify'; //压缩js
import {log, colors} from 'gulp-util'; //命令行工具包,log与色彩输出
import args from './util/args'; //刚自己写的对命令行参数进行解析的包

// 为了集中处理项目js文件抛出异常引起gulp流出现问题,需用plumber统一处理错误
gulp.task('scripts', () => {
  return gulp
    .src(['app/js/index.js'])
    .pipe(plumber({errorHandle: function () {}}))
    .pipe(named())
    .pipe(gulpWebpack({
      module: {
        loaders: [
          {
            test: /\.js$/,
            loader: 'babel-loader'
          }
        ]
      }
    }), null, (err, stats) => {
      log(`Finished '${colors.cyan('scripts')}'`, stats.toString({chunks: false}))
    })
    //gulp处理完的js指定写入路径,api:gulp.dest
    .pipe(gulp.dest('server/public/js'))
    //js文件重命名为cp.min.js,还没压缩,只是复制一份
    .pipe(rename({basename: 'cp', extname: '.min.js'}))
    // 压缩
    .pipe(uglify({
      compress: {
        properties: false
      },
      output: {
        'quote_keys': true
      }
    }))
    // 把压缩后的文件放入服务器目录
    .pipe(gulp.dest('server/public/js'))
    // 使用gulpif监视命令行传入的参数,若有--watch,则执行热更新
    .pipe(gulpif(args.watch, livereload()))
})

处理后台页面模板

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

gulp.task('pages',()=>{
  return gulp.src('app/**/*.ejs')
    .pipe(gulp.dest('server')) //文件被写入的路径是以所给的相对路径根据所给的目标目录计算而来。类似的,相对路径也可以根据所给的 base 来计算。这里实际写到的路径是server下的/**/*.ejs,即server/views/*.ejs
    .pipe(gulpif(args.watch,livereload()))
})

处理css

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

gulp.task('css',()=>{
  return gulp.src('app/**/*.css')
    .pipe(gulp.dest('server/public'))
    //文件被写入的路径是以所给的相对路径根据所给的目标目录计算而来。类似的,相对路径也可以根据所给的 base 来计算。这里实际写到的路径是server下的/**/*.css,即server/public/css/*.css
    .pipe(gulpif(args.watch,livereload()))
})

处理服务端热重启

import gulp from 'gulp';
import gulpif from 'gulp-if';
import liveserver from 'gulp-live-server'; //启动gulp服务器的包
import args from './util/args';

gulp.task('serve',(cb)=>{
  //如果没在监听,直接运行回调函数
  if(!args.watch) return cb(); 
  //启动express脚手架默认的服务器脚本
  const server = liveserver.new(['--harmony','server/bin/www']); 
  server.start();
  //监听server目录下的js文件和ejs模板文件,通知服务器哪些文件改变了
  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)()
  });
})

处理浏览器热更新

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']);//若js文件发生改变,则调用刚才创建的scripts脚本
  gulp.watch('app/**/*.ejs',['pages']); //同上
  gulp.watch('app/**/*.css',['css']); //同上
});

处理服务器清除旧文件

每次服务器监听到静态资源文件的改变, 会触发重启, 用新的静态资源去render页面,此时需要删除旧的静态资源文件

import gulp from 'gulp';
import del from 'del';
import args from './util/args';
//清除服务端的静态资源文件和模板文件
gulp.task('clean',()=>{
  return del(['server/public','server/views'])
})

build.js处理所有gulp文件运行关联顺序

import gulp from 'gulp';
import gulpSequence from 'gulp-sequence'; //处理文件关联关系和先后顺序

//先clean,再css,再pages,再编译js,最后一个数组说明数组里的任务都放在前面四个任务执行过一次之后再执行,且serve端更新一定 在 browser静态资源改变之后 
gulp.task('build',gulpSequence('clean','css','pages','scripts',['browser','serve']));

default.js gulp工作流默认入口

gulp在无命令行参数时会优先运行defalut.js

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

gulp程序入口

import requireDir from 'require-dir';//需要运行某一文件夹的gulp任务
requireDir('./tasks'); //放入tasks目录

编辑.babelrc

{
  "presets":["es2015"],
  "plugins":["transform-decorators-legacy"]
}

给express脚手架添加热更新中间件

//在处理路由前,express优先处理静态资源,若在这个static方法定义的目录中没有找到req.url对应的静态资源,则调用Next()方法传入下一个中间件,最终会传递到路由中间件上
app.use(express.static(path.join(__dirname, 'public')));
//一定要再静态资源设置之后使用热更新中间件,此插件的安装要再最外层项目目录下的依赖安装,而不是server目录的依赖
app.use(require('connect-livereload')());

gulp程序启动

gulp --watch
在app/public/js下写一个简单的js,再在app/public/css下写一个chotee.css,例如

class Chotee{
  constructor(){
    this.name = 'chotee 啊,成功!'
  }
}

const ct1 = new Chotee

document.body.innerHTML = ct1.name;
body {
  background-color: pink;
}

在app/views/目录下的index.ejs模板中引入

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
  <link rel="stylesheet" href="/css/chotee.css">
</head>

<body>
  hello chotee
  <script src="/js/index.js" charset="utf-8"></script>
</body>
</html>

打开浏览器访问localhost:3000端口(express脚手架默认端口), 看到

image.png

成功! 此时再去修改js文件,模板文件,热更新文件,成功,成功,成功!

整个项目github地址: https://github.com/choteewang/gulp-es6-work-flow

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容

  • 在现在的前端开发中,前后端分离、模块化开发、版本控制、文件合并与压缩、mock数据等等一些原本后端的思想开始...
    Charlot阅读 5,386评论 1 32
  • gulpjs是一个前端构建工具,与gruntjs相比,gulpjs无需写一大堆繁杂的配置参数,API也非常简单,学...
    依依玖玥阅读 3,123评论 7 55
  • gulpjs是一个前端构建工具,与gruntjs相比,gulpjs无需写一大堆繁杂的配置参数,API也非常简单,学...
    井皮皮阅读 1,274评论 0 10
  • gulpjs是一个前端构建工具,与gruntjs相比,gulpjs无需写一大堆繁杂的配置参数,API也非常简单,学...
    小裁缝sun阅读 897评论 0 3
  • 对网站资源进行优化,并使用不同浏览器测试并不是网站设计过程中最有意思的部分,但是这个过程中的很多重复的任务能够使用...
    懵逼js阅读 1,026评论 0 8