JavaScript性能优化-脚手架工具及自动化构建(12)

Part2 · 前端工程化实战

JavaScript性能优化-工具及代码优化

文章说明:本专栏内容为本人参加【拉钩大前端高新训练营】的学习笔记以及思考总结,学徒之心,仅为分享。如若有误,请在评论区支出,如果您觉得专栏内容还不错,请点赞、关注、评论。共同进步!

上一篇:【JavaScript性能优化-工具及代码优化】

本篇主要内容是前端脚手架工具及自动化构建

超长文、多图预警!!!超长文、多图预警!!!

一、脚手架工具

脚手架的本质作用:创建项目基础结构、提供项目规范和约定

  • 相同的组织架构
  • 相同的开发范式
  • 相同的模块依赖
  • 相同的工具配置
  • 相同的基础代码

二、前端脚手架

1.内容概要

  • 脚手架的作用
  • 常用的脚手架工具
  • 通用脚手架工具剖析
  • 开发一款脚手架

2.常用的脚手架

  • React.js项目–>create-react-app
  • Vue.js项目–>vue-cli
  • Angular项目–>angular-cli
  • Yeoman
  • Plop

3.Yeoman基本使用

  • 在全局范围安装yo

    npm install yo --global  # or yarn global add yo
    
  • 安装对应的generator

    npm install generator-node --global  # or yarn global add generator-node
    
  • 通过yo运行generator

    cd project-dir
    mkdir my-module
    yo node
    

4.Yeoman Sub Generator

常规使用步骤:

  1. 明确需求
  2. 找到合适的Generator
  3. 全局范围安装找到Generator
  4. 通过yo运行对应的Generator
  5. 通过命令行交互填写选项
  6. 生成你所需要的项目结构

Sub Generator使用示例:yo node:cli

  • 使用yo node:cli命令安装
  • yarn link引导全局
  • 使用my-module --help查看

5.创建Generator模块

Generator本质上就是一个NPM模块

Generator模块需求:名称必须为generator-

基本使用步骤

  1. 命令行内容

    mkdir generator-sample  # 创建项目目录
    cd generator-sample
    yarn init  #初始化项目
    yarn add yeoman-generator  # 安装依赖
    
  2. 根据模板创建文件

    1. 进入generator-sample,创建目录generators
    2. 进入generators创建index.js
  3. 编写index.js

    // 此文件作为 Generator 的核心入口
    // 需要导出一个继承自 Yeoman Generator 的类型
    // Yeoman Generator 在工作时会自动调用我们在此类型中定义的一些生命周期方法
    // 我们在这些方法中可以通过调用父类提供的一些工具方法实现一些功能,例如文件写入
    
    const Generator = require('yeoman-generator')
    
    module.exports = class extends Generator {
        // Yeoman 自动在生成文件阶段调用此方法
    
        // 我们这里尝试往项目目录中写入文件
        writing () {
            this.fs.write(
                this.destinationPath('temp.text'),
                Math.random().toString()
            )
        }
    }
    
  4. 命令行运行

    yarn link  # 将模块包引至全局
    cd ..  # 切回上级目录
    mkdir my-project
    cd my-project
    yo sample  # 运行yo sample命令,查看生成的文件temp.txt
    

进阶使用步骤

上述过程中除index.js文件内容不同,其余都相同

// 此文件作为 Generator 的核心入口
// 需要导出一个继承自 Yeoman Generator 的类型
// Yeoman Generator 在工作时会自动调用我们在此类型中定义的一些生命周期方法
// 我们在这些方法中可以通过调用父类提供的一些工具方法实现一些功能,例如文件写入

const Generator = require('yeoman-generator')

module.exports = class extends Generator {
  prompting () {
    // Yeoman 在询问用户环节会自动调用此方法
    // 在此方法中可以调用父类的 prompt() 方法发出对用户的命令行询问
    return this.prompt([
      {
        type: 'input',
        name: 'name',
        message: 'Your project name',
        default: this.appname // appname 为项目生成目录名称
      }
    ])
    .then(answers => {
      // answers => { name: 'user input value' }
      this.answers = answers
    })
  }
  writing () {
    // Yeoman 自动在生成文件阶段调用此方法

    // // 我们这里尝试往项目目录中写入文件
    // this.fs.write(
    //   this.destinationPath('temp.txt'),  // 文件绝对路径
    //   Math.random().toString()
    // )

    // -------------------------------------------------------

    // // 通过模板方式写入文件到目标目录

    // // 模板文件路径
    // const tmpl = this.templatePath('foo.txt')
    // // 输出目标路径
    // const output = this.destinationPath('foo.txt')
    // // 模板数据上下文
    // const context = { title: 'Hello zce~', success: false }

    // this.fs.copyTpl(tmpl, output, context)

    // -------------------------------------------------------

    // 模板文件路径
    const tmpl = this.templatePath('bar.html')
    // 输出目标路径
    const output = this.destinationPath('bar.html')
    // 模板数据上下文
    const context = this.answers

    this.fs.copyTpl(tmpl, output, context)
  }
}

