前端工程化-02-初識gulp

基於流的構建系統

gulp基本使用

# 初始化項目
yarn init -y
# 安裝gulp
yarn add gulp -D

項目根目錄創建 gulpfile.js 文件 (gulp入口文件)

定義一個基本任務

// 定義一個構件任務
exports.foo = done => {
    console.log('hello foo')
    // 標識任務完成
    done()
}

執行 yarn gulp foo

定義一個默認任務

// 定義一個默認構建任務
exports.default = done => {
    console.log('hello default')
    // 標識任務完成
    done()
}

執行 yarn gulp

組合任務

const {
    series,
    parallel
} = require('gulp')

const task1 = done => {
    setTimeout(() => {
        console.log('task1 working')
        done()
    }, 300)
}
const task2 = done => {
    setTimeout(() => {
        console.log('task2 working')
        done()
    }, 200)
}
const task3 = done => {
    setTimeout(() => {
        console.log('task3 working')
        done()
    }, 100)
}
// 通過 series 串行任務
exports.series = series(task1, task2, task3)
// 通過 parallel 並行任務
exports.parallel = parallel(task1, task2, task3)

分別調用 yarn gulp series 和 yarn gulp parallel 可以查看效果

異步任務

回調方式

// 回調函數方式
exports.callback = done => {
    console.log('calback task')
    done()
}
// 錯誤優先回調函數
exports.callback_err = done => {
    console.log('calback task')
    done(new Error('task failed'))
}

promise

// 使用promise
exports.promise = () => {
    console.log( `Promise task` )
    return Promise.resolve()
}

// 使用promise 拋出異常
exports.promise_err = () => {
    console.log( `Promise task` )
    return Promise.reject( `failed Promise` )
}

async

// 模擬異步請求
const timeroutPromise = time => {
    return new Promise(resolve => {
        console.log( `等待${time}` )
        setTimeout(resolve, time)
    })
}
// 模擬錯誤異步請求
const errPromise = time => {
    return new Promise((resolve, reject) => {
        console.log( `等待${time}` )
        setTimeout(reject, time)
    })
}

// 使用 async
exports.async = async () => {
    await timeroutPromise(100)
    console.log( `async task` )
}

// 使用 async
exports.async_err = async () => {
    await errPromise(100)
    console.log( `asyncerr task` )
}

流操作(常用)

const fs = require('fs')
// stream 流操作
exports.stream = () => {
    // 讀取定義
    const readStream = fs.createReadStream('package.json')
    // 寫入定義
    const writeStream = fs.createWriteStream('package.json.tmp')
    // 管道操作
    readStream.pipe(writeStream)
    return readStream
}
// stream 使用回調方式模擬流操作結束 
exports.streamMock = done => {
    // 讀取定義
    const readStream = fs.createReadStream('package.json')
    // 寫入定義
    const writeStream = fs.createWriteStream('package.json.tmp')
    // 管道操作
    readStream.pipe(writeStream)
    readStream.on('end', () => {
        done()
    })
}

構建過程核心原理

模擬壓縮CSS

目錄結構如下

├── dist
├── gulpfile.js
├── package.json
├── package.json.tmp
├── src
│   └── style.css
└── yarn.lock

style.css

/* body註釋 */
body {
    background: #ffffff;
}

/* html註釋 */
html {
    background: #e0e5e5;
}

gulpfile.js

