《记一忘三二》前端构建工具学习

Scripts构建

sass编译

首先需要将./scss/style.scss转为./dist/style.css

bash 复制代码
# 安装sass编译工具
pnpm i sass -D
bash 复制代码
# 使用sass编译工具
npx sass ./scss/style.scss ./dist/style.css

但这样在执行编译命令时,需要记住目录、配置等编译参数

json 复制代码
{
    "scripts": {
        "build": "sass ./scss/style.scss ./dist/style.css"
    }, 
    "devDependencies": {
        "sass": "^1.85.1"
    }
}

配置scripts能够给长命令 取一个命令别名,这样只需要执行这个命令别名就可以了

bash 复制代码
# 执行scripts的命令
npx run build

browser-sync服务

开启web服务器

bash 复制代码
# 安装browser-sync
npm i browser-sync -D
bash 复制代码
#  启动web服务器
npx browser-sync ./

命令在scripts中配置命令别名

json 复制代码
{
    "scripts": {
        "build": "sass ./scss/style.scss ./dist/style.css",
        "browser": "browser-sync ./"
    },
    "devDependencies": {
        "browser-sync": "^3.0.3",
        "sass": "^1.85.1"
    }
}

**&&**串行

build命令browser命令都是需要单独执行的,但是sass编译是项目启动的前提,也就是说在执行browser命令时,都需要提前执行build命令

通过添加serve命令,使用**&&实现 串行**build命令browser命令

json 复制代码
{
    "scripts": {
        "build": "sass ./scss/style.scss ./dist/style.css",
         "browser": "browser-sync ./ --files \"dist/*.css\"",
        "serve": "npm run build && npm run browser"
    },
    "devDependencies": {
        "browser-sync": "^3.0.3",
        "sass": "^1.85.1"
    }
}

sass编译添加--watch

json 复制代码
{
    "scripts": {
        "build": "sass ./scss/style.scss ./dist/style.css --watch",
        "browser": "browser-sync ./",
        "serve": "npm run build && npm run browser"
    },
    "devDependencies": {
        "browser-sync": "^3.0.3",
        "sass": "^1.85.1"
    }
}

单独执行build命令并没有发生问题,并且scss文件也能实现监听并且改变

但是去执行serve命令,会发现build命令之后,控制台就停顿了,后续未执行browser命令

npm-run-all

因为--watch需要单独开启一个控制台, build命令browser命令串行显然是行不通的

bash 复制代码
npm install npm-run-all --save-dev
json 复制代码
{
    "scripts": {
        "build": "sass ./scss/style.scss ./dist/style.css --watch",
        "browser": "browser-sync ./ --files \"dist/*.css\"",
        "serve": "run-p  build browser"
    },
    "devDependencies": {
        "browser-sync": "^3.0.3",
        "npm-run-all": "^4.1.5",
        "sass": "^1.85.1"
    }
}

run-p能够并行 执行build命令browser命令

Grunt工作流

基础使用

bash 复制代码
# 安装grunt
npm i grunt -D

根目录创建gruntfile.js文件

js 复制代码
module.exports = (grunt) => {
    grunt.registerTask("task", () => {
        console.log("task")
    })
}
bash 复制代码
# 执行 task 任务
npx grunt task

定义任务

grunt.registerTask(任务名称, 任务函数)

同步任务

js 复制代码
module.exports = (grunt) => {
    grunt.registerTask("task", () => {
        console.log("task")
    })
}
bash 复制代码
# 执行 task 任务
npx grunt task

异步任务

js 复制代码
grunt.registerTask("async-task", function () {
    const done = this.async()
    setTimeout(() => {
        console.log("async-task")
        done()
    }, 1000)
})

done函数被调用,表示异步任务执行完毕

注:使用this关键生成done函数,所以不能使用箭头函数

bash 复制代码
# 执行 task 任务
npx grunt async-task

默认任务

js 复制代码
module.exports = (grunt) => {
    grunt.registerTask("task", () => {
        console.log("task")
    })

    grunt.registerTask("default", ["task"])
}
bash 复制代码
# 执行默认任务,会自动执行第二参数的全部任务名称
npx grunt 

标记任务失败

同步任务

js 复制代码
module.exports = (grunt) => {
  grunt.registerTask('error-task', () => {
    return false
  })
}
bash 复制代码
# 执行 error-task 任务
npx grunt error-task

