工程化概述

前端工程化解決的問(wèn)題:
  • 傳統(tǒng)語(yǔ)言或語(yǔ)法的弊端 ;
  • 無(wú)法使用模塊化/組件化
  • 重復(fù)的機(jī)械式工作
  • 代碼風(fēng)格統(tǒng)一、質(zhì)量保證
  • 依賴后端服務(wù)接口支持
  • 整體依賴后端項(xiàng)目
腳手架工具

腳手架本質(zhì)作用:創(chuàng)建項(xiàng)目基礎(chǔ)結(jié)構(gòu)蜗元、提供項(xiàng)目規(guī)范和約定

  • 相同的組織結(jié)構(gòu)
  • 相同的開(kāi)發(fā)范式
  • 相同的模塊依賴
  • 相同的工具配置
  • 相同的基礎(chǔ)代碼

步驟:

  • 在全部范圍安裝yo
    npm install yo --global or yarn global add yo
  • 安裝對(duì)應(yīng)的generator
    npm install generator-node or yarn global add genertor-node
  • 安裝yo運(yùn)行g(shù)enerator
    yo node
yeoman的常規(guī)使用步驟
  1. 明確你的需求
  2. 找到合適的Generator
  3. 全局范圍安裝找到的Generator
  4. 通過(guò)Yo運(yùn)行對(duì)應(yīng)的Generator
  5. 通過(guò)命令行交互填寫選項(xiàng)
  6. 生成你所需要的項(xiàng)目結(jié)構(gòu)
自定義Generator
Generator基本結(jié)構(gòu)

index.js1

index.js2
Plop

小而美的腳手架

  • 將plop模塊作為項(xiàng)目開(kāi)發(fā)依賴
  • 在項(xiàng)目根目錄下創(chuàng)建一個(gè)plopfile.js文件
  • 在plopfile.js文件中定義腳手架任務(wù)
  • 編寫用于生成特定類型文件的模板
  • 通過(guò)Plop提供的CLI運(yùn)行腳手架任務(wù)


    plop應(yīng)用文件
自動(dòng)化構(gòu)建工具

grunt 的基本使用:
gruntfile.js 文件

module.exports = grunt => {
    grunt.registerTask('foo', () => {
        console.log('hello grunt~')
    })

    grunt.registerTask('bar', '任務(wù)描述', () => {
        console.log('other task~')
    })

    grunt.registerTask('default', ['foo', 'bar'])

    // grunt.registerTask('async-task', () => {
    //     setTimeout(() => {
    //         console.log('async task working~')
    //     }, 1000)
    // })
     grunt.registerTask('async-task', function () {
        const done = this.async()
        setTimeout(() => {
            console.log('async task working~')
            done(false) //標(biāo)記任務(wù)失敗
        }, 1000)
    })
}

grunt的配置

module.exports = grunt => {
    grunt.initConfig({
        foo: {
            bar: 123
        }
    })
    
    grunt.registerTask('foo', () => {
        console.log(grunt.config('foo'))
    })
}
grunt 的多目標(biāo)任務(wù)
module.exports = grunt => {
    grunt.initConfig({
        build:{
            options: {
                foo: 'bar'
            },
            css: {
                options: {
                    foo: 'baz'
                }
            },
            js: '2'
        }
    })
    //多目標(biāo)模式傻咖,可以讓任務(wù)根據(jù)配置形成多個(gè)子任務(wù)
    grunt.registerMultiTask('build', function () {
        console.log(this.options())
        console.log(`target: ${this.target}, data: ${this.data}`)
    })
}
grunt 的插件的使用
  • 導(dǎo)入插件模塊
  • 然后使用grunt.loadNpmTasks()創(chuàng)建插件任務(wù)
  • initConfig()中配置選項(xiàng)
    插件使用

grunt 使用案例

const sass = require('sass')
const loadGruntTasks = require('load-grunt-tasks')

module.exports = grunt => {
  grunt.initConfig({
        sass: {
            options: {
                sourceMap: true,
                implementation: sass
            },
            main: {
                files: {
                    'dist/css/main.css': 'src/scss/main.scss'
                }
            }
        },
        babel: {
            options: {
                sourceMap: true,
                presets: ['@babel/preset-env']
            },
            main: {
                files: {
                    'dist/js/app.js': 'src/js/main.js'
                }
            }
        },
        watch: {
            js: {
                files: ['src/js/*.js'],
                task: ['babel']
            },
            css: {
                files: ['src/scss/*.scss'],
                tasks: ['sass']
            }
        }
    })

    //自動(dòng)加載所有g(shù)runt 插件任務(wù)
    loadGruntTasks(grunt)

    grunt.registerTask('default', ['sass', 'babel', 'watch'])
    // grunt.loadNpmTasks('grunt-sass')
}

gulp

gulpfile.js

exports.foo = (done) => {
    console.log('foo task working~')
    done() //回調(diào)函數(shù)它碎,標(biāo)識(shí)任務(wù)完成
}

