Automated build and grunt

Article description: This article is the notes and experience of the front-end training camp of Regao. If there is something wrong, I hope you can point out and teach, thank you! 

 1. Automated construction

Introduction:

Automation refers to the replacement of manual work by machines. Construction can be understood as conversion, which is to convert one thing into another. Generally speaking, automated construction is to automatically convert the source code written in the development stage into code or programs that can be run in the production environment. This transition process is called automated construction workflow. This is to get us out of operation as much as possible. Problems caused by environmental compatibility. In the development stage, use some efficiency-improving grammars, specifications and standards. For example, when developing web applications, you can use ECMAScript NEXT to improve coding efficiency and quality, use sass to enhance the programmability of CSS, and then use the template engine to abstract the duplicates in the page. HTML, most of these usages are not directly supported by browsers. These unsupported code features are converted into code that can be run directly. These can be used in our development process to improve our coding efficiency in these ways.

Initial experience of automated construction:

The css is handwritten at first, and then run in the browser:

We build with sass:

  •  Install the sass module and install it as a development dependency
yarn add sass --dev //或者 npm install sass --save-dev
  • Use command to convert sass file to css file

 Convert the scss file and place it in the css folder

.\node_modules\.bin\sass scss/main.scss css/style.css

 

  • The above command is too cumbersome, we can simplify it, use NPM Scripts, package the build command, and realize the simplest way to automate the construction of the workflow

Then, use the packaged command in the command line interface to convert the sass file into a css file:

yarn build //或者 npm run build 
注意:yarn build 的run可以省略,而npm不可以
  •  Install the browser-sync module to start a test server to run our project
yarn add browser-sync --dev// 或者 npm install browser-sync --save-dev

Then use NPM Scripts to package commands, as shown in the following figure:

Finally, use the packaged command in the command line interface to start the test server, and then arouse our browser to run our web page.

yarn serve //或者npm run serve

 

In order for us to make the build command work before starting the serve command, we can add a preserve command, which will be automatically executed before the serve command is executed. At this time, if we execute the serve again, it will automatically execute the build command first. After the build is completed, execute the corresponding serve

You can also add a --watch parameter to the sass command, and then sass will monitor the changes of the file when it is working. Once the file in the code changes, it will be automatically compiled

But when executing serve, sass will wait for file changes to block the execution of the serve command:

This causes the following browse sync to fail to work later. In this case, multiple tasks need to be performed at the same time. Here you can use the npm-run-all module to achieve this. Install this module first:

yarn add npm-run-all --dev

After having this module, you can add a new command in scripts. This command is called start. In this command, we use the run-p command in npm run all to execute the build and serve commands at the same time. Execute in line:

yarn start

At this time, try to modify the content in the sass file, the css file will also change accordingly

We add --files \"css/*.css\" in browser-sync, this parameter can monitor the changes of some files under the project (in this case, css files) after browser-sync is started, once the file changes , Browser-sync will automatically synchronize the content of these files to the browser to update the browser interface, refresh the effect, and avoid manually refreshing the browser after modifying the code.

Small summary: In the build command in scripts, it automatically monitors the changes of sass files to compile sass, browser-sync starts a web service, and refreshes the browser when the file changes.

Commonly used automation tools:

Compared with complex projects, npm scripts are relatively laborious and require more professional tools. The most used development tools are mainly:

  • Grunt, its plug-in can help you automate almost anything you want to do, but because its work process is based on temporary files, the build speed is slow.
  • Gulp, it solves the problem of grunt's very slow build speed. Its build process is completed in memory, which is much faster than disk read and write speed. In addition, it supports simultaneous execution of multiple tasks by default, as opposed to Graunt is more intuitive and easy to understand, and the plugin ecology is relatively complete. It is currently the most popular build system
  • FIS, compared to the first two micro-kernel construction systems, FIS is more like a bundled package. It integrates some typical requirements of our project as much as possible inside, for example, it can easily handle resource loading and modular development. , Code deployment, resource optimization, etc. FIS is more suitable for beginners.

Strictly speaking, webpack is a module packaging tool.

2. Basic use of Grunt

  • Create a new empty project (empty folder), use yarn to initialize, and generate a package.json file
yarn init --yes
  • Add grunt module through yarn command
yarn add grunt
  • Add the gruntfile file in the project root directory, this file is the entry file of Grunt:
code gruntfile.js
// Grunt 的入口文件
// 用于定义一些需要 Grunt 自动执行的任务
// 需要导出一个函数
// 此函数接收一个 grunt 的形参,内部提供一些创建任务时可以用到的API

module.exports = grunt => {
    //registerTask 去注册一个任务,第一个参数去指定任务的名字,第二个参数去指定一个任务函数,也就是当任务发生时自动执行的函数
    grunt.registerTask('foo',() =>{
        console.log('hello grunt~')
    })
}
  • Use the yarn grunt command output in the console:
