让我们用gulp写个前端脚手架

栏目: Node.js · 发布时间: 5年前

  • 公司有个新项目要做官网,需要支持国际化,UI设计了很多页面,老板着急要于是我们就直接用 html + css + jquery分工开发了, ,做出来的项目结构是这样的(直接部署到服务器上):
让我们用gulp写个前端脚手架
  • 等到项目维护迭代的时候就很麻烦,遇到了很多问题:
  1. 每个html页面都有导航、footer、head等公共页面,修改需要设计所有文件
  2. 没有使用css预处理器,用惯了sass,css嵌套写起来很别扭
  3. 用惯了ES6,总是想写let
  4. 资源文件没有加hash值
  5. 新加语言种类需要把所有html页面复制一份重新编写
  • 正好最近看招聘信息,好多要求要会用webpack和gulp,就想着学学gulp,用gulp搭个脚手架升级一下官网项目。
  • 下面来介绍一下这个脚手架的搭建过程

项目介绍

项目简介

  1. 项目基于gulp、babel7构建
  2. 使用ejs开发静态页面,支持国际化开发
  3. js支持commenjs规范以及esm规范
  4. 使用sass预处理css,使用postcss处理浏览器后缀
  5. 使用browser-sync构建开发环境,使用http-proxy-middleware处理请求代理

项目结构

├── README.md
├── dev     //开发环境打包代码
├── dist    //生产环境打包代码
├── favicon.ico
├── gulp    //gulp配置
├── gulpfile.babel.js   //babel配置
├── package.json
├── src
│   ├── html    //index入口文件
│   │   ├── ejs
│   │   │   └── footer.ejs
│   │   └── index.html
│   ├── imgs    //图片
│   │   └── 123.jpeg
│   ├── js  //js
│   │   ├── index.js
│   │   └── moduleA.js
│   ├── lang    //国际化语言文件
│   │   ├── en.json
│   │   └── zh-cn.json
│   ├── scss    //sass文件
│   │   ├── common
│   │   │   └── _reset.scss
│   │   └── index.scss
│   └── static  //静态文件
│       └── jquery-3.2.1.min.js
└── user.config.js.config   //开发配置文件
复制代码

使用gulp打包

gulp简介

  • gulp相关内容可以查看官网以及其它文章
  • gulp配置文件中使用相关库可以查询github了解功能以及使用方法

gulp配置

  • gulp主要任务配置都放在了gulp文件夹下
  • 根目录新建了gulpfile.babel.js文件,并使用 require-dir 导入gulp文件夹下的任务
//gulpfile.babel.js文件
import requireDir from 'require-dir'
requireDir('./gulp/task')
requireDir('./gulp')
复制代码
  • 项目分为开发环境和生产环境两个主要任务,/gulp/dev.js是开发环境任务,/gulp/prod.js是生产环境任务,/gulp/task/文件夹下是其他任务

  • npm 命令

"scripts": {
    "start": "npm run dev",//开发环境
    "dev": "gulp dev",
    "build": "gulp prod"//生产环境
},
复制代码

开发与生产

区别

  • 首先看一下生产环境与开发环境区别:
  1. 生产环境需要资源加hash值,防止用户缓存问题
  2. 生产环境需要压缩代码
  3. 开发环境需要建立本地服务器,处理转发请求
  4. 开发环境文件更改需要同步更新,刷新浏览器
  5. 开发环境文件需要添加sourcemap配置,方便检查错误

开发环境

  • gulp dev
gulp.task('dev',
    gulp.series(
        'clean:dev',
        'html:dev',
        gulp.parallel('scss:dev', 'js:dev', 'static:dev', 'favicon:dev'),
        'img:dev',
        'server'
    ))
复制代码
  • 开发环境使用browser-sync 搭建服务器,使用 http-proxy-middleware 代理请求

  • 同时创建user.config.js.config文件,供开发配置服务端口和请求代理配置使用,需要复制一份改为user.config.js,防止多人开发冲突。

  • 开发环境不进行代码压缩等处理,打包后代码放在dev文件夹下

  • /gulp/task/server.js文件中创建server任务