异步任务

js 复制代码
module.exports = (grunt) => {
  grunt.registerTask('async-error-task', function () {
    const done = this.async()
    setTimeout(() => {
      done(false)
    }, 1000)
  })
}
bash 复制代码
# 执行 async-error-task 任务
npx grunt async-error-task

多个任务

js 复制代码
module.exports = (grunt) => {
  grunt.registerTask('error-task-1', () => {
    console.log('error-task-1')
    return false
  })
  grunt.registerTask('error-task-2', () => {
    console.log('error-task-2')
  })

  grunt.registerTask('default', ['error-task-1', 'error-task-2'])
}
bash 复制代码
npx grun

当前任务执行失败还会影响后续任务执行

js 复制代码
npx grun --force

--force能够忽略执行失败的任务,后续的任务会照常执行

执行方式

中途有任务标记失败,就会终止这次执行

js 复制代码
module.exports = (grunt) => {
  // 定义同步任务 task-1
  grunt.registerTask('task-1', () => {
    console.log('task-1')
  })

  // 定义同步任务 task-2
  grunt.registerTask('task-2', function () {
    const done = this.async()
    setTimeout(() => {
      console.log('task-2')
      done()
    }, 1000)
  })

  // 定义同步任务 task-3
  grunt.registerTask('task-3', () => {
    console.log('task-3')
  })

  // 定义任务队列
  grunt.registerTask('default', ['task-1', 'task-2', 'task-3'])
}

同步串行

js 复制代码
module.exports = (grunt) => {
  grunt.registerTask('hello', () => {
    console.log('Hello, Grunt!')
  })

  grunt.registerTask('world', () => {
    console.log('Hello, World!')
  })

  grunt.registerTask('say', () => {
    console.log('Hello, say!')
  })

  grunt.registerTask('parallel', ['hello', 'world', 'say'])
}

异步串行

异步任务会等待上一个任务执行完毕

js 复制代码
module.exports = (grunt) => {
  grunt.registerTask('async-task-1', function () {
    const done = this.async()
    setTimeout(() => {
      console.log('async-task-1')
      done()
    }, 1000)
  })

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

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

  grunt.registerTask('series', ['async-task-1', 'async-task-2', 'async-task-3'])
}

配置参数

options

this.options()获取的配置参数,只要在initConfig配置的参数都可以按照路径进行访问

js 复制代码
module.exports = (grunt) => {
  grunt.initConfig({
    build: {
      options: {
        soureMap: true,
      },
    },
  })

  grunt.registerTask('build', function () {
    const options = this.options()

    console.log(options)
  })
}

grunt.initConfig数据

grunt.initConfig配置的数据,可通过grunt.config('具体路径')获取数据

js 复制代码
module.exports = (grunt) => {
  grunt.initConfig({
    js: './src/js/index.js',
    build: {
      css: './src/css/index.css',
    },
  })

  grunt.registerTask('build', () => {
    const js = grunt.config('js')
    const css = grunt.config('build.css')

    console.log(css, js)
  })
}

注: grunt.config能够获取options数据

多目标任务

js 复制代码
module.exports = (grunt) => {
  grunt.initConfig({
    build: {
      options: {
        soureMap: true,
      },
      css: {
        options: {
          soureMap: false,
        },
        src: './css/index.css',
        dist: './css/index.css',
      },
      js: {
        src: './js/index.js',
        dist: './js/index.js',
      },
    },
  })

  grunt.registerMultiTask('build', function () {
    const options = this.options()
    const target = this.target
    const data = this.data

    console.log(target, options, data)
  })
}

一个任务有多个目标,也可以说一个目标下面的子任务

在执行build任务时,会执行cssjs两个子任务

bash 复制代码
# 执行 build 主任务
npx grunt build

并且还可以单独子任务

bash 复制代码
# 执行 build:css 子任务
npx grunt build:css
# 执行 build:js 子任务
npx grunt build:js

插件使用

grunt-contrib-clean

bash 复制代码
# 安装 grunt-contrib-clean
pnpm  i grunt-contrib-clean -D

加载grunt-contrib-clean插件,并设置任务目标

js 复制代码
module.exports = (grunt) => {
  grunt.initConfig({
    // 设置 grunt-contrib-clean 的目标
    clean: {
      dist: {
        src: ['./dist/**'],
      },
    },
  })

  // 加载 grunt-contrib-clean 插件
  grunt.loadNpmTasks('grunt-contrib-clean')
}
bash 复制代码
# 执行 clean 任务
npx grunt clean