6.Plop使用

官方简介:

我喜欢把Plop称为“微型发电机框架”。现在,我称其为“小工具”,因为它为您提供了一种以一致的方式生成代码或任何其他类型的纯文本文件的简单方法。您会看到,我们都在代码中创建了结构和模式(路由,控制器,组件,帮助程序等)。这些模式会随着时间的推移而变化和改进,因此当您需要在此处创建新的模式插入名称时,在代码库中查找代表当前“最佳实践”的文件并不总是那么容易。那就是挽救您的地方。使用plop,您将拥有在code中创建任何给定模式的“最佳实践”方法。可以通过输入plop轻松地从终端运行代码。这不仅使您免于在代码库中四处寻找要复制的正确文件,而且还使“正确的方式”变成了“创建新文件的最简单的方式”。

React项目中使用plop步骤

项目初始结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dhLtMGaC-1606035018990)(%E6%93%B7%E5%8F%96-1605681121108.JPG)]

  1. 安装plop至开发环境中

    yarn add plop --dev
    
  2. 在项目根目录中创建plopfile.js文件,并编写以下代码

    // Plop入口文件,需要导出一个函数
    // 此函数接受一个plop对象,用于创建生成器任务
    module.exports = plop => {
        plop.setGenerator('component', {
            description: 'Create a component',
            prompts: [
                {
                    type: 'input',  // 问题的输入方式
                    name:'name',  // 问题返回值的键
                    message: 'Component name:',  // 屏幕上给出的提示
                    default: 'MyComponent',  // 问题的默认答案
                }
            ],
            actions: [
                {
                    type: 'add',  // 添加一个全新的文件
                    path: 'src/components/{{name}}/{{name}}.js',  // 添加文件的存放位置
                    templateFile: 'plop-templates/component.hbs',  // 模板文件的位置
                }
            ]
        })
    }
    
  3. 创建plop-templates目录,在其中添加模板文件component.hbs,内容如下:

    import React from 'react'
    
    export default () => {
        <div className="{{name}}">
            <h1>{{name}}</h1>
        </div>
    }
    
  4. 命令行运行

    yarn plop component  # component是我们在plop中plop.setGenerator中的第一个参数
    yarn run v1.22.10
    $ F:\2020\Others\important\lagou\02-01-study-materials\code\02-01-02-05-react-app\node_modules\.bin\plop component
    ? Component name: Footer
    √  ++ \src\components\Footer\Footer.js
    Done in 3.79s.
    
  5. 至此我们就可以在src/components中看到我们生成的Footer目录,其中文件为Footer.js

三、自动化构建工具

1.自动化构建初体验

  1. 项目结构:

在这里插入图片描述

我们使用sass使编写css提高效率,但需要对sass进行编译。

yarn init --yes  # 初始化项目目录
yarn add sass --dev  # 在开发环境安装sass
yarn add browser-sync --dev  # 在开发环境安装browser-sync
yarn add npm-run-all  --dev  # 在开发环境安装npm-run-all用来运行所有script

编辑package.json文件:

{
  "name": "my-web-app",
  "version": "0.1.0",
  "main": "index.js",
  "author": "zce <w@zce.me> (https://zce.me)",
  "license": "MIT",
  "scripts": {
    "build": "sass scss/main.scss css/style.css --watch", 
    "serve": "browser-sync . --files \"css/*.css\"",
    "start": "run-p build serve"
  },
  "devDependencies": {
    "browser-sync": "^2.26.7",
    "npm-run-all": "^4.1.5",
    "sass": "^1.29.0"
  }
}

命令行运行:

yarn start

自动执行:

  • yarn build

  • yarn browser-sync

2.常用的自动化构建工具

在这里插入图片描述

为什么要使用自动化构建工具:

一句话:自动化。对于需要反复重复的任务,例如压缩(minification)、编译、单元测试、linting等,自动化工具可以减轻你的劳动,简化你的工作。

2.1Grunt

Grunt 生态系统非常庞大,并且一直在增长。由于拥有数量庞大的插件可供选择,因此,你可以利用 Grunt 自动完成任何事,并且花费最少的代价。如果找不到你所需要的插件,那就自己动手创造一个 Grunt 插件,然后将其发布到 npm 上吧。

由于其工作过程是基于临时文件的,所以构建的速度相对较慢,频繁的磁盘读写导致速度慢

2.2Gulp

gulp 将开发流程中让人痛苦或耗时的任务自动化,从而减少你所浪费的时间、创造更大价值。

工作过程是基于内存实现的,解决了Grunt的速度问题。默认支持同时去处理多个任务,效率大大提高,使用方式相对于Grunt相对通俗易懂,插件生态也同样完善。个人安利。

2.3FIS

解决前端开发中自动化工具、性能优化、模块化框架、开发规范、代码部署、开发流程等问题

