使用gulp构建一个小型项目

315 阅读7分钟

项目结构

项目整体结构如下:

|____public
| |____favicon.ico
|____src
| |____assets
| | |____fonts
| | | |____pages.eot
| | | |____pages.svg
| | | |____pages.ttf
| | | |____pages.woff
| | |____images
| | | |____brands.svg
| | | |____logo.png
| | |____scripts
| | | |____main.js
| | |____styles
| | | |_icons.scss
| | | |_variables.scss
| | | |main.scss
| |____layouts
| | |____basic.html
| |____partials
| | |____footer.html
| | |____header.html
| |____about.html
| |____index.html
|____package.json

pubilc中都是静态文件无需编译,src下是源代码,需要构建成浏览器认识的代码哦。

开始前先把今天的主角gulp安装上, 安装在开发依赖哦 yarn add gulp -D

进入正题

样式编译

当前项目下创建gulpfile.js文件,进入该文件开始写我们的构建任务,默认构建到dist文件

const {src, dest} = require('gulp')
const style = () => {
    return src('src/assets/styles/*.scss', {base: 'src'})
    .pipe(dest('dist'))
}
module.exports = {
    style
}

执行命令

yarn gulp style

得到

image.png

将src/assets/styles的所有css拷贝到dist文件,其中base配置是保证基准路径,保证拷贝的文件路径与src下文件一致

接下来安装插件将scss装换成css

yarn add gulp-sass sass -D

引入sass根据文档

const sass = require('gulp-sass')(require('sass'));

此时style中添加sass转换

const style = () => {
    return src('src/assets/styles/*.scss', {base: 'src'})
    .pipe(sass({outputStyle: 'expanded'}))
    .pipe(dest('dist'))
}

但是再次执行style命令

image.png

脚本编译

与样式的编写一致,切换下插件

yarn add gulp-babel -D

gulp-babel只是挂起babel,核心转换需要babel/core , @babel/preset-env是可以ecma新特性都进行转换

yarn add @babel/core @babel/preset-env -D

编写脚本任务,此时gulpfile.js文件内容是这样的

const { src, dest } = require('gulp')
const sass = require('gulp-sass')(require('sass'));
const babel = require('gulp-babel')
const style = () => {
    return src('src/assets/styles/*.scss', { base: 'src' })
        .pipe(sass({ outputStyle: 'expanded' }))
        .pipe(dest('dist'))
}
const scripts = () => {
    return src('src/assets/scripts/*.js', { base: 'src' })
        .pipe(babel({ presets: ["@babel/preset-env"] }))
        .pipe(dest('dist'))
}
module.exports = {
    style,
    scripts
}

执行脚本命令

image.png

页面html编译

此处需要安装模板引擎,这里用了gulp-swig

yarn add gulp-swig -D
const swig = require('gulp-swig')
// ... other code
const pages = () => {
    return src('src/**/*.html', { base: 'src' })
        .pipe(swig())
        .pipe(dest('dist'))
}

**代表匹配src下任意子目录,此处html文件分别在几个文件里。

image.png

样式,脚本,页面组合

构建时同时调用

const { src, dest, parallel } = require('gulp')
// ...
const compile = parallel(style, scripts, pages)
module.exports = {
    ...,
    compile
}

图片和字体文件转换

安装图片插件

yarn add gulp-imagemin -D

ps: 直接安装gulp-imagemin(当前版本^8.0.0)执行命令会报错,此处处理降了一个版本(^7.1.0)就正常执行了 【且是一个通过c++完成的模块,需要从github上下载,比较慢】 编写任务

const imagemin = require('gulp-imagemin');
//...
const images = () => {
    return src('src/assets/images/**', { base: 'src' })
        .pipe(imagemin())
        .pipe(dest('dist'))
}
//遇到不是图片的文件直接略过,字体文件一般没办法压缩,拷贝就好了
const fonts = () => {
    return src('src/assets/fonts/**', { base: 'src' })
        .pipe(imagemin())
        .pipe(dest('dist'))
}
//...
const compile = parallel(style, scripts, pages, images, fonts)
module.exports = {
    compile
}

此处就直接并行执行所有了

image.png 查看dist文件【执行前已经删除了老dist文件】

image.png

其他文件public及文件清除

这里只有一个文件,直接拷贝就好

|____public
| |____favicon.ico

删除任务需要安装一个插件del【del不是gulp模块,但是可以使用,且返回一个promise方法,gulp支持的】

yarn add del -D

编写拷贝plblic任务

//...其他文件:public
const extra = () => {
    return src('public/**', { base: 'public' })
        .pipe(dest('dist'))
}
//清除任务
const clean = () => {
    return del(['dist'])
}