注:一般情况下,grunt的插件名称是grunt-contrib-(插件任务名称)

综合示例

bash 复制代码
# 安装依赖
npm install grunt-contrib-clean grunt-contrib-uglify @babel/core @babel/preset-env grunt grunt-babel grunt-contrib-watch -D
js 复制代码
module.exports = (grunt) => {
  grunt.initConfig({
    clean: {
      dist: {
        src: ['./dist/**'],
      },
    },
    uglify: {
      dist: {
        files: {
          './dist/index.js': './dist/index.js',
        },
      },
    },
    babel: {
      options: {
        presets: ['@babel/preset-env'],
      },
      dist: {
        files: {
          './dist/index.js': './src/index.js',
        },
      },
    },
    watch: {
      scripts: {
        files: ['src/**/*.js'],
        tasks: ['babel', 'uglify'],
        options: {
          spawn: false,
        },
      },
    },
  })

  grunt.loadNpmTasks('grunt-babel')
  grunt.loadNpmTasks('grunt-contrib-clean')
  grunt.loadNpmTasks('grunt-contrib-uglify')
  grunt.loadNpmTasks('grunt-contrib-watch')
  grunt.registerTask('default', ['clean', 'babel', 'uglify', 'watch'])
}

Gulp工作流

基础使用

bash 复制代码
npm i gulp -D

根目录创建gulpfile.js文件

js 复制代码
exports.world = (done) => {
  console.log('world')
  done()
}

exports.asyncTask = (done) => {
  setTimeout(() => {
    console.log('asyncTask')
    done()
  })
}

exports.default = (done) => {
  console.log('default')
  done()
}
bash 复制代码
# 执行 world 任务
npx gulp world
# 执行 asyncTask 任务
npx gulp asyncTask
# 执行 default 任务,也就是默认任务
npx gulp

定义任务

任何任务都需要标记结束,通常使用done

默认任务

js 复制代码
exports.default = (done) => {
  console.log('default')
  done()
}

同步任务

js 复制代码
exports.world = (done) => {
  console.log('world')
  done()
}

异步任务

done
js 复制代码
exports.asyncTask = (done) => {
  setTimeout(() => {
    console.log('asyncTask')
    done()
  })
}
Promise
js 复制代码
exports.asyncTask = () => {
  console.log('asyncTask')
  return Promise.resolve()
}
async
JS 复制代码
exports.asyncTask = async () => {
  console.log('asyncTask')
}
on监听
js 复制代码
const {
  src,
  dest,
} = require('gulp')

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

自动监听end事件进行任务结束判断

js 复制代码
const {
  src,
  dest,
} = require('gulp')

exports.copy_src = (done) => {
  src('src/**').pipe(dest('dist')).on('end', done)
}

标记任务失败

done
js 复制代码
exports.error_task = (done) => {
  done(new Error('error-task failed'))
}

exports.async_error_task = (done) => {
  setTimeout(() => {
    done(new Error('async-error-task failed'))
  }, 1000)
}
Promise
js 复制代码
exports.error_task = () => {
  return Promise.reject(new Error('error-task failed'))
}
async
js 复制代码
exports.error_task = async () => {
  throw new Error('error-task failed')
}

执行方式

异步串行

js 复制代码
const { series } = require('gulp')

function async_task_1(done) {
  setTimeout(() => {
    console.log('async task 1')
    done()
  }, 1000)
}

function async_task_2(done) {
  setTimeout(() => {
    console.log('async task 2')
    done()
  }, 1000)
}

function async_task_3(done) {
  setTimeout(() => {
    console.log('async task 3')
    done()
  }, 1000)
}

exports.series = series(async_task_1, async_task_2, async_task_3)

异步并行

js 复制代码
const { parallel } = require('gulp')

function async_task_1(done) {
  setTimeout(() => {
    console.log('async task 1')
    done()
  }, 1000)
}

function async_task_2(done) {
  setTimeout(() => {
    console.log('async task 2')
    done()
  }, 1000)
}

function async_task_3(done) {
  setTimeout(() => {
    console.log('async task 3')
    done()
  }, 1000)
}

exports.parallel = parallel(async_task_1, async_task_2, async_task_3)

同步串行

js 复制代码
const { series } = require('gulp')