百度团队的工具,捆绑套餐,将很多功能都提供给我们。

3.Grunt使用

3.1 Grunt基本使用
  1. 创建空项目grunt-sample

    yarn init --yes
    
  2. 安装grunt模块

    yarn add grunt --dev
    
  3. 项目根目录添加gruntfile.js文件,并编写以下内容

    // grunt入口文件
    // 用于定义一些需要Grunt自动执行的任务
    // 需要导出一个函数
    // 此函数接收一个grtun对象,内部体用一些创建任务时可以用的API
    
    module.exports = grunt => {
        // 第二个字符串为任务描述
        grunt.registerTask('foo','a sample task', () => {
            console.log('hello grunt');
        })
    
        grunt.registerTask('bar', () => {
            console.log('other task');
        })
    
    
        // // default 是默认任务名称
        // // 通过grunt执行时可以省略任务名
        // // grunt.registerTask('default', () => {
        // //     console.log('default task');
        // // })
    
        // // 第二个参数可以指定此任务的映射任务
        // // 这样执行default就相当于执行对应的任务
        // // 这里的映射的任务会按照顺序一次执行,不会同步执行
        // grunt.registerTask('default', ['foo', 'bar'])
    
        // // 也可以在任务函数中执行其他任务
        // grunt.registerTask('run-other', () => {
        //     // foo和bar会在当前任务执行完成过后自动依次执行
        //     grunt.task.run('foo', 'bar')
        //     console.log('current task runing');
        // })
    
        // // 默认grunt采用同步模式编码
        // // 如果需要异步可以使用this.async()方法创建回调函数
        // // 下面代码不会再settimeout后打印语句
        // // grunt.registerTask('async-task', () => {
        // //     setTimeout(() => {
        // //         console.log('async task working');
        // //     }, 1000);
        // // })
    
        // // 由于函数体重需要使用this,所以这里不能使用箭头函数
        grunt.registerTask('async-task', function () {
            const done = this.async()
            setTimeout(() => {
                console.log('async task working');
                done()
            }, 1000);
       })
    }
    
  4. 命令行运行

    yarn grunt  # 后面添加任务名或不添加任务名默认执行default
    
3.2 Grunt标记任务失败

标记任务失败需要在函数体中返回false。默认情况下(yarn grunt default),如果为任务列表,则当前面的任务执行失败后,后续的任务不再执行。如果在yarn grunt default后面添加–force时,则前面任务失败后,强制执行后面的任务yarn grunt default --force。

异步函数中标记当前任务执行失败的方式是为回调函数指定一个 false 的实参

module.exports = grunt => {
  // 任务函数执行过程中如果返回 false
  // 则意味着此任务执行失败
  grunt.registerTask('bad', () => {
    console.log('bad working~')
    return false
  })

  grunt.registerTask('foo', () => {
    console.log('foo working~')
  })

  grunt.registerTask('bar', () => {
    console.log('bar working~')
  })

  // 如果一个任务列表中的某个任务执行失败
  // 则后续任务默认不会运行
  // 除非 grunt 运行时指定 --force 参数强制执行
  grunt.registerTask('default', ['foo', 'bad', 'bar'])

  // 异步函数中标记当前任务执行失败的方式是为回调函数指定一个 false 的实参
  grunt.registerTask('bad-async', function () {
    const done = this.async()
    setTimeout(() => {
      console.log('async task working~')
      done(false)
    }, 1000)
  })
}
3.3 Grunt的配置方法

除了grunt.registerTask外,grunt还提供了一个去添加配置选项的API:initConfig

module.exports = grunt => {
  // grunt.initConfig() 用于为任务添加一些配置选项
  grunt.initConfig({
    // 键一般对应任务的名称
    // 值可以是任意类型的数据
    foo: {
      bar: 'baz'
    }
  })

  grunt.registerTask('foo', () => {
    // 任务中可以使用 grunt.config() 获取配置
    console.log(grunt.config('foo'))
    // 如果属性值是对象的话,config 中可以使用点的方式定位对象中属性的值
    console.log(grunt.config('foo.bar'))
  })
}
3.4 Grunt多目标任务

命令行运行yarn grunt build时,可以同时运行目标任务。如果需要运行指定目标任务,可以使用yarn grunt build:foo命令

module.exports = grunt => {
  // 多目标模式,可以让任务根据配置形成多个子任务

  // grunt.initConfig({
  //   build: {
  //     foo: 100,
  //     bar: '456'
  //   }
  // })

  // grunt.registerMultiTask('build', function () {
  //   console.log(`task: build, target: ${this.target}, data: ${this.data}`)
  // })

  grunt.initConfig({
    build: {
      // 任务配置选项,并不会执行
      options: {
        msg: 'task options'
      },
      foo: {
        // 会覆盖build中的option
        options: {
          msg: 'foo target options'
        }
      },
      bar: '456'
    }
  })

  grunt.registerMultiTask('build', function () {
    console.log(this.options())
  })
}