之前一直手动删除dist文件,现在可执行yarn gulp clean自动删除dist

执行命令yarn gulp extra

image.png

改造下构建任务执行前先删除dist,这里执行build

const { src, dest, parallel, series } = require('gulp')
//...
const compile = parallel(style, scripts, pages, images, fonts)
//构建
const build = series(clean, parallel(compile, extra))
module.exports = {
    compile,
    clean,
    build
}

image.png 看着木有问题哦,先执行的clean,clean结束在执行后续

自动加载插件

使用gulp-load-plugins来解决require插件过多的问题

yarn add gulp-load-plugins -D

ps: 碰到最新版sass单独使用,至少不会报错 插件使用:

const loadPlugins = require('gulp-load-plugins')
const plugins = loadPlugins()
const sass = require('gulp-sass')(require('sass'));
// const babel = require('gulp-babel')
// const swig = require('gulp-swig')
// const imagemin = require('gulp-imagemin');
// const del = require('del')

所有的gulp插件都会被挂载到plugins对象里面,对象的属性命名规则是去掉gulp-,再后面的名字是驼峰式 插件调用更加简单。 如:仅仅是去除了reauire('gulp-babel'), 使用的时候plugins.babel

const scripts = () => {
    return src('src/assets/scripts/*.js', { base: 'src' })
        .pipe(plugins.babel({ presets: ["@babel/preset-env"] }))
        .pipe(dest('dist'))
}

添加开发服务器

安装插件,支持热更新,代码更新后唤醒浏览器

yarn add browser-sync -D

编写启动服务

const browserSync = require('browser-sync');
const bs = browserSync.create();//创建一个开发服务器
//...
// 创建启动服务
const serve = () => {
    // 服务器配置
    bs.init({
        notify: false,//唤醒浏览器后右上角落的提示
        // open: true,//是否自动打开
        // port: 2000,//自定义端口, 默认3000
        files: 'dist/**',//监听哪些文件发生了变化
        server: {
            baseDir: 'dist',//基础目录
        }
    })
}

好像还不错

image.png

监视变化及构建优化

监视变化:开发服务器只能监视dist下的代码变动,不能监视源代码的变动,所以需要加了监视任务,源代码变动了执行对应的构建任务,此时dist变动了开发服务器就能监视到了

gulp提供了watch方法监视源代码,watch两个参数,第一个监听的文件列表,第二个变化后执行的任务

const { src, dest, parallel, series, watch } = require('gulp')
//...
const serve = () => {
    watch('src/assets/styles/*.scss', style)
    watch('src/assets/scripts/*.js', scripts)
    watch('src/**/*.html', pages)
    watch('src/assets/images/**', images)
    watch('src/assets/fonts/**', fonts)
    // public一般不变动,这里不写了
    // 服务器配置
    bs.init({
        notify: false,//唤醒浏览器后右上角落的提示
        // open: true,//是否自动打开
        // port: 2000,//自定义端口, 默认3000
        files: 'dist/**',//监听哪些文件发生了变化
        server: {
            baseDir: 'dist',//基础目录
        }
    })
}

构建优化:主要是watch图片,字体,以及public等这些文件任务 如下:

const serve = () => {
    watch('src/assets/styles/*.scss', style)
    watch('src/assets/scripts/*.js', scripts)
    watch('src/**/*.html', pages)
    // watch('src/assets/images/**', images)
    // watch('src/assets/fonts/**', fonts)
    // public一般不变动,这里不写了

    // 合并到一个监视任务,变动为刷新浏览器,不是执行构建任务,提高开发体验
    watch(['src/assets/images/**', 'src/assets/fonts/**', 'public/**'], bs.reload)
    // 服务器配置
    bs.init({
        notify: false,//唤醒浏览器后右上角落的提示
        // open: true,//是否自动打开
        // port: 2000,//自定义端口, 默认3000
        files: 'dist/**',//监听哪些文件发生了变化
        server: {
            // baseDir: 'dist',//基础目录
            baseDir: ['dist', 'src', 'public'],//dist下找到会到src, public下寻找
        }
    })
}

//执行命令修改
const compile = parallel(style, scripts, pages);

const build = series(clean, parallel(compile, extra, images, fonts));//生产前执行

const start = series(compile, serve);//开发环境,先编译再去启动服务

useref文件引用处理

当前dist下html文件,查看index.html文件 image.png 处理文件引用,插件gulp-useref

yarn add gulp-useref -D

编写任务

// 文件引用处理
const useref = () => {
    return src('dist//**/*.html', { base: 'dist' })//此时创建html
        .pipe(plugins.useref({ searchPath: ['dist', '.'] }))//两个地址, 使用更多的放在前面
        .pipe(dest("release"));
}