exports.default = (done) => {
    console.log('default task working~')
    done() //回調(diào)函數(shù)刘急,標(biāo)識(shí)任務(wù)完成
}
gulp的組合任務(wù)
const {series, parallel} = require('gulp')

const task1 = done => {
    setTimeout(()=> {
        console.log('task1 working')
        done()
    }, 1000)
}

const task2 = done => {
    setTimeout(()=> {
        console.log('task2 working')
        done()
    }, 1000)
}

const task3 = done => {
    setTimeout(()=> {
        console.log('task3 working')
        done()
    }, 1000)
}

exports.foo = series(task1, task2, task3) //串行執(zhí)行任務(wù)

exports.bar = parallel(task1, task2, task3) //并行執(zhí)行任務(wù)
gulp文件操作API
const {src, dest} = require('gulp')
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-demo
const { src, dest, parallel, series, watch } = require('gulp')

const del = require('del')
const browserSync = require('browser-sync')

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

const plugins = loadPlugins()
const bs = browserSync.create()

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 clean = () => {
  return del(['dist', 'temp'])
}

const style = () => {
  return src('src/assets/styles/*.scss', { base: 'src' })
    .pipe(plugins.sass({ outputStyle: 'expanded' }))
    .pipe(dest('temp'))
    .pipe(bs.reload({ stream: true }))
}

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({ data, defaults: { cache: false } })) // 防止模板緩存導(dǎo)致頁(yè)面不能及時(shí)更新
    .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'))
}

const serve = () => {
  watch('src/assets/styles/*.scss', style)
  watch('src/assets/scripts/*.js', script)
  watch('src/*.html', page)
  // watch('src/assets/images/**', image)
  // watch('src/assets/fonts/**', font)
  // watch('public/**', extra)
  watch([
    'src/assets/images/**',
    'src/assets/fonts/**',
    'public/**'
  ], bs.reload)

  bs.init({
    notify: false,
    port: 2080,
    // open: false,
    // files: 'dist/**',
    server: {
      baseDir: ['temp', 'src', 'public'],
      routes: {
        '/node_modules': 'node_modules'
      }
    }
  })
}

const useref = () => {
  return src('temp/*.html', { base: 'temp' })
    .pipe(plugins.useref({ searchPath: ['temp', '.'] }))
    // html 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
    })))
    .pipe(dest('dist'))
}

const compile = parallel(style, script, page)

// 上線之前執(zhí)行的任務(wù)
const build =  series(
  clean,
  parallel(
    series(compile, useref),
    image,
    font,
    extra
  )
)

const develop = series(compile, serve)

module.exports = {
  clean,
  build,
  develop
}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末矩父,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子排霉,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,188評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件攻柠,死亡現(xiàn)場(chǎng)離奇詭異球订,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)瑰钮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門冒滩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人浪谴,你說(shuō)我怎么就攤上這事开睡。” “怎么了苟耻?”我有些...
    開(kāi)封第一講書人閱讀 165,562評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵篇恒,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我凶杖,道長(zhǎng)胁艰,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 58,893評(píng)論 1 295
  • 正文 為了忘掉前任智蝠,我火速辦了婚禮腾么,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘杈湾。我一直安慰自己解虱,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,917評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布漆撞。 她就那樣靜靜地躺著殴泰,像睡著了一般。 火紅的嫁衣襯著肌膚如雪叫挟。 梳的紋絲不亂的頭發(fā)上艰匙,一...
    開(kāi)封第一講書人閱讀 51,708評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音抹恳,去河邊找鬼员凝。 笑死,一個(gè)胖子當(dāng)著我的面吹牛奋献,可吹牛的內(nèi)容都是我干的健霹。 我是一名探鬼主播,決...
    沈念sama閱讀 40,430評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼瓶蚂,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼糖埋!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起窃这,我...
    開(kāi)封第一講書人閱讀 39,342評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤瞳别,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體祟敛,經(jīng)...
    沈念sama閱讀 45,801評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡疤坝,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,976評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了馆铁。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片跑揉。...
    茶點(diǎn)故事閱讀 40,115評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖埠巨,靈堂內(nèi)的尸體忽然破棺而出历谍,到底是詐尸還是另有隱情,我是刑警寧澤辣垒,帶...
    沈念sama閱讀 35,804評(píng)論 5 346
  • 正文 年R本政府宣布望侈,位于F島的核電站,受9級(jí)特大地震影響乍构,放射性物質(zhì)發(fā)生泄漏甜无。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,458評(píng)論 3 331
  • 文/蒙蒙 一哥遮、第九天 我趴在偏房一處隱蔽的房頂上張望岂丘。 院中可真熱鬧,春花似錦眠饮、人聲如沸奥帘。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,008評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)寨蹋。三九已至,卻和暖如春扔茅,著一層夾襖步出監(jiān)牢的瞬間已旧,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,135評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工召娜, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留运褪,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,365評(píng)論 3 373
  • 正文 我出身青樓玖瘸,卻偏偏與公主長(zhǎng)得像秸讹,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子雅倒,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,055評(píng)論 2 355