3.5 Grunt插件的使用
  1. 安装插件
  2. gruntfile中载入插件
  3. 根据文档完成相关的配置选项
grunt sass

项目初始

在这里插入图片描述

  1. 安装插件grunt-sass以及npm模块sass

    yarn add grunt-sass sass --dev
    
  2. 编写gruntfile.js

    const sass = require('sass')
    module.exports = grunt => {
        grunt.initConfig({
            sass: {
                options: {
                    implementation:sass,
                },
                main: {
                    files: {
                        'dist/css/main.css': 'src/scss/main.scss'  // 键为目标文件路径,值为需要编译的文件
                    }
                }
            }
        })
    
        grunt.loadNpmTasks('grunt-sass')
    }
    

    命令运行后的目录

在这里插入图片描述

grunt-babel

初始目录

在这里插入图片描述

  1. 安装grunt-babel

    yarn add grunt-babel @babel/core @babel/preset-env --dev
    yarn add load-grunt-tasks --dev
    
  2. 编辑上面sass中js

    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']  // 最新的ECMAScript中的特性加载进来
                },
                main:{
                    files: {
                        'dist/js/app.js': 'src/js/app.js'
                    }
                }
            }
        })
        // grunt.loadNpmTasks('grunt-sass')
        loadGruntTasks(grunt)  // 自动加载所有的grunt插件中的所有任务
    }
    

    命令后的目录

    在这里插入图片描述

grunt-contrib-watch

源文件变化时,实时编译文件

  1. 安装grunt-contrib-watch

    yarn add grunt-contrib-watch --dev
    
  2. 编辑js文件

    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']  // 最新的ECMAScript中的特性加载进来
                },
                main:{
                    files: {
                        'dist/js/app.js': 'src/js/app.js'
                    }
                }
            },
            watch: {
                js: {
                    files:['src/js/*.js'],
                    tasks: ['babel']
                },
                css: {
                    files:['src/scss/*.scss'],
                    tasks: ['sass']
                }
            }
        })
    
        // grunt.loadNpmTasks('grunt-sass')
        loadGruntTasks(grunt)  // 自动加载所有的grunt插件中的所有任务
        grunt.registerTask('default', ['sass', 'babel'])  // 确保启动watch瞬间先执行sass任务和babel
    }
    

    监听文件时terminal的状态:

在这里插入图片描述

3.6 Grunt总结

4.Gulp使用

当下最流行的前端构建系统,其核心特性就是高效、易用。现在项目中安装gulp开发依赖。添加gulpfile.js,用于编写需要gulp自动执行的任务。随后可以再命令行使用gulp提供cli工具运行构建任务。

4.1 Gulp的基本使用

  1. 初始化项目目录

    mkdir gulp-test  # 创建项目目录
    cd gulp-test  # 切换目录
    yarn init --yes  # 初始化目录
    yarn add gulp --dev  # 安装gulp到开发环境
    
  2. 根目录创建gulpfile.js文件

    // gulp入口文件
    
    // 导出函数成员
    exports.foo = () => {
        console.log('foo task working~');
    }
    
  3. 通过命令行运行任务

    yarn gulp foo
    
    # [22:23:50] Using gulpfile D:\DeskTop\02-01-study-materials\gulp-test\gulpfile.js
    # [22:23:50] Starting 'foo'...
    # foo task working~
    # [22:23:50] The following tasks did not complete: foo
    # [22:23:50] Did you forget to signal async completion?
    # error Command failed with exit code 1.
    # info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
    

    The following tasks did not complete: foo,foo任务未完成,因为最新的gulp中取消了同步代码运行模式,默认约定为异步任务,任务执行完成后,需要调用回调函数或其他方式去标记这个任务表示完成。这里我们手动的调用回调函数。

    // gulp入口文件
    
    // 导出函数成员
    exports.foo = done => {
        console.log('foo task working~');
        done()  // 表示任务完成
    }
    
    exports.default = done => {
        console.log('default task working~');
        done()  // 标记任务完成
    }
    
    

    此时foo任务会正常启动,正常结束。此时我们直接运行yarn gulp,他会自动运行default任务,同grunt一样。除此之外,gulp4.0前,注册gulp任务需要通过gulp模块中的方法来实现,具体来看:

    const gulp  = require('gulp')
    gulp.task('bar',done => {
        console.log('bar task working~')
    })
    

4.2 Gulp的组合使用

glup中需要使用到并行任务和串行任务,在我们项目过程中,编译scss文件和js文件是不冲突的,所以我们需要使用并行任务。而我们在编译文件和部署服务时,我们需要先进行编译scss和css文件,然后进行服务部署,这时候需要使用串行任务。在glup中提供了两个API serires以及parallel,分别提供串行和并行任务。