防止读写冲突,换了release文件作为导出文件

执行这个命令,可以看到引用的css文件已经被处理

image.png

文件压缩

安装插件

yarn add gulp-htmlmin gulp-uglify gulp-clean-css -D

修改引用任务:修改前安装gulp-if插件【yarn add gulp-if -D】,判断使用

const useref = () => {
    return src('dist/**/.html', { base: 'dist' })//此时创建html
        .pipe(plugins.useref({ searchPath: ['dist', '.'] }))//两个地址, 使用更多的放在前面
        // useref创建了js,css
        .pipe(plugins.if(/\.js$/, plugins.uglify()))
        .pipe(plugins.if(/\.css$/, plugins.cleanCss()))
        .pipe(plugins.if(/\.html$/, plugins.htmlmin({
            collapseWhitespace: true,
            minifyCSS: true,//压缩内联样式
            minifyJS: true,//内联js压缩
        })))
        .pipe(dest("release"));
}

执行命令

image.png

优化构建命令与配置npm Scripts

整体代码:

// 实现这个项目的构建任务
const { src, dest, parallel, series, watch } = require('gulp')

const loadPlugins = require('gulp-load-plugins')
const plugins = loadPlugins()
const sass = require('gulp-sass')(require('sass'));
// const babel = require('gulp-babel')
// const swig = require('gulp-swig')
// const imagemin = require('gulp-imagemin');
const del = require('del')
const browserSync = require('browser-sync');
const bs = browserSync.create();//创建一个开发服务器

//style, scripts,page任务放在临时文件dist,防止读写冲突
const style = () => {
    return src('src/assets/styles/*.scss', { base: 'src' })
        .pipe(sass({ outputStyle: 'expanded' }))
        .pipe(dest('dist'))
}

const scripts = () => {
    return src('src/assets/scripts/*.js', { base: 'src' })
        .pipe(plugins.babel({ presets: ["@babel/preset-env"] }))
        .pipe(dest('dist'))
}

const pages = () => {
    return src('src/**/*.html', { base: 'src' })
        .pipe(plugins.swig())
        .pipe(dest('dist'))
}

const images = () => {
    return src('src/assets/images/**', { base: 'src' })
        .pipe(plugins.imagemin())
        .pipe(dest('release'))
}

const fonts = () => {
    return src('src/assets/fonts/**', { base: 'src' })
        .pipe(plugins.imagemin())
        .pipe(dest('release'))
}

const extra = () => {
    return src('public/**', { base: 'public' })
        .pipe(dest('release'))
}

const clean = () => {
    return del(['dist', 'release'])
}
// 文件引用处理
const useref = () => {
    return src('dist/**/*.html', { base: 'dist' })//此时创建html
        .pipe(plugins.useref({ searchPath: ['dist', '.'] }))//两个地址, 使用更多的放在前面
        // useref创建了js,css
        .pipe(plugins.if(/\.js$/, plugins.uglify()))
        .pipe(plugins.if(/\.css$/, plugins.cleanCss()))
        .pipe(plugins.if(/\.html$/, plugins.htmlmin({
            collapseWhitespace: true,
            minifyCSS: true,//压缩内联样式
            minifyJS: true,//内联js压缩
        })))
        .pipe(dest("release"));
}

// 创建启动服务
const serve = () => {
    watch('src/assets/styles/*.scss', style)
    watch('src/assets/scripts/*.js', scripts)
    watch('src/**/*.html', pages)
    // watch('src/assets/images/*', images)
    // watch('src/assets/fonts/*', fonts)
    // public一般不变动,这里不写了

    // 合并到一个监视任务,变动为刷新浏览器,不是执行构建任务,提高开发体验
    watch(['src/assets/images/**', 'src/assets/fonts/**', 'public/**'], bs.reload)
    // 服务器配置
    bs.init({
        notify: false,//唤醒浏览器后右上角落的提示
        // open: true,//是否自动打开
        // port: 2000,//自定义端口, 默认3000
        files: 'dist/**',//监听哪些文件发生了变化
        server: {
            // baseDir: 'dist',//基础目录
            baseDir: ['dist', 'src', 'public'],//dist下找到会到src, public下寻找
            routes: {
                '/node_modules': 'node_modules'
            }
        }
    })
}

//优化后命令compile, build, start
const compile = parallel(style, scripts, pages);

const build = series(
    clean,
    parallel(
        series(
            compile,
            useref
        ),
        extra,
        images,
        fonts
    )
);//生产前执行

const start = series(compile, serve);//开发环境

module.exports = {
    compile,
    clean,
    build,
    start,
    useref,
    serve
}

package.json命令

image.png