const fs = require('fs')
const {
    Transform
} = require('stream')
exports.default = () => {
    // 文件讀取流
    const read = fs.createReadStream('src/style.css')
    // 文件寫入流
    const write = fs.createWriteStream('dist/style.min.css')
    // 文件轉換流
    const transform = new Transform({
        transform: (chunk, encoding, callback) => {
            // 核心轉換過程實現
            // chunk => 讀取流中讀取到內容(Buffer)
            const input = chunk.toString()
            // 模擬壓縮轉換
            const output = input.replace(/\s+/g, '').replace(/\/\*.+?\*\//g, '')
            // 返回結果,第一個參數是異常 沒有異常傳 null ,第二個參數是返回值
            callback(null, output)
        }
    })
    // 管道操作
    read
        .pipe(transform) //轉換
        .pipe(write) // 寫入
    return read
}

執行 yarn gulp

文件操作APi以及轉換流

將 src/*.css 導入到 dist目錄下

const {
    src,
    dest
} = require('gulp')

exports.default = () => {
    return src('src/*.css')
        .pipe(dest('dist'))
}

安裝 yarn add gulp-clean-css -D (壓縮css)

安裝 yarn add gulp-rename -D (重命名)

// 將 src/*.css 導入到dist目錄下並壓縮且重命名
const {
    src,
    dest
} = require('gulp')
// 引入壓縮css插件
const cleanCss = require('gulp-clean-css')
// 引入重命名插件
const rename = require('gulp-rename')
exports.default = () => {
    return src('src/*.css')
        .pipe(cleanCss())
        .pipe(rename({
            extname: '.min.css'
        }))
        .pipe(dest('dist'))
}

gulp-常見構建任務

git clone [email protected]:zce/zce-gulp-demo.git 下載模板項目

# 安裝gulp 
yarn add gulp -D 
# 創建gulpfile文件
echo gulpfile.js

引入gul並導出src dest

const {
    src,
    dest
} = require('gulp')

樣式編譯

// yarn add gulp-sass -D  
const sass = require('gulp-sass')
const style = () => {
    // 下劃線 _xx.scss會被忽略過
    return src('src/assets/styles/*.scss', {
            base: 'src'
        })
        .pipe(sass({
            // 設置輸出爲展開模式
            outputStyle: 'expanded'
        }))
        .pipe(dest('dist'))
}

js文件編譯

// yarn add gulp-babel @babel/preset-env @babel/core -D  
const babel = require('gulp-babel')
const script = () => {
    return src('src/assets/scripts/*.js', {
            base: 'src'
        })
        .pipe(babel({
            presets: ['@babel/preset-env']
        }))
        .pipe(dest('dist'))
}

模板文件編譯

// yarn add gulp-swig -D  
const swig = require('gulp-swig')
const page = () => {
    // **/* 所有子目錄通配方式
    return src('src/*.html', {
            base: 'src'
        })
        .pipe(swig({
            // 需要設置 cache 爲false,否則後面的自動更新不會生效
            defaults: {
                cache: false
            },
            data
        }))
        .pipe(dest('dist'))
}

圖片壓縮

// yarn add gulp-imagemin -D
const imagemin = require('gulp-imagemin')
const image = () => {
    return (src('src/assets/images/**', {
            base: 'src'
        }))
        .pipe(imagemin())
        .pipe(dest('dist'))
}

字體文件處理

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

無需處理文件複製到dist

// 額外文件拷貝
const extra = () => {
    return (src('public/**', {
            base: 'public'
        }))
        .pipe(dest('dist'))
}

自動刪除dist

// yarn add del -D 
const del = require('del')
const clean = () => {
    return del(['dist'])
}

useref 文件引用處理(處理文件引用關係)

// yarn add gulp-useref -D 
const useref = require('gulp-useref')
const useRef = () => {
    return (src('dist/**/*.html', {
            base: 'dist'
        }))
        .pipe(useref({
            searchPath: ['dist', '.']
        }))
        .pipe(dest('dist'))
}

壓縮文件

// 壓縮文件
// gulp-if 判斷
//  html js css 壓縮
// yarn add gulp-htmlmin gulp-uglify gulp-clean-css gulp-if -D -D 
const useref = require('gulp-useref')
const gulpif = require('gulp-if')
const htmlmin = require('gulp-htmlmin')
const cleanCss = require('gulp-clean-css')
const uglify = require('gulp-uglify')
const useRef = () => {
    return (src('dist/**/*.html', {
            base: 'dist'
        }))
        .pipe(useref({
            searchPath: ['dist', '.']
        }))
        // 壓縮js
        .pipe(gulpif(/\.js$/, uglify()))
        // 壓縮css
        .pipe(gulpif(/\.css$/, cleanCss()))
        // 壓縮html
        .pipe(gulpif(/\.html$/, htmlmin({
            minifyCSS: true,
            minifyCSS: true,
            minifyURLs: true,
            collapseWhitespace: true,
            removeComments: true
        })))
        .pipe(dest('release'))
}

組合功能

const {
    parallel,
    series
} = require('gulp')

// 開發打包
const compile = series(clean, parallel(style, script, page))

// 生產環境打包
const build = series(compile, parallel(image, font), extra, useRef)

熱更新服務器

const browserSync = require('browser-sync')
const bs = browserSync.create()
const server = () => {
    watch('src/assets/styles/*.scss', style)
    watch('src/assets/scripts/**/*.js', script)
    watch('src/**.html', page)
    watch(['src/assets/fonts/**', 'src/assets/images/**', 'public/**'], bs.reload)
    bs.init({
        // 關閉右上角提示
        notify: false,
        // 端口
        port: 6001,
        // 不默認打開
        open: false,
        // 監聽文件變化,自動刷新
        files: "dist/**",
        // 服務設置
        server: {
            // 運行文件夾
            baseDir: ['dist', 'src', 'public'],
            // 配置映射,routes 高於 baseDir
            routes: {
                ///node_modules 映射到工程下的node_modules
                '/node_modules': 'node_modules'
            }
        }
    })
}
// 組合出dev功能,先編譯在啓動
const dev = series(compile, server)