const {series, parallel} = reqire(‘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) // 执行串行任务
exports.bar = parallel(task1, task2, task3) // 执行并行任务
yarn gulp foo # 此时三个任务会依次等待1秒后执行console.log()方法
yarn gulp bar # 此时三个任务会同时开始,在1秒后同时执行conssole.log()方法。

4.3 Gulp的异步任务

gulp中的任务都是异步任务,也就是我们经常提到的一部函数。我们调用一个异步函数时是没有办法去直接明确这个调用是否完成的。都是在函数内部通过回调或者事件去通知外部这个函数是否调用完成。在异步任务中,同样面临如何去通知gulp任务的完成情况。上面我们使用同步任务done()来模仿异步任务。

// 通过同步任务进行模拟
exports.call ask = done => {
    console.log(‘callback task’)
    done()
}

// 同步任务失败情况
export.callback_error = done => {
    console.log(‘callback_error task’)
    done(new Error(‘callback_error task failed!))
}

// 使用promise去完成异步任务
exports.promise = () => {
    console.log(‘promise task~)
    return Promise.resolve() // 标记promise任务完成
}

// promise任务失败情况
exports.promise_error = () => {
    console.log(‘promise_error task’)
    return Promise.reject(new Error(‘promise_error failed!))
}

// 使用ES7中提供的async和await语法糖
const timeout = time => {
    return new Promise(resolve => {
    	setTimeout(resolve, time)
    })
}

exports.async = async () => {
    await timeout(1000)
    console.log(async task~)
}

// 使用stream
const { doesNotMatch } = require('assert')
const fs = require('fs')

exports.stream = () => {
    const read = fs.createReadStream('yarn.lock')
    const write = fs.createWriteStream('a.txt')
    read.pipe(write)
    return read
}

// 模仿stream
exports.stream_copy = done => {
    const read = fs.createReadStream('yarn.lock')
    const write = fs.createWriteStream('b.txt')
    read.pipe(write)
    read.on('end', () => {
        done()
    })
}

4.4 Gulp构建过程核心工作原理

构建过程大多数都是将文件读取然后进行一些转换,最后写入另外一个位置。

这里我们模拟压缩css到吗为min.css的过程,主要分为以下几个步骤:

  1. 创建文件读取流-目标css
  2. 创建文件写入流-目标min.css
  3. 文件转换流,将读取的文件流使用replace进行替换空白字符与注释
  4. 使用pipe将文件流先转换,然后再讲转换流写入

具体代码如下:

const fs = require('fs')
const {Transform} = require('stream')


exports.default = () => {
  // 文件流读取
  const readStream = fs.createReadStream('normalize.css')
  // 写入文件流
  const writeStream = fs.createWriteStream('normalize.min.css')

  // readStream.pipe(writeStream)
  //
  // return readStream

  // 文件流转换
  const transformStream = new Transform({
    // 核心转换过程
    transform: (chunk, encoding, callback) => {
      const input = chunk.toString()
      const output = input.replace(/\s+/g, '').replace(/\/\*.+?\*\//g, '')
      callback(null, output)  // 第一个参数为错误对象,output为转换完的结果
    }
  })

  return readStream
    .pipe(transformStream)  // 先转换
    .pipe(writeStream)  // 再写入
}

4.5 Gulp文件操作API

Gulp中为我们提供读取流和写入流 的API,相比于底层Node的API,Gulp的API更强大、更易用,至于负责文件的转换流,绝大多数情况我们都是通过独立的插件来提供。我们在实际去通过Gulp创建构建任务时的流程就是:先通过src方法去创建一个读取流,然后再借助插件提供的转换流来实现文件加工,最后我们再通过Gulp提供的dest方法去创建一个写入流,从而写入到目标文件。具体工作过程如下:

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'))
}

4.6 Gulp案例-样式编译

const {src, dest} = require('gulp')
//  gulp.src:gulp底层是使用的nodejs的stream,首先获取到stream流,然后使用pipe()方法把流数据导入到你想让它去的地方。
//  gulp.dest:src函数是读取文件,那dest函数就是写文件,gulp.dest(path[,options]),path是要写入的文件的路径,这里注意只能是路径,不能是具体的文件
const sass = require('gulp-sass')  // 真是执行css编译的,其调用node-sass,而node-sass是c++的二进制模块,所以安装时需要设置淘宝镜像进行安装

const style = () => {
	return src('src/assets/styles/*.scss', {base: 'src'})  // base作用是以src为基准,原样输出目录结构
		.pipe(sass({outputStyle: 'expanded'}))  // outputStyle作用是将sass生成的css文件最后的花括号放在块末尾
		.pipe(dest('dist'))
}

module.exports = {
	style
}

命令行运行:

yarn gulp style

4.7 Gulp案例-脚本编译

安装依赖:

yarn add gulp-babel --dev
yarn add @babel/core @babel/preset-env  # preset-env会将ECMAScript中所有的新特性进行转换
const babel = require('gulp-babel')

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

module.exports = {
	style,
	script
}