gulp.task('server', function () {
    browserSync.init({
        server: "./dev",
        port: userConfig.port,
        middleware: proxyMiddleware
    });
});
复制代码

生产环境

  • gulp prod
gulp.task('prod',
    gulp.series(
        'clean',
        'html:prod',
        gulp.parallel('scss:prod', 'js:prod', 'static:prod', 'favicon:dist'),
        'img:prod'
    ))
复制代码
  • 生产环境任务主要是在开发环境任务基础上,添加压缩、hash编码等任务,打包文件放在dist文件夹下

文件处理

清理文件夹

  • 打包前使用 gulp-clean 清空dev|dist文件夹,/gulp/task/clean.js文件中的clean:prod、clean:dev、clean任务
gulp.task('clean:prod',function () {
    return gulp.src('./dist', {read: false,allowEmpty: true})
        .pipe(gulpClean());
})
gulp.task('clean:dev',function () {
    return gulp.src('./dev', {read: false,allowEmpty: true})
        .pipe(gulpClean());
})
gulp.task('clean',gulp.parallel('clean:prod','clean:dev'))
复制代码

处理js

  • 由于官网项目不需要太多js操作,因此引入jquery足够了,jquery作为静态文件引入,之后会讲
  • /gulp/task/js.js文件处理js任务,项目js入口代码在/src/js/文件夹下
  • 首先分析一下需求,因为有多个html页面,每个页面需要处理不同的表单和页面逻辑,因此js也需要有多个入口。
  • html中可以使用相对于服务器路径引用js文件
<script src="/js/index.js"></script>
复制代码
  • 使用 browserify 打包js文件,可以支持commonjs模块化,同时也使用了 gulp-babel ,使项目支持SE6语法以及esm模块化开发。
  • 入口文件配置
//如果需要多个入口文件,则继续配置
let entries = [
    {
        name: 'index',
        entry: ['src/js/index.js']
    }
]
复制代码
  • 开发环境处理js,处理流程:任务js:dev->devArrFun循环入口文件->makeBundle打包js->重新命名->生成文件到dev文件夹->同时监听变化->重新打包刷新浏览器
  • 生产环境处理js,处理流程:任务js:prod->prodArrFun循环入口文件->bundle打包js存储在dev文件夹中->任务js:dev2dist压缩js、添加hash、替换html文件中的路径
  • 任务代码
//使用browserify和babel打包js文件
function makeBundle(name,entry){
    if(!bundleArr[name]){
        let b = browserify({
            entries: entry,
            debug: devServer,
            extensions: ['es6'],
        })
            .transform(html2js)
            .transform(babelify)
            .on('error', function (err) { console.error(err); })
        bundleArr[name] = b
    }
    return bundleArr[name]
}

//直接打包不检测更新
function bundle(name,entry){
    let b = makeBundle(name,entry)
    return b
        .bundle()
        .pipe(source(`${name}.js`))
        .pipe(buffer())
        .pipe(replace('@img', 'img'))
        .pipe(gulp.dest('dev/js'))
        .pipe(gulpif(devServer,global.browserSync.reload({stream: true})))//文件变化刷新浏览器
}

//开发环境打包
let devArrFun = entries.map(i=>{//循环入口,每个文件都打包
    return devFun.bind(null,i.name,i.entry)
})

//打包js并检测更新
function devFun(name,entry) {

    devServer = true

    let b = makeBundle(name,entry)

    b.plugin(watchify);

    //文件变化重新打包js
    b.on('update',bundle.bind(null,name,entry))

    return bundle(name,entry)
}

//生产环境打包
let prodArrFun = entries.map(i=>{
    return bundle.bind(null,i.name,i.entry)
})

gulp.task('js',gulp.parallel(prodArrFun))

//开发环境任务
gulp.task('js:dev',gulp.parallel(devArrFun))

