拉勾教育大前端高薪训练营的学习笔记-工程化(脚手架,grunt,gulp)

文章内容输出来源:拉勾教育Java高薪训练营

工程化

  1. 工程化的作用
    • 可以解决使用es6,7,8的兼容问题
    • 可以使用less,sass,postcss预编译(本身在运行环境是不能执行的)
    • 模块化/组件化提高可维护性(本身在运行环境是不能直接支持)
    • 自动化(原本需要手动压缩代码和资源文件,手动上传代码到服务器)
    • 统一代码风格,git代码质量保证
    • 解决对后端代码的依赖问题
  2. 工程化:提高效率,质量保证,降低成本

脚手架工具

  1. Yeoman

    • 安装:yarn global add yo generator-node
    • 生成: 新建一个文件夹my-module,在这个文件夹下执行 yo node(node 就是 generator-node)
    • 使用yarn安装依赖包,执行命令yarn link, 就会出现my-module命令,检查my-module --help
    • 可以在Yeoman官网查找generator相关的插件
  2. 自定义Generator

    • mkdir generator-sample
    • cd generator-sample
    • yarn init && yarn add yeoman-generator
    • mkdir generators/app && cd generators/app
    • touch index.js
    // generators/app/index.js
    // Generator 核心入口
    // 需要导出一个继承自Yeoman Generator的类型
    // Yeoman Generator在工作中会自动调用我们在此类型中定义的一些生命周期
    // 在这些方法中可以通过调用父类提供的一些工具方法实现一些功能,比如文件写入
    
    const Generator = require('yeoman-generator')
    
    module.exports = class extends Generator{
        // yeoman 在询问用户环节会自动调用此方法
        // 在此方法中可以调用父类发prompt()方法发出对用户的命令行询问
        prompting(){
            return this.prompt([
                {
                    type: 'input',
                    name: 'title',
                    message: 'Your project name',
                    default: this.appname // appname为项目上传目录名称
                }, {
                    type: 'input',
                    name: 'success',
                    message: 'Your project name',
                    default: true // appname为项目上传目录名称
                }
            ]).then(answers=>{
                this.answers = answers
            })
        }
        writing(){
            // Yeoman 自动在生成文件阶段调用此方法
            // 我们在这里往项目目录中写入文件
            // this.fs.write(
            //     this.destinationPath('temp.txt'),
            //     Math.random().toString()
            // )
    
            // 通过模板方式写入文件到项目目录
            // 在app目录下新建templates目录,用于存放模板文件
            // 模板文件路径
            const tmpl = this.templatePath('foo.txt')
            // 输出路径
            const output = this.destinationPath('foo.txt')
            // 模板数据上下文
            const context = this.answers // {title: 'hello',success:true}
    
            this.fs.copyTpl(tmpl,output,context)
        }
    }
    
    • cd [generator-sample目录下] && yarn link
    • cd …/ && mkdir my-pro && cd my-pro
    • yo sample
  3. 提交到npm

    • echo node_module > .gitignore
    • git init && git add . && git commit -m “msg”
    • git remote add origin [git http://…git 路径]
    • git push -u origin master
    • yarn publish [–registry-https://registry.yarnpkg.com] 或者 npm publish [–registry-https://registry.npmjs.org]
  4. plop

    • 安装plop依赖
    • 在根目录下创建一个plopfile.js
    • 在plopfile.js定义脚手架任务
    • 编写用于生成特定类型文件的模板
    • 通过Plop提供的CLI运行脚手架任务
  5. 脚手架工作原理

    • mkdir sample
    • cd sample
    • yarn init
    • yarn add inquirer ejs
    • 修改package.json,添加"bin": “cli.js”,再在根目录下创建cli.js
    #!/usr/bin/env node
    
    // node CLI 应用入口文件必须要有这样的文件头
    // 如果是linux和macOS系统下还需要修改此文件的读写权限 755
    // 可以通过chmod 755 cli.js来实现
    
    // 脚手架工作工程:
    // 1. 通过命令行交互询问用户问题
    // 2.根据用户回答的结果生成文件
    
    // console.log('working!')
    const inquirer = require("inquirer")
    const path =require('path')
    const fs = require('fs')
    const ejs = require('ejs')
    
    inquirer.prompt([
        {
            type: 'input',
            name: 'name',
            message: 'Your project name?'
        }
    ]).then(answers=>{
        // console.log(answers)
    
        // 模板目录
        const tmpDir = path.join(__dirname, 'templates')
        // 目标目录
        const destDir = process.cwd()
    
        // 将模板下的文件全部转换到目标目录
        fs.readdir(tmpDir, (err,files)=>{
            if(err) throw err
            files.forEach(file=>{
                // console.log(file)
                // 通过模板引擎渲染文件
    
                ejs.renderFile(path.join(tmpDir,file),answers,(err,res)=>{
                    if (err) throw err
                    // console.log(res)
    
                    fs.writeFileSync(path.join(destDir,file),res)
                })
            })
        })
    })
    
    • yarn link
    • sample (执行cli.js的任务)

自动化构建

  1. npm script 自动化构建sass

    • preserve是npm script的钩子,执行命令前会执行
    • –watch 会监听scss的变化实时传化成css
    • yarn add npm-run-all; run-p会同时执行build和server两个命令
    • –files *css/*.css* 会监听css/目录下的css文件,如果有修改会更新
     "scripts":{
        "build": "sass sass/main.scss css/main.css --watch",
        // "preserve": "yarn build", 
        "serve": "browser-sync . --files \"css/*.css\"",
        "start": "run-p build server"
    }
    
  2. Grunt

    • yarn add grunt
    • 在根目录下创建gruntfile.js
    // Grunt 的入口文件
    // 用于定义一些需要Grunt自动执行的任务
    // 需要导出一个函数
    // 此函数接受一个Grunt的形参,内部提供一些创建任务可以用到的API
    
    module.exports = grunt =>{
        grunt.registerTask('foo',()=>{
            console.log('hello grunt~')
        })
    
        grunt.registerTask('bar',' 任务描述',()=>{
            console.log('other task~')
        })
    
        // default为默认,直接执行yarn grunt
        // grunt.registerTask('default',()=>{
        //     console.log('default task~')
        // })
    
        // 执行yarn grunt,会依次执行foo和bar
        grunt.registerTask('default',['foo','bar'])
    
        // 不支持异步
        // grunt.registerTask('async-task',()=>{
        //     setTimeout(()=>{
        //         console.log("async task working!")
        //     },1000)
        // })
    
        // 需要this.async()来解决异步问题
        // 而且不能使用箭头函数,需要使用function(){}
        grunt.registerTask('async-task',function(){
            const done = this.async()
            setTimeout(()=>{
                console.log("async task working!")
                done()
            },1000)
        })
    }
    
    • yarn grunt foo 或 yarn grunt bar…
  3. Grunt 任务失败

    • 当在default执行多了任务时,其中一个任务return false或异步done(false)回调或出现其他问题,将不会执行接下来的任务
    • 可以通过 yarn grunt --force来解决
  4. Grunt配置方法

    module.exports = grunt =>{
        grunt.initConfig({
            foo: 'bar',
            bar: {
                foo: 'foo'
            }
        })
        grunt.registerTask('foo',()=>{
            // 显示 'bar'
            console.log(grunt.config('foo'))
            // 显示 'foo'
            console.log(grunt.config('bar.foo'))
        })
    
  5. Grunt多任务

    • 执行命令yarn grunt build
    • 单个任务yarn grunt build:css
    grunt.initConfig({
        build:{
            // 配置选项,不是任务
            // 可以通过this.options()获取
            options:{},
            // 如果
            // css: {
                // 在执行css时通过this.options()获取,不会获取外部的options
            //    options:{}
            // }
            css:'1',
            js:'2'
        }
    })
    
    grunt.registerMultiTask('build',function(){
        console.log(`target: ${this.target}, data:${this.data}`)
    })
    
  6. Grunt 插件的使用

    • npm或yarn安装插件
    grunt.initConfig({
        // 插件的配置
    })
    grunt.loadNpmTasks('[插件名称]')
    
  7. Grunt常用的插件

    • yarn add load-grunt-tasks用于自动加载所有的插件,(loadGruntTasks(grunt))
    • yarn add grunt-sass sass
    • yarn add grunt-babel @babel-core @babel/preset-env
    • yarn add grunt-contrib-watch监听编译,修改文件后自动编译
  8. gulp基本使用

    • yarn add gulp --dev
    • 在根目录下创建gulpfile.js
    // gulp入口文件
    
    exports.foo = done=>{
        console.log('foo task working~')
        done() // 标识任务完成
    }
    
    exports.default = done=>{
        console.log('default task working~')
        done() // 标识任务完成
    }
    // 目前不推荐使用,推荐使用上面的方式
    const gulp = require('gulp')
    gulp.task('bar',done=>{
        console.log('var task working~')
        done() // 标识任务完成
    })
    
    • yarn gulp bar…
  9. gulp组合任务

    // gulp组合任务
    const { series, parallel } = require('gulp')
    const foo = done=>{
        console.log('foo task working~')
        done() // 标识任务完成
    }
    const foo1 = done=>{
        console.log('foo1 task working~')
        done() // 标识任务完成
    }
    // 执行yarn gulp task1,会依次执行foo,foo1
    // 串行执行任务,就是一个个执行
    exports.task1 = series(foo, foo1)
    // 并行执行任务,就是一起执行
    exports.task2 = parallel(foo,foo1)
    
  10. gulp异步任务

    • gulp输出error
    //Error
    // 如果时多任务执行时,报错后不执行后面的内容
    exports.callback_error = done=>{
            console.log('callback task working~')
            done(new Error('tsak failed!'))
        }
    
    // pomise
    exports.promise = ()=>{
        console.log('promise task working~')
        return Promise.resolve()
    }
    
    exports.promise_error = ()=>{
        console.log('promise task working~')
        return Promise.reject(new Error('task failed!'))
    }
    
    // async
    const timeout = time=>{
        return new Promise(resolve=>{
            setTimeout(resolve,time)
        })
    }
    
    exports.async = async ()=>{
        await timeout(1000)
        console.log('async task~')
    }
    
        
    const fs = require('fs')
    // exports.stream = ()=>{
    //     const readStream = fs.createReadStream('package.json')
    //     const writeStream = fs.createWriteStream('temp.txt')
    //     readStream.pipe(writeStream)
    //     return readStream
    // }
    
    // return 可以识别为在end事件执行done()
    exports.stream = done=>{
        const readStream = fs.createReadStream('package.json')
        const writeStream = fs.createWriteStream('temp.txt')
        readStream.pipe(writeStream)
        readStream.on('end',()=>{
            done()
        })
    }
    
  11. gulp压缩css

    // 压缩css
    const fs = require('fs')
    const {Transform} = require('stream')
    exports.minicss = ()=>{
        const readCss = fs.createReadStream('main.css')
        const writeCss = fs.createWriteStream('main.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)
            }
        })
    
        readCss.pipe(transform).pipe(writeCss)
        return readCss
    }
    
  12. 使用gulp API实现css压缩

    • 安装css压缩插件yarn add gulp-clean-css gulp-rename --dev
    • 编写配置
    // gulp API
    const {src,dest} = require('gulp')
    const cleanCss = require('gulp-clean-css')
    const rename = require('gulp-rename')
    exports.apitest = ()=>{
        return src('main.css') // src('css/*.css)
        .pipe(cleanCss())
        .pipe(rename({extname:'.min.css'})) // 重命名后缀
        .pipe(dest('dist'))
    }
    
    • 执行
  13. gulp项目基本配置

    • 样式编译
    • 脚本编译
    • html模板编译
    • 图片和字体文件编译
    • 其他文件复制和dist文件自动清除
  14. gulp 自动加载插件

    • yarn add gulp-load-plugin --dev
    • 使用plugins.sass()…
    const gulp = require('gulp');
    const plugins = require('gulp-load-plugins')();
    
  15. gulp开发服务器

    • yarn add browser-sync --dev
    • gulp配置browser-sync: https://browsersync.io/docs/gulp
    const serve = ()=>{
        bs.init({
            // 关闭浏览器右上方的提示
            notify: false,
            // localhost的端口
            port:2080,
            // 自动打开浏览器页面关闭
            open: false,
            // 监听文件,当dist下文件改动,浏览器更新
            files: 'dist/**',
            server:{
                baseDir: 'dist',
                // 将路径替换,可以是在html里的link或是script
                router:{
                    '/node_modules': 'node_modules'
                }
            }
        })
    }
    
  16. gulp源文件监听更新视图

    • const {watch} = reqiure(‘gulp’)
    • 在serve的bs.init上插入下面代码
    • watch([需要编译的所有css文件], [编译css的命令如minicss])
    • watch([需要压缩的所有图片,字体,其他文件], bs.reload) bs.reload用于更新,没有编译或压缩
  17. gulp文件引用处理

    • yarn add gulp-useref --dev
  18. gulp文件压缩

    • yarn add gulp-clean-css gulp-htmlmin gulp-uglify --dev

gulp项目配置

- 样式编译
- 脚本编译
- html模板编译
- 图片和字体文件编译
- 其他文件复制和dist文件自动清除
- 自动加载插件
- 开发服务器和热更新,监听dist和源码触发更新
- 监听源码优化
- 文件引用路径处理
- 文件压缩,代码混淆
  1. FIS
    • yarn global add fis3
    • 命令fis3 release -d ouput
    • 作用将文件的相对路径转换为绝对路径

你可能感兴趣的:(前端,自动化构建)