命令行运行:

yarn gulp script

4.8 Gulp案例-页面编译

安装依赖:

yarn add gulp-swig --dev
const {src, dest, parallel, series} = require('gulp')
//  gulp.src:gulp底层是使用的nodejs的stream,首先获取到stream流,然后使用pipe()方法把流数据导入到你想让它去的地方。
//  gulp.dest:要说src函数是读取文件,那么dest函数就是写文件,gulp.dest(path[,options]),path是要写入的文件的路径,这里注意只能是路径,不能是具体的文件
const sass = require('gulp-sass')
const babel = require('gulp-babel')


const swig = require('gulp-swig')


const data = {...}

const style = () => {
	return src('src/assets/styles/*.scss', {base: 'src'})  // base作用是以src为基准,原样输出目录结构
		.pipe(sass({outputStyle: 'expanded'}))  // outputStyle作用是将sass生成的css文件最后的花括号放在块末尾
		.pipe(dest('dist'))
}


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

const page = () => {
	return src('src/*.html', {base: 'src'})
		.pipe(swig({data}))  // 填充模板页面的数据
		.pipe(dest('dist'))
}

const compile = parallel(style, script, page)  // 任务并行


module.exports = {
	compile
}

命令行输入:

yarn gulp compile

4.9 Gulp案例-图片和字体文件转换

安装依赖:

yarn add gulp-imagemin --dev  # 与node-sass相同,需要引入二进制文件,科学上网
const {src, dest, parallel, series} = require('gulp')
//  gulp.src:gulp底层是使用的nodejs的stream,首先获取到stream流,然后使用pipe()方法把流数据导入到你想让它去的地方。
//  gulp.dest:要说src函数是读取文件,那么dest函数就是写文件,gulp.dest(path[,options]),path是要写入的文件的路径,这里注意只能是路径,不能是具体的文件
const sass = require('gulp-sass')
const babel = require('gulp-babel')
const swig = require('gulp-swig')
const imagemin = require('gulp-imagemin')

const data = {...}

const style = () => {
	return src('src/assets/styles/*.scss', {base: 'src'})  // base作用是以src为基准,原样输出目录结构
		.pipe(sass({outputStyle: 'expanded'}))  // outputStyle作用是将sass生成的css文件最后的花括号放在块末尾
		.pipe(dest('dist'))
}

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

const page = () => {
	return src('src/*.html', {base: 'src'})
		.pipe(swig({data}))  // 填充模板页面的数据
		.pipe(dest('dist'))
}

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'))
}

const compile = parallel(style, script, page, image, font)  // 任务并行


module.exports = {
	compile,
}

运行命令:

yarn gulp image
yarn gulp font

4.10 Gulp案例-其他文件及文件清除

const {src, dest, parallel, series} = require('gulp')
//  gulp.src:gulp底层是使用的nodejs的stream,首先获取到stream流,然后使用pipe()方法把流数据导入到你想让它去的地方。
//  gulp.dest:要说src函数是读取文件,那么dest函数就是写文件,gulp.dest(path[,options]),path是要写入的文件的路径,这里注意只能是路径,不能是具体的文件
const sass = require('gulp-sass')
const babel = require('gulp-babel')
const swig = require('gulp-swig')
const imagemin = require('gulp-imagemin')

const data = {...}

const style = () => {
	return src('src/assets/styles/*.scss', {base: 'src'})  // base作用是以src为基准,原样输出目录结构
		.pipe(sass({outputStyle: 'expanded'}))  // outputStyle作用是将sass生成的css文件最后的花括号放在块末尾
		.pipe(dest('dist'))
}

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

const page = () => {
	return src('src/*.html', {base: 'src'})
		.pipe(swig({data}))  // 填充模板页面的数据
		.pipe(dest('dist'))
}

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'))
}

const extra = () => {
	return src('public/**', {base: 'public'})  // 额外拷贝的任务
		.pipe(dest('dist'))
}

const compile = parallel(style, script, page, image, font)  // 任务并行

const build = parallel(compile, extra)  // 任务并行

module.exports = {
	build
}

需要在build任务之前先自动清除dist文件,因此使用series创建串行任务。

安装依赖

yarn add del --dev
const {src, dest, parallel, series} = require('gulp')
//  gulp.src:gulp底层是使用的nodejs的stream,首先获取到stream流,然后使用pipe()方法把流数据导入到你想让它去的地方。
//  gulp.dest:要说src函数是读取文件,那么dest函数就是写文件,gulp.dest(path[,options]),path是要写入的文件的路径,这里注意只能是路径,不能是具体的文件
const del = require('del')

const sass = require('gulp-sass')
const babel = require('gulp-babel')
const swig = require('gulp-swig')
const imagemin = require('gulp-imagemin')

const data = {...}

const clean = () => {
	return del(['dist'])  // 返回promise
}
              
