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任务
时,会执行css
、js
两个子任务
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.js
和src/main.js
等,这些文件可能通过 Webpack 等工具打包生成了bundle.js
sourcesContent
: 包含了源文件的内容names
: 包含了源文件中出现的变量和函数名称sourceRoot
:表示指定源文件的根目录