function task_1(done) {
  console.log('async task 1')
  done()
}

function task_2(done) {
  console.log('async task 2')
  done()
}

function task_3(done) {
  console.log('async task 3')
  done()
}

exports.series = series(task_1, task_2, task_3)

异步并行

js 复制代码
const { parallel } = require('gulp')

function task_1(done) {
  console.log('async task 1')
  done()
}

function task_2(done) {
  console.log('async task 2')
  done()
}

function task_3(done) {
  console.log('async task 3')
  done()
}

exports.parallel = parallel(task_1, task_2, task_3)

Webpack

devtool

当浏览器加载并执行一个包含sourceMappingURL注释的JavaScript文件时,会自动根据该注释中指定的目录地址加载对应的映射文件。浏览器将根据加载到的文件内容,生成源文件现文件之间的映射信息,从而实现源代码的调试功能

会根据不同的devtool生成不同的sourceMappingURL注释

方式

false

不生成映射注释

eval
js 复制代码
//# sourceURL=webpack://my-webpack/./src/main.js?

浏览器不会加载映射文件,根据源文件 的内容在src/main.js位置生成一份一样的文件,映射关系介绍行对行

source-map
js 复制代码
//# sourceMappingURL=bundle.js.map

浏览器加载映射文件bundle.js.map,生成映射关系源文件

映射文件

json 复制代码
{
    "version": 3,
    "file": "bundle.js",
    "mappings": ";;;;;;;;;;;;;;;;;AAAA,.....CAACT,gDAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,C",
    "sources": [
        "webpack://my-webpack/./src/utils/math.js",
        "webpack://my-webpack/webpack/bootstrap",
        "webpack://my-webpack/webpack/runtime/define property getters",
        "webpack://my-webpack/webpack/runtime/hasOwnProperty shorthand",
        "webpack://my-webpack/webpack/runtime/make namespace object",
        "webpack://my-webpack/./src/main.js"
    ],
    "sourcesContent": [
        "const sum = (a, b) => a + b;\r\n\r\nconst subtract = (a, b) => a - b;\r\n\r\nconst ...... \r\nconsole.log(sum(1, 2));"
    ],
    "names": [
        "sum",
        "a",
        "subtract",
        "b",
        "address"
    ],
    "sourceRoot": ""
}
  • version: 指定源码映射的版本,这里是第 3 版。第 2 版比第 1 版生成的映射文件大小减少%,第 3 版比第 2 版减少%
  • file : 构建后的文件名称 bundle.js
  • mappings: 包含了实际的映射关系,这是一个 Base64 编码的字符串,用于描述源文件和构建后文件之间的对应关系。这个字符串的具体含义需要通过解码和解析才能理解
  • sources : 包含了源文件的路径列表。这里列出了多个源文件,例如 src/utils/math.jssrc/main.js 等,这些文件可能通过 Webpack 等工具打包生成了 bundle.js
  • sourcesContent: 包含了源文件的内容
  • names: 包含了源文件中出现的变量和函数名称
  • sourceRoot:表示指定源文件的根目录
相关推荐
万少6 分钟前
HarmonyOS Next 弹窗系列教程(3)
前端·harmonyos·客户端
七灵微1 小时前
【后端】单点登录
服务器·前端
持久的棒棒君5 小时前
npm安装electron下载太慢,导致报错
前端·electron·npm
crary,记忆7 小时前
Angular微前端架构:Module Federation + ngx-build-plus (Webpack)
前端·webpack·angular·angular.js
漂流瓶jz8 小时前
让数据"流动"起来!Node.js实现流式渲染/流式传输与背后的HTTP原理
前端·javascript·node.js
SamHou08 小时前
手把手 CSS 盒子模型——从零开始的奶奶级 Web 开发教程2
前端·css·web
我不吃饼干8 小时前
从 Vue3 源码中了解你所不知道的 never
前端·typescript
开航母的李大8 小时前
【中间件】Web服务、消息队列、缓存与微服务治理:Nginx、Kafka、Redis、Nacos 详解
前端·redis·nginx·缓存·微服务·kafka
Bruk.Liu8 小时前
《Minio 分片上传实现(基于Spring Boot)》
前端·spring boot·minio
鱼樱前端9 小时前
Vue3+d3-cloud+d3-scale+d3-scale-chromatic实现词云组件
前端·javascript·vue.js