const style = () => {
	return src('src/assets/styles/*.scss', {base: 'src'})  // base作用是以src为基准,原样输出目录结构
		.pipe(sass({outputStyle: 'expanded'}))  // outputStyle作用是将sass生成的css文件最后的花括号放在块末尾
		.pipe(dest('dist'))
}

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

const page = () => {
	return src('src/*.html', {base: 'src'})
		.pipe(swig({data}))  // 填充模板页面的数据
		.pipe(dest('dist'))
}

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'))
}

const extra = () => {
	return src('public/**', {base: 'public'})  // 额外拷贝的任务
		.pipe(dest('dist'))
}

const compile = parallel(style, script, page, image, font)  // 任务并行

const build = series(clean, parallel(compile, extra))  // 任务并行

module.exports = {
	build
}

4.11 Gulp案例-自动加载插件

代码合理化,自动加载所有gulp的插件,使用gulp-load-plugins

const {src, dest, parallel, series} = require('gulp')
//  gulp.src:gulp底层是使用的nodejs的stream,首先获取到stream流,然后使用pipe()方法把流数据导入到你想让它去的地方。
//  gulp.dest:要说src函数是读取文件,那么dest函数就是写文件,gulp.dest(path[,options]),path是要写入的文件的路径,这里注意只能是路径,不能是具体的文件
const del = require('del')

const loadPlugins = require('gulp-load-plugins')  // 加载load-plugins
const plugins = loadPlugins()  //以下所有插件使用plugins.[插件名],如果插件名为gulp-xx-xx,那么改为plugins.xxYy,驼峰命名

const data = {...}

const clean = () => {
	return del(['dist', 'temp'])
}

const style = () => {
	return src('src/assets/styles/*.scss', {base: 'src'})  // base作用是以src为基准,原样输出目录结构
		.pipe(plugins.sass({outputStyle: 'expanded'}))  // outputStyle作用是将sass生成的css文件最后的花括号放在块末尾
		.pipe(dest('dist'))
}

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

const page = () => {
	return src('src/*.html', {base: 'src'})
		.pipe(plugins.swig({data}))  // 填充模板页面的数据
		.pipe(dest('dist'))
}

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 compile = parallel(style, script, page, image, font)  // 任务并行

const build = series(clean, parallel(compile, extra))  // 任务并行

module.exports = {
	build
}

4.12 Gulp案例-开发服务器、监视变化以及构建优化

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 develop = series(compile, serve)

module.exports = {
	clean,
	build,
	develop
}

4.14 Gulp案例-userer文件引用处理

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'))
}

4.16 Gulp案例-重新规划构建过程

暴露出任务

{
  "name": "zce-gulp-demo",
  "version": "0.1.0",
  "main": "index.js",
  "repository": "https://github.com/zce/zce-gulp-demo.git",
  "author": "zce <w@zce.me> (https://zce.me)",
  "license": "MIT",
  "scripts": {
    "clean": "gulp clean",  // 此时可以直接执行yarn clean
    "build": "gulp build",
    "develop": "gulp develop"
  },
  "dependencies": {
    "bootstrap": "^4.3.1",
    "jquery": "^3.4.1",
    "popper.js": "^1.15.0"
  },
  "devDependencies": {
    "@babel/core": "^7.5.5",
    "@babel/preset-env": "^7.5.5",
    "browser-sync": "^2.26.7",
    "del": "^5.1.0",
    "gulp": "^4.0.2",
    "gulp-babel": "^8.0.0",
    "gulp-clean-css": "^4.2.0",
    "gulp-htmlmin": "^5.0.1",
    "gulp-if": "^3.0.0",
    "gulp-imagemin": "^6.1.0",
    "gulp-load-plugins": "^2.0.1",
    "gulp-sass": "^4.0.2",
    "gulp-swig": "^0.9.1",
    "gulp-uglify": "^3.0.2",
    "gulp-useref": "^3.1.6"
  }
}

gitignore忽略生成的目录

dist

temp

今日分享就到了这里,上面很多的概念性问题,要完全的理解并使用这些新的知识,需要很长一段时间。多用、多查、多做!