//将dev中文件转入dist文件夹中
gulp.task('js:dev2dist',function () {
    return gulp.src('dev/js/*.js')
        .pipe(uglify())
        .pipe(md5(6, './dist/*.html'))
        .pipe(gulp.dest('dist/js'))
})
//生产环境任务
gulp.task('js:prod',gulp.series('js','js:dev2dist'))
复制代码

处理css

  • 使用sass预处理css,使用postcss的autoprefixer添加浏览器前缀,/src/scss/文件夹放置sass入口文件
  • 使用相对于服务器路径引用css文件
<link rel="stylesheet" href="/css/index.css">
复制代码
  • 处理流程依然是查找入口文件,打包scss文件,同时开发环境监听文件变化刷新浏览器,生产环境进一步处理开发环境打包的文件。
  • 任务代码
function scss() {
    return gulp
        .src('./src/scss/*.scss')//查找入口文件
        .pipe(gulpif(devServer,sourcemaps.init()))//开发环境添加sourcemap配置
        .pipe(sass().on('error', sass.logError))
        .pipe(postcss([autoprefixer()]))//添加浏览器前缀
        .pipe(replace('../imgs', '../imgs'))//处理图片路径
        .pipe(replace('../../imgs', '../imgs'))
        .pipe(gulpif(devServer,sourcemaps.write()))
        .pipe(gulp.dest('./dev/css'));//开发环境存放文件
}

gulp.task('scss',scss)

gulp.task('scss:dev', function () {
    devServer = true
    //开发环境监听文件变化重新打包并刷新浏览器
    gulp.watch(['./src/scss/*.scss','./src/scss/*/*.*'], function (event) {
        return scss().pipe(global.browserSync.reload({stream: true}));
    });
    return scss()
});

gulp.task('scss:dev2dist',function () {
    return gulp.src('./dev/css/*.css')
        .pipe(webpcss())//处理webp文件
        .pipe(cleanCSS())//压缩文件
        .pipe(md5(6, './dist/*.html'))//添加hash,并替换html中的文件名称
        .pipe(gulp.dest('./dist/css'));//生产环境保存文件
})

gulp.task('scss:prod', gulp.series('scss','scss:dev2dist'));
复制代码

处理图片

  • css以及html中使用图片可以直接相对路径引用,在scss以及html打包中会替换img文件路径
  • 图片存储在/src/imgs/文件夹中,目前只支持两级目录
  • 开发环境只是图片复制,生产环境会压缩图片、添加hash、替换css\html中的文件
  • 任务代码
const srcArr = ['./src/imgs/*.{png,gif,jpg,jpeg}','./src/imgs/*/*.{png,gif,jpg,jpeg}']

function img(){
    return gulp
        .src(srcArr)
        .pipe(gulp.dest('./dev/imgs'))
}

gulp.task('img',img)

gulp.task('img:dev',function () {

    gulp.watch(srcArr, function (event) {
        return img(event.path)
            .pipe(global.browserSync.reload({stream: true}))
    });

    return img();
})

gulp.task('img:dev2dist',function () {
    return gulp
        .src(srcArr)
        .pipe(imagemin())//压缩图片
        .pipe(md5(6, ['./dist/*.html', './dist/css/*.css', './dist/js/*.js']))//添加hash,替换文件名
        .pipe(gulp.dest('./dist/imgs'))
})

gulp.task('img:prod',gulp.series('img','img:dev2dist'))
复制代码

处理静态文件

  • jquery等其他库可以放在/src/static/文件加下,在html中使用相对于服务器路径引用即可,/gulp/task/static.js中的任务负责,处理静态资源的复制。
<script src="/static/jquery-3.2.1.min.js"></script>
复制代码

ejs以及国际化配置

  • 最后一项是对于html的处理,再来回顾一下我们的需求
  1. 导航、footer、head等可以使用公共模板
  2. 添加国际化配置文件可以生成不同语言页面
  • 因此我使用了ejs 来编写html,同时添加语言配置的json文件,打包出不同的语言页面

处理公共html模块

  • /src/html/文件夹存放html以及ejs文件,使用ejs加载公共模块