gulp自動載入包

yarn add gulp - load - plugins - D
const loadPlugins = require('gulp-load-plugins')
const plugins = loadPlugins()
// 使用方式 
// plugins.babel  
// 如果是 gulp-ab-cd-ef
// 調用名爲 abCdEf

完整的gulpfile.js文件

const data = {
    menus: [{
            name: 'Home',
            icon: 'aperture',
            link: 'index.html'
        },
        {
            name: 'Features',
            link: 'features.html'
        },
        {
            name: 'About',
            link: 'about.html'
        },
        {
            name: 'Contact',
            link: '#',
            children: [{
                    name: 'Twitter',
                    link: 'https://twitter.com/w_zce'
                },
                {
                    name: 'About',
                    link: 'https://weibo.com/zceme'
                },
                {
                    name: 'divider'
                },
                {
                    name: 'About',
                    link: 'https://github.com/zce'
                }
            ]
        }
    ],
    pkg: require('./package.json'),
    date: new Date()
}

const {
    src,
    dest,
    watch
} = require('gulp')
const del = require('del')

const loadPlugins = require('gulp-load-plugins')
const plugins = loadPlugins()

// 樣式編譯
const style = () => {
    // 下劃線 _xx.scss會被忽略過
    return src('src/assets/styles/*.scss', {
            base: 'src'
        })
        .pipe(plugins.sass({
            // 設置輸出爲展開模式
            outputStyle: 'expanded'
        }))
        .pipe(dest('temp'))
        .pipe(bs.reload({
            stream: true
        }))
}

// js文件編譯
const script = () => {
    return src('src/assets/scripts/*.js', {
            base: 'src'
        })
        .pipe(plugins.babel({
            presets: ['@babel/preset-env']
        }))
        .pipe(dest('temp'))
        .pipe(bs.reload({
            stream: true
        }))
}

// 模板文件編譯
const page = () => {
    // **/* 所有子目錄通配方式
    return src('src/*.html', {
            base: 'src'
        })
        .pipe(plugins.swig({
            // 需要設置 cache 爲false,否則後面的自動更新不會生效
            defaults: {
                cache: false
            },
            data
        }))
        .pipe(dest('temp'))
        .pipe(bs.reload({
            stream: true
        }))
}

// 圖片壓縮
const image = () => {
    return (src('src/assets/images/**', {
            base: 'src'
        }))
        .pipe(plugins.imagemin())
        .pipe(dest('dist'))
}

// 字體文件
const font = () => {
    return (src('src/assets/fonts/*', {
            base: 'src'
        }))
        .pipe(plugins.imagemin())
        .pipe(dest('dist'))
}

// 額外文件拷貝
const extra = () => {
    return (src('public/**', {
            base: 'public'
        }))
        .pipe(dest('dist'))
}

// 自動刪除dist文件
const clean = () => {
    return del(['dist', 'temp'])
}
const useref = () => {
    return (src('temp/**/*.html', {
            base: 'temp'
        }))
        .pipe(plugins.useref({
            searchPath: ['temp', '.']
        }))
        // 壓縮js
        .pipe(plugins.if(/\.js$/, plugins.uglify()))
        // 壓縮css
        .pipe(plugins.if(/\.css$/, plugins.cleanCss()))
        // 壓縮html
        .pipe(plugins.if(/\.html$/, plugins.htmlmin({
            minifyCSS: true,
            minifyCSS: true,
            minifyURLs: true,
            collapseWhitespace: true,
            removeComments: true
        })))
        .pipe(dest('dist'))
}

// 組合功能
const {
    parallel,
    series
} = require('gulp')

const compile = parallel(style, script, page)

const build = series(clean, parallel(series(compile, useref), image, font, extra))

// 優化開發環境 減少不必要開銷 例如圖片壓縮 字體壓縮
const browserSync = require('browser-sync')
const bs = browserSync.create()
const server = () => {
    watch('src/assets/styles/*.scss', style)
    watch('src/assets/scripts/**/*.js', script)
    watch('src/**.html', page)
    watch(['src/assets/fonts/**', 'src/assets/images/**', 'public/**'], bs.reload)
    bs.init({
        // 關閉右上角提示
        notify: false,
        // 端口
        port: 6001,
        // 不默認打開
        open: false,
        // 服務設置
        server: {
            // 運行文件夾
            baseDir: ['temp', 'src', 'public'],
            // 配置映射,routes 高於 baseDir
            routes: {
                ///node_modules 映射到工程下的node_modules
                '/node_modules': 'node_modules'
            }
        }
    })
}
const dev = series(compile, server)
module.exports = {
    build,
    dev,
    clean
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章