记录:2020/11/22

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
### 回答1: 好的,下面是一个简单的天气系统项目,基于Vue.js和OpenWeatherMap API。 1. 首先,用Vue-cli创建一个新项目: ``` vue create weather-app ``` 2. 安装axios和momentjs: ``` npm install axios moment --save ``` 3. 创建一个组件来显示天气信息: ```vue <template> <div> <div v-if="weather"> <h2>{{ weather.name }}</h2> <p>{{ formattedDate }}</p> <p>{{ weather.weather[0].description }}</p> <p>{{ weather.main.temp }}°C</p> <img :src="'http://openweathermap.org/img/w/' + weather.weather[0].icon + '.png'" /> </div> <div v-else> <p>Loading...</p> </div> </div> </template> <script> import axios from 'axios' import moment from 'moment' export default { name: 'Weather', data () { return { weather: null, error: null } }, props: { city: { type: String, required: true } }, computed: { formattedDate () { if (this.weather) { return moment(this.weather.dt * 1000).format('DD MMM YYYY HH:mm:ss') } } }, mounted () { axios.get(`https://api.openweathermap.org/data/2.5/weather?q=${this.city}&units=metric&appid=${process.env.VUE_APP_OPENWEATHERMAP_API_KEY}`) .then(response => { this.weather = response.data }) .catch(error => { this.error = error }) } } </script> ``` 4. 在App.vue中使用该组件: ```vue <template> <div id="app"> <Weather city="London" /> <Weather city="New York" /> <Weather city="Tokyo" /> </div> </template> <script> import Weather from './components/Weather.vue' export default { name: 'App', components: { Weather } } </script> ``` 5. 最后,在.env文件中添加OpenWeatherMap API密钥: ``` VUE_APP_OPENWEATHERMAP_API_KEY=YOUR_API_KEY_HERE ``` 6. 运行项目: ``` npm run serve ``` 现在,你应该可以在浏览器中看到来自OpenWeatherMap API的天气信息了! ### 回答2: 使用Vue的脚手架可以轻松地搭建一个完整的天气系统项目。以下是一个可以利用Vue CLI创建的基础项目结构。 1. 首先,使用Vue CLI创建一个新的项目。 ```bash vue create weather-app ``` 2. 进入项目目录。 ```bash cd weather-app ``` 3. 在项目中安装所需的依赖。 ```bash npm install axios vue-router ``` 4. 创建一个`WeatherApp`组件用于展示天气信息。可以在`src/components`目录下创建一个`WeatherApp.vue`文件,而且在该组件中,你可以从天气API获取天气数据。 5. 创建一个路由文件来管理页面导航。在`src`目录下创建一个`router.js`文件,并将路由和组件进行关联。 6. 在项目的根组件中引入`WeatherApp`组件,并使用`router-view`来展示不同页面。 7. 在`src/main.js`文件中配置路由。导入`vue-router`和创建的路由文件,然后使用`Vue.use()`注册路由插件。 8. 配置天气API。你可以根据需要选择一个合适的天气API供应商,并在项目中使用`axios`来获取天气数据。 9. 在`WeatherApp`组件中使用`axios`来发起HTTP请求,获取天气数据。可以在`created`生命周期钩子中调用API。 10. 在组件中展示天气数据。根据API响应的格式,使用`v-for`和`v-bind`等指令来遍历和绑定数据。 11. 样式美化。使用Vue提供的`<style scoped>`标签来实现组件的样式,并使用CSS库或自定义样式来美化界面。 12. 最后,使用`npm run serve`命令启动项目,即可在浏览器中查看完整的天气系统项目。 通过上述步骤,我们可以利用Vue的脚手架搭建一个完整的天气系统项目。项目中包含了路由管理、API调用和数据展示等基本功能,可以方便地获取并展示天气信息。当然,根据实际需求,我们还可以添加更多的功能和页面来完善这个项目。 ### 回答3: 利用Vue的脚手架可以很方便地写一个关于天气系统的完整项目。 首先,在命令行中使用脚手架创建一个Vue项目:vue create weather-system。然后进入项目目录:cd weather-system。 接下来,可以开始编写相关的功能和组件。首先,可以创建一个Weather组件,用于显示天气信息。在Weather组件中,可以通过调用天气API获取天气数据,并将数据展示在前端页面上。 在天气API中,可以通过输入城市名称,获取该城市的实时天气情况、未来几天的天气预报等信息。可以使用axios库发送异步HTTP请求,然后在组件中处理返回的数据。将获取到的数据展示在页面上,可以显示当前温度、天气情况、风力等信息。还可以使用图表库如echarts来展示其他的天气指标,如气温曲线图。 在编写Weather组件时,可以根据需求添加一些附加功能。比如,可以添加城市选择功能,用户可以通过下拉菜单或输入框选择不同的城市,然后根据所选的城市显示对应的天气信息。 另外,也可以添加其他的功能模块。例如,可以创建一个天气预警提醒组件,用于显示当前城市是否有天气预警,以及具体的预警内容。还可以创建一个天气趋势分析组件,用于分析天气变化趋势,比如显示不同季节的平均气温、降水量等。 在完成项目的基本功能后,可以使用Vue Router创建路由,实现不同页面之间的跳转和导航。可以创建一个首页,用于展示天气信息。还可以创建一个关于页面,用于展示该项目的相关介绍和使用说明。 最后,可以使用Vue的打包工具将项目打包成静态文件,用于部署到服务器上。可以使用命令:npm run build 来进行打包。 综上所述,利用Vue的脚手架可以方便地编写一个关于天气系统的完整项目。通过调用天气API获取数据,使用Vue组件展示天气信息,并添加必要的功能模块,最后完成打包部署。这样就可以提供一个实用的天气系统,方便用户查看各地天气情况。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

5coder

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值