<%- include('ejs/footer',{type: common.type}) %>
复制代码

html入口

  • 处理html的任务在/task/html.js中,每次新增页面,需要配置html入口文件
//该配置会打包出index.html(中文)以及index-en.html(英文)两个页面
//html入口文件
let htmlConfig = [
    {
        entry: 'src/html/index.html',
        name: 'index.html',//打包后文件名
        lang: 'zh-cn'//ejs语言配置文件,对应/src/lang下的json文件
    },
    {
        entry: 'src/html/index.html',
        name: 'index-en.html',
        lang: 'en'
    },
]
复制代码

国际化处理

  • /src/lang/文件夹中为不语言添加不同配置
  • 举个例子:
  1. 比如en.json以及zh-cn.json的配置如下
//en.json
{
    "footer": "footer"
}
//zh-cn.json
{
    "footer": "福特儿"
}
复制代码
  1. ejs中使用模板
<div><%= footer %></div>
复制代码
  1. 打包出html分别为
//index.html
<div>福特儿</div>
//index-en.html
<div>footer</div>
复制代码
  • 我们还可使用ejs其他语法编写比如:按条件渲染生成不同html处理页面差异、用变量处理dom元素属性、生成不同class处理语言显示等问题,这些就需要靠你的智慧了。

  • 任务代码

//处理ejs模板
function html(config){
    return gulp
        .src(config.entry)
        .pipe(data(function(file) {//加载语言配置
            return JSON.parse(fs.readFileSync(`src/lang/${config.lang}.json`))
        }))
        .pipe(replace('../imgs', './imgs'))//替换图片路径
        .pipe(replace('../../imgs', './imgs'))
        .pipe(ejs().on('error', handleError))//错误处理
        .pipe(rename(config.name))//替换文件名
        .pipe(gulp.dest('dev'))
}

let htmlDevArr = htmlConfig.map(config=>{
    return function (config) {
        //监听变化重新打包并且刷新浏览器
        gulp.watch([config.entry,'src/html/*/*.*','src/lang/*'], function (event) {
            return html(config).pipe(global.browserSync.reload({stream: true}));
        });
        return html(config)
    }.bind(null,config)
})

//开发环境命令
gulp.task('html:dev',gulp.parallel(htmlDevArr))

gulp.task('html:dev2dist',function () {
    return gulp
        .src('dev/*.html')
        .pipe(htmlmin({ collapseWhitespace: true }))//压缩html
        .pipe(gulp.dest('dist'))
})

let htmlProdArr = htmlConfig.map(config=>{
    return function (config) {
        return html(config)
    }.bind(null,config)
})
//生产环境命令
gulp.task('html:prod',gulp.series(gulp.parallel(htmlProdArr),'html:dev2dist'))
复制代码

错误处理

  • 开发中还遇到了一个问题:ejs模板报错时会停止gulp任务,需要使用 gulp-notify 处理报错,防止任务终止
const notify = require("gulp-notify");
module.exports = function(){
    var args = Array.prototype.slice.call(arguments)

    notify.onError({
        title: 'compile error',
        message: '<%=error.message %>'
    }).apply(this, args)

    this.emit();
}
复制代码

总结

  • 以上就是gulp官网项目脚手架搭建过程,由于是一边学习gulp一边搭的,很多处理方法都是一边搜索一边找合适的加上的,希望大家多提意见。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

PCI Express 体系结构导读

PCI Express 体系结构导读

王齐 / 机械工业 / 2010-3 / 55.00元

《PCI Express 体系结构导读》讲述了与PCI及PCI Express总线相关的最为基础的内容,并介绍了一些必要的、与PCI总线相关的处理器体系结构知识,这也是《PCI Express 体系结构导读》的重点所在。深入理解处理器体系结构是理解PCI与PCI Express总线的重要基础。 读者通过对《PCI Express 体系结构导读》的学习,可超越PCI与PCI Express总线......一起来看看 《PCI Express 体系结构导读》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具