yarn grunt foo// foo 是任务名

  • You can also add multiple tasks, use the command to view the help:
yarn grunt --help
// Grunt 的入口文件
// 用于定义一些需要 Grunt 自动执行的任务
// 需要导出一个函数
// 此函数接收一个 grunt 的形参,内部提供一些创建任务时可以用到的API

module.exports = grunt => {
    //registerTask 去注册一个任务,第一个参数去指定任务的名字,第二个参数去指定一个任务函数,也就是当任务发生时自动执行的函数
    grunt.registerTask('foo',() =>{
        console.log('hello grunt~')
    })

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

Console:

  • You can register a default task, when yarn grunt, default will be called automatically
// Grunt 的入口文件
// 用于定义一些需要 Grunt 自动执行的任务
// 需要导出一个函数
// 此函数接收一个 grunt 的形参,内部提供一些创建任务时可以用到的API

module.exports = grunt => {
    //registerTask 去注册一个任务,第一个参数去指定任务的名字,第二个参数去指定一个任务函数,也就是当任务发生时自动执行的函数
    grunt.registerTask('foo',() =>{
        console.log('hello grunt~')
    })

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

    grunt.registerTask('default',() =>{
        console.log('default task~')
    })
}

If the tasks of foo and bar are placed in the tasks of automatic tasks, they will be automatically executed in series

// Grunt 的入口文件
// 用于定义一些需要 Grunt 自动执行的任务
// 需要导出一个函数
// 此函数接收一个 grunt 的形参,内部提供一些创建任务时可以用到的API

module.exports = grunt => {
    //registerTask 去注册一个任务,第一个参数去指定任务的名字,第二个参数去指定一个任务函数,也就是当任务发生时自动执行的函数
    grunt.registerTask('foo',() =>{
        console.log('hello grunt~')
    })

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

    // grunt.registerTask('default',() =>{
    //     console.log('default task~')
    // })

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

}

  • Asynchronous tasks are supported in grunt. We use setTimeout to simulate asynchronous tasks in this task:
// Grunt 的入口文件
// 用于定义一些需要 Grunt 自动执行的任务
// 需要导出一个函数
// 此函数接收一个 grunt 的形参,内部提供一些创建任务时可以用到的API

module.exports = grunt => {
    //registerTask 去注册一个任务,第一个参数去指定任务的名字,第二个参数去指定一个任务函数,也就是当任务发生时自动执行的函数
    grunt.registerTask('foo',() =>{
        console.log('hello grunt~')
    })

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

    // grunt.registerTask('default',() =>{
    //     console.log('default task~')
    // })

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

    grunt.registerTask('async-task',() =>{
        setTimeout(() =>{
            console.log('async task working~')
        },1000)
    })
}

Run the asynchronous task on the command line, and then you will find the console delayed printing:

The grunt code supports synchronous mode by default. If you need asynchronous operation, you must use the async method of this to get a callback function. Call this callback function after the asynchronous operation is completed.

grunt.registerTask('async-task',function(){
        const done = this.async()
        setTimeout(() =>{
            console.log('async task working~')
            done()//表示下这个任务已经完成了,grunt就知道这个是个异步任务,会等待done的执行,直到done执行,grunt才会结束这个任务的执行
        },1000)
    })

Grunt marking task failed

If an error occurs in the build code, for example, the required file cannot be found, you can mark this task as a failed task and implement return false in the function:

module.exports = grunt => {
    grunt.registerTask('bad',() =>{
        console.log('bad workding~')
        return false
    })
}

When the task is run on the console, it will show that the task has failed. If the task is in a task list, after the task fails, the subsequent tasks will not be executed. For example, in the following code, the bar task cannot be executed: 

module.exports = grunt => {
    grunt.registerTask('bad',() =>{
        console.log('bad workding~')
        return false
    })

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

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

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

The above console shows that the bar task is not executed. If you use --force, all tasks will be enforced:

yarn grunt default --force

If it is an asynchronous task, there is no way to mark it with return false. You need to add false to done and mark it as a failed task:

grunt.registerTask('bad-async',function (){
        const done = this.async()
        setTimeout(() =>  {
            setTimeout(() => {
                console.log('bad async')
                done(false)
            },1000)
        })
    })

Grunt configuration method

grunt.initConfig() is an API used to add some configuration options. It receives a parameter in the form of a {} object, and the attribute name (key) of the object is generally consistent with the task name; the value can be any type.

module.exports = grunt => {
    grunt.initConfig({
        foo:'bar'
    })
    //有了上面的配置属性之后,就可以在下面的任务当中使用这个配置属性

    grunt.registerTask('foo',() =>{
        console.log(grunt.config('foo'))//接收一个字符串参数,这个字符串参数是在config当中所指定的属性的名字
    })
}

When the attribute value is an object:

module.exports = grunt => {
    grunt.initConfig({
        foo:{//属性值如果是个对象的话
            bar:123
        }
    })
    //有了上面的配置属性之后,就可以在下面的任务当中使用这个配置属性

    grunt.registerTask('foo',() =>{
        console.log(grunt.config('foo.bar'))//可以拿到对应的属性值
    })
}

Grunt multi-objective mission

Grunt supports tasks in multi-objective mode, which can be understood as the concept of subtasks. This form of task is useful for subsequent specific implementation of various construction tasks:
 

module.exports = grunt => {
    //多目标模式,可以让任务根据配置形成多个子任务
    //接收两个参数,第一个参数是任务的名字,第二个参数是一个函数(任务执行过程所需要做的事情)
    grunt.registerMultiTask('build',function(){
        console.log('build task')
    })
}

When running the task in the console, an error will be reported, indicating that some targets have not been set for our build task. This is because when setting a multi-target task, we need to configure different targets for this multi-target task, through grunt's init method To configure in config:

module.exports = grunt => {
    //多目标模式,可以让任务根据配置形成多个子任务
    grunt.initConfig({
        build:{
            css:'1',
            js:'2'
        }
    })
    //接收两个参数,第一个参数是任务的名字,第二个参数是一个函数(任务执行过程所需要做的事情)
    grunt.registerMultiTask('build',function(){
        console.log('build task')
    })
}

After the console runs, you will find that there are two subtasks executed. In fact, they are not called subtasks. They are called multi-targets in grunt, that is, the build task has two targets, one js target and one css target.

If you want to run a target separately, you can add the corresponding target name after the command line:

yarn grunt build:css

In our task, we can get the name of the current goal through this, and get the data corresponding to this goal through data, and then run the corresponding goal of the task on the console:

module.exports = grunt => {
    //多目标模式,可以让任务根据配置形成多个子任务
    grunt.initConfig({
        build:{
            css:'1',
            js:'2'
        }
    })
    //接收两个参数,第一个参数是任务的名字,第二个参数是一个函数(任务执行过程所需要做的事情)
    grunt.registerMultiTask('build',function(){
        console.log(`tartget:${this.target},data:${this.data}`)
    })
}

The key of each attribute in the build will become the target, except for the specified option

module.exports = grunt => {
    //多目标模式,可以让任务根据配置形成多个子任务
    grunt.initConfig({
        build:{
            //在option当中指定的信息会作为这个任务的配置选项出现,控制台打印不出options内容
            options:{
                foo:'bar'
            },
            css:'1',
            js:'2'
        }
    })
    //接收两个参数,第一个参数是任务的名字,第二个参数是一个函数(任务执行过程所需要做的事情)
    grunt.registerMultiTask('build',function(){
        console.log(this.options())//要想打印options里面的内容,需要用this的options方法
        console.log(`tartget:${this.target},data:${this.data}`)
    })
}

The attribute value of the target can also be an options object:

module.exports = grunt => {
    //多目标模式,可以让任务根据配置形成多个子任务
    grunt.initConfig({
        build:{
            //在option当中指定的信息会作为这个任务的配置选项出现
            options:{
                foo:'bar'
            },
            //如果说目标的配置也是一个对象的话,这个属性也可以添加options,这个options能覆盖掉对象里的options
            css:{
                options:{
                    foo:'baz'
                }
            },
            js:'2'
        }
    })
    //接收两个参数,第一个参数是任务的名字,第二个参数是一个函数(任务执行过程所需要做的事情)
    grunt.registerMultiTask('build',function(){
        console.log(this.options())
        console.log(`tartget:${this.target},data:${this.data}`)
    })
}

Use of Grunt plugin

grunt.loadNpmTaks() loads some tasks provided by the plugin:

grunt.loadNpmTasks('grunt-contrib-clean'), load grunt-contrib-clean plug-in, this plug-in is used to clean up temporary files generated during project development.

Common naming method for grunt plugins: grunt-contrib-pluginname

When using the grunt plugin to run a plugin task, the pluginname after the full plugin name is actually the task name provided: yarn grunt pluginname //or npm run grunt pluginname

  • grunt-contrib-clean:

安装:  $ yarn add grunt-contrib-clean // 或者 npm install grunt-contrib-clean

  module.exports = grunt => {
      grunt.initConfig({
          clean: {
              temp: 'temp/app.js', // 所要清除的文件的具体路径
              tempTxt: 'temp/*.txt', // 使用通配符*,删除所有txt文件
              tempFiles: 'temp/**'   // 使用**的形式,删除temp整个文件夹
          }
      })
      
      grunt.loadNpmTasks('grunt-contrib-clean')
  }

Use: The tasks in the plug-in need to be configured in initConfig().

module.exports = grunt => {
  grunt.initConfig({
    clean:{
      // temp:'temp/app.js'//清除temp下的app.js文件
      // temp:'temp/*.txt'//清除temp下所有的txt文件
      temp:'temp/**'//清除temp目录下所有的文件
    }
  })
  grunt.loadNpmTasks('grunt-contrib-clean')
}

temp file is cleared

  • Grunt-sass: is an npm module that depends on sass through npm internally. It needs an npm to provide the sass module for support, so both modules need to be installed:

Install the plug-in module: yarn add grunt-sass or npm install grunt-sass sass --save-dev

Configure sass:

module.exports = grunt => {
  grunt.initConfig({
    sass:{
      main:{//需要指定输入文件,以及最终输出的css文件路径
        files:{
          //属性名(键)为,需要输出的css的路径
          //属性值为需要输入的scss文件的路径
          'dist/css/main.css':'src/scss/main.scss'
        }
      }
    }
  })

  grunt.loadNpmTasks('grunt-sass')
}

At this time, the running console reports an error, and you need to pass in an implementation option, which is used to specify which module in grunt-sass to use to process sass compilation:

Add option to sass:

const sass = require('sass')//导入sass模块

module.exports = grunt => {
  grunt.initConfig({
    sass:{
      options:{
        sourceMap:true,//生成对应的sourceMap文件
        implementation:sass//把sass模块传入属性当中
      },
      main:{//需要指定输入文件,以及最终输出的css文件路径
        files:{
          //属性名(键)为,需要输出的css的路径
          //属性值为需要输入的scss文件的路径
          'dist/css/main.css':'src/scss/main.scss'
        }
      }
    }
  })

  grunt.loadNpmTasks('grunt-sass')
}

The console command runs:

You can see the compiled scss file in the folder:

More can be seen in the official grunt-sass documentation.

  • grunt-babel plugin, used to compile ES6 syntax, it needs to use Babel's core module @babel/core, and Babel's preset @babel/preset-env

Install the plug-in module:

 yarn add grunt-babel @babel/core @babel/preset-env --dev

At this time, grunt.loadNpmTasks() is needed to add babel tasks. As grunt-file becomes more and more complex, this method will be used more and more. At this time, there is a module ( load-grunt-tasks ) in the community that can be reduced Use of this method :

  1. Install the module:
     
     yarn add load-grunt-tasks --dev //或者 npm install load-grunt-tasks -save-dev
    

     

  2. Basic use:
      const loadGruntTasks = require('load-grunt-tasks')
      
      module.exports = grunt => {
          loadGruntTasks(grunt) // 自动加载所有的 grunt 插件中的任务
      }
    

     

After installing the babel module, modify the corresponding js:

  const loadGruntTasks = require('load-grunt-tasks')
  
  module.exports = grunt => {
      grunt.initConfig({
          babel: {//将ECMAScript最新特性转换为js
              options: { 
                  sourceMap: true,
                  // //你需要转换哪些特性,把这些特性打包形成了preset
                  presets: ['@babel/preset-env'] //env 会默认根据最新的es特性去做对应的转换
              },
              main: {
                  files: {
                      'dist/js/app.js': 'src/js/app.js'
                  }
              }
          }
      })
      loadGruntTasks(grunt) // 自动加载所有的 grunt 插件中的任务
  }

Run yarn grunt babel

 

At this time, the js file in the js folder automatically converts the original es6 code to es5, and also generates the corresponding sourceMap file:

  • The grunt-contrib-watch plug-in means that when the file changes, it can automatically track the compilation

Install the plug-in module

 yarn add grunt-contrib-watch --dev // 或者 npm install grunt-contrib-watch -save-dev 

Basic usage:

const sass = require('sass')//导入sass模块
const loadGruntTasks = require('load-grunt-tasks')

module.exports = grunt => {
  grunt.initConfig({
    sass:{
      options:{
        sourceMap:true,//生成对应的sourceMap文件
        implementation:sass//把sass模块传入属性当中
      },
      main:{//需要指定输入文件,以及最终输出的css文件路径
        files:{
          //属性名(键)为,需要输出的css的路径
          //属性值为需要输入的scss文件的路径
          'dist/css/main.css':'src/scss/main.scss'
        }
      }
    },
    babel:{//将ECMAScript最新特性转换为js
      options:{
        sourceMap:true,
        //你需要转换哪些特性,把这些特性打包形成了preset
        presets:['@babel/preset-env']//env 会默认根据最新的es特性去做对应的转换
      },
      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.registerTask('default',['sass','babel','watch'])
}

Run command

yarn grunt

 

Guess you like

Origin blog.csdn.net/weixin_41962912/article/details/111151388