共计 8766 个字符,预计需要花费 22 分钟才能阅读完成。
什么是项目构建?
项目构建包括如下内容:
代码转换:将 TypeScript 编译成 JavaScript、将 LESS 编译成 CSS 等。
文件优化:压缩 JavaScript、CSS、HTML 代码,压缩合并图片等。
代码分割:提取多个页面的公共代码,提取首屏不需要执行部分代码让其异步记在。
模块合并:在采用模块化的项目里会有很多个模块和文件,需要通过构建功能将模块分类合并成一个文件。
自动刷新:监听本地源代码变化,自动重新构建、刷新浏览器。
代码校验:在代码被提交到仓库前需要校验代码是否符合规范,以及单元测试是否通过。
自动发布:更新代码后,自动构建出线上发布代码并传输给发布系统。
构建工具就是做以上这些事,将源代码转换成可以执行的 JavaScript、CSS、HTML 代码。
构建环境的认识
我们对平时开发的代码区分了两种环境:
开发环境 development
自动编译运行项目、检查语法错误、详细的错误提示等 …(能帮助程序员更好的写代码, 在内存中编译运行,没有任何文件输出)
生产环境 production
压缩代码、兼容性处理等 …(生成打包后的项目文件,提供项目上线使用)
而我们使用的库也分为两种依赖:
开发依赖 devDependencies
项目构建打包需要的依赖
生产依赖 dependencies
项目上线运行时需要的依赖
gulp 介绍
gulp 中文网:https://www.gulpjs.com.cn/
gulp 是与 grunt 功能类似的前端项目构建工具, 是基于 nodejs 平台运行
能自动化地完成 javascript/coffee/sass/less/html/image/css 等文件的合并、压缩、检查、监听文件变化、浏览器自动刷新、测试等任务
gulp 更高效 (异步多任务), 更易于使用, 插件高质量
使用 gulp 插件
下文中使用的插件你都可以在 npm 或者 gulp 官网上找到具体的使用用法,我下面说做的配置都是基础或者默认的,你也可以自行配置
gulp 开发套路
开发套路:
去 https://gulpjs.com/plugins/ 搜 … gulp-xxx
打开插件的 npm 仓库 看文档使用
下载并引入 gulp 插件
配置插件任务
相关插件:
gulp-eslint : js 文件语法检查
gulp-babel: js 语法转换
gulp-browserify: 将 commonjs 模块化转换浏览器能识别的语法
gulp-connect: 用于运行网络服务器的 Gulp 插件
open: 在用户首选的应用程序中打开文件或 URL
less-plugin-autoprefix: 使用 autoprefixer 从 less 转换后为 css 添加前缀。
gulp-concat : 合并文件 (js/css)
gulp-uglify : 压缩 js 文件
gulp-rename : 文件重命名
gulp-less : 编译 less
gulp-clean-css : 压缩 css
gulp-cssmin: 压缩 css
gulp-livereload : 实时自动编译刷新
重要 API
gulp.src(filePath/pathArr) : 指向指定路径的所有文件, 返回文件流对象, 用于读取文件
gulp.dest(dirPath/pathArr): 指向指定的所有文件夹, 用于向文件夹中输出文件
gulp.task(name, [deps], fn): 定义一个任务
gulp.watch() : 监视文件的变化
* 安装 gulp
npm install gulp-cli -g 全局安装
npm install gulp –save-dev 局部安装
配置编码: gulpfile.js
将所有要配置的的代码写到里面
处理 js 文件
1、js 文件语法检查
准备工作:创建 js 文件
src/js/module1.js
src/js/module2.js
src/js/module3.js
src/js/main.js
下载插件:
npm install gulp-eslint –save-dev
配置编码
const gulp = require(‘gulp’);
const eslint = require(‘gulp-eslint’);
// 语法检查 必须有一个 eslint 的配置文件
gulp.task(‘eslint’, function () {
// 读取所有的 js 文件,返回值就是一个可读流
return gulp.src([‘src/js/*.js’])
// 对流中的文件 / 数据进行语法检查
.pipe(eslint())
.pipe(eslint.format())
.pipe(eslint.failAfterError())
.pipe(livereload());
})
在 package.json 中配置 eslint 的检查项
“eslintConfig”: {
“parserOptions”: {
“ecmaVersion”: 7,
“sourceType”: “module”,
“ecmaFeatures”: {
“module”: true
}
}
}
//package.json 文件内容,eslint 的检查项放置位置
“author”: “”,
“license”: “ISC”,
“dependencies”: {},
“devDependencies”: {},
“eslintConfig”: {
“parserOptions”: {
“ecmaVersion”: 7,
“sourceType”: “module”,
“ecmaFeatures”: {
“module”: true
}
}
}
运行指令: gulp eslint
2、js 语法转换
下载插件:
npm install –save-dev gulp-babel @babel/core @babel/preset-env
配置编码
const babel = require(‘gulp-babel’);
// babel 能将 es6 模块化语法转换为 commonjs 模块化语法
// 能将 es6 及其以上的语法转换为 es5 及其以下的语法
gulp.task(‘babel’, () =>
// 读取所有 js 文件
gulp.src(‘src/js/*.js’)
// 进行语法转换
.pipe(babel({
presets: [‘@babel/preset-env’] // 此处需要修改,官网有误
}))
// 输出出去,输出路径
.pipe(gulp.dest(‘build/js’))
);
运行指令: gulp babel
3、将 commonjs 模块化转换浏览器能识别的语法
下载插件:
npm install –save-dev gulp-browserify
注意:这里是将 commonjs 模块化语法后的 js 文件转换浏览器能识别的语法
配置编码
const browserify = require(‘gulp-browserify’);
const rename = require(“gulp-rename”);
// 重命名文件,为了不与 babel 产生的文件命名起冲突,可以保留 banel 产生的 js 文件
gulp.task(‘browserify’, function() {
// 只要放入口文件
return gulp.src(‘build/js/app.js’)
.pipe(browserify())
// 重命名文件
.pipe(rename(“built.js”))
.pipe(gulp.dest(‘build/js’))
});
运行指令: gulp browserify
4、压缩 JS
下载插件:
npm install –save-dev gulp-uglify
配置编码
const uglify = require(‘gulp-uglify’);
const rename = require(‘gulp-rename’);
gulp.task(‘uglify’, function() {
return gulp.src(‘./build/js/built.js’)
.pipe(uglify())
.pipe(rename(‘dist.min.js’))
.pipe(gulp.dest(‘./dist/js/’))
});
gulp.task(‘js-prod’, gulp.series(‘js-dev’, ‘uglify’)); // 顺序执行
运行指令: gulp js-prod
处理 less 文件
准备工作:创建 less 文件
src/less/test1.less
src/less/test2.less
1. 将 less 编译成 css
下载插件:
npm install gulp-less –save-dev
配置编码
const less = require(‘gulp-less’);
gulp.task(‘less’, function () {
return gulp.src(‘./src/less/*.less’)
.pipe(less())
.pipe(gulp.dest(‘./build/css’))
});
运行指令: gulp less
2、压缩 css
下载插件
npm install gulp-clean-css less-plugin-autoprefix –save-dev
配置编码
// 第一种方案,采用 gulp-clean-css
const cleanCSS = require(‘gulp-clean-css’);
const LessAutoprefix = require(‘less-plugin-autoprefix’);
const autoprefix = new LessAutoprefix({browsers: [“cover 99.5%”, “not dead”] });
const connect = require(‘gulp-connect’); 合并 css 文件
gulp.task(‘css’, function () {
return gulp.src(‘./src/less/*.less’)
.pipe(less({
plugins: [autoprefix] // 自动扩展样式的兼容性前缀
})) // 将 less 文件转换成 css 文件
.pipe(concat(‘dist.min.css’)) // 合并 css 文件
.pipe(cleanCSS({compatibility: ‘ie8’})) // 压缩 css 文件
.pipe(gulp.dest(‘./dist/css’))
});
// 第二种方案,采用 gulp-cssmin
const cssmin = require(‘gulp-cssmin’); 合并 css 文件
const LessAutoprefix = require(‘less-plugin-autoprefix’);
const autoprefix = new LessAutoprefix({browsers: [“cover 99.5%”, “not dead”] });
// 与 LessAutoprefix 相配合,使用 autoprefixer 从 less 转换后为 css 添加前缀,因为有些浏览器对一些带有前缀的 css 才能识别
const connect = require(‘gulp-connect’);
gulp.task(‘css’, function () {
return gulp.src(‘./src/less/*.less’)
.pipe(concat(‘dist.min.css’))
.pipe(less({
plugins: [autoprefix]
}))
.pipe(cssmin())
.pipe(gulp.dest(‘./dist/css’))
});
运行指令: gulp css
处理 html
1. 压缩 html
下载插件:
npm install gulp-htmlmin –save-dev
配置编码
var htmlmin = require(‘gulp-htmlmin’);
// 压缩 html 任务
gulp.task(‘html’, () => {
return gulp.src(‘src/*.html’)
.pipe(htmlmin({
collapseWhitespace: true, // 去除空格
removeComments: true // 去掉注释
}))
.pipe(gulp.dest(‘dist’));
});
修改页面引入
<link rel=”stylesheet” href=”css/dist.min.css”>
<script type=”text/javascript” src=”js/dist.min.js”></script>
运行指令: gulp html
自动编译代码
下载插件
npm install gulp-livereload –save-dev
配置编码:
const livereload = require(‘gulp-livereload’);
// 所有的任务最后加上 .pipe(livereload()) 这条代码决定自动编译哪个任务
gulp.task(‘watch’, function() {
livereload.listen();
gulp.watch(‘src/less/*.less’, gulp.series(‘less’));
gulp.watch(‘src/js/*.js’, gulp.series(‘js’));
});
运行指令: gulp watch
自动打开 / 更新页面(热更新)
下载插件
npm install gulp-connect open –save-dev
配置编码
// 自动化 –> 自动编译 –> 自动刷新浏览器(热更新)–> 自动打开浏览器
gulp.task(‘watch’, function() {
livereload.listen();
// 开启服务器
connect.server({
name: ‘Dev App’,
root: [‘build’], // 提供服务的根路径
port: 3000, // 开启端口号
livereload: true // 是否实时刷新
});
// 自动打开浏览器, 开启链接
open(‘http://localhost:3000’);
// 监视指定文件,一旦文件发生变化,就执行后面的任务
gulp.watch(‘src/less/*.less’, gulp.series(‘less’));
gulp.watch(‘src/js/*.js’, gulp.series(‘js-dev’));
});
运行指令: gulp watch
配置默认任务 –> 执行以上多个任务
// gulp.series()同步顺序执行,同一时间只能执行一个任务 速度慢
// gulp.parallel()异步执行,同一时间执行多个任务 速度快
gulp.task(‘js-dev’, gulp.series(‘eslint’, ‘babel’, ‘browserify’));
gulp.task(‘js-prod’, gulp.series(‘js-dev’, ‘uglify’));
gulp.task(‘build’, gulp.parallel(‘js-dev’, ‘less’));
// 生产环境的指令: gulp prod
gulp.task(‘prod’, gulp.parallel(‘js-prod’, ‘css’, ‘html’));
// 开发环境的指令:gulp start
gulp.task(‘start’, gulp.series(‘build’, ‘watch’));
我的文件目录
下面是我的 gulpfile.js 配置文件
// 引入 gulp
const gulp = require(‘gulp’);
const eslint = require(‘gulp-eslint’);
const babel = require(‘gulp-babel’);
const browserify = require(‘gulp-browserify’);
const rename = require(“gulp-rename”);
const less = require(‘gulp-less’);
const livereload = require(‘gulp-livereload’);
const connect = require(‘gulp-connect’);
const open = require(“open”);
const uglify = require(‘gulp-uglify’);
const LessAutoprefix = require(‘less-plugin-autoprefix’);
// https://github.com/browserslist/browserslist
const autoprefix = new LessAutoprefix({browsers: [“cover 99.5%”, “not dead”] });
const cssmin = require(‘gulp-cssmin’);
const concat = require(‘gulp-concat’);
const htmlmin = require(‘gulp-htmlmin’);
// 语法检查 必须有一个 eslint 的配置文件
gulp.task(‘eslint’, function () {
// 读取所有的 js 文件,返回值就是一个可读流
return gulp.src([‘src/js/*.js’])
// 对流中的文件 / 数据进行语法检查
.pipe(eslint())
.pipe(eslint.format())
.pipe(eslint.failAfterError())
.pipe(livereload());
})
// 语法转换
// babel 能将 es6 模块化语法转换为 commonjs 模块化语法
// 能将 es6 及其以上的语法转换为 es5 及其以下的语法
gulp.task(‘babel’, () =>
// 读取所有 js 文件
gulp.src(‘src/js/*.js’)
// 进行语法转换
.pipe(babel({
presets: [‘@babel/preset-env’] // 此处需要修改,官网有误
}))
// 输出出去
.pipe(gulp.dest(‘build/js’))
.pipe(livereload())
);
// 将 commonjs 的模块化语法转换成浏览器能识别语法
gulp.task(‘browserify’, function() {
// 只要放入口文件
return gulp.src(‘build/js/app.js’)
.pipe(browserify())
// 重命名文件
.pipe(rename(“built.js”))
.pipe(gulp.dest(‘build/js’))
.pipe(livereload());
});
// 压缩 js 代码
gulp.task(‘uglify’, function () {
return gulp.src(‘./build/js/built.js’)
.pipe(uglify())
.pipe(rename(‘dist.min.js’))
.pipe(gulp.dest(‘dist/js’))
})
// 将 less 编译成 css
gulp.task(‘less’, function () {
return gulp.src(‘./src/less/*.less’)
.pipe(less())
.pipe(gulp.dest(‘./build/css’))
.pipe(livereload());
});
// 压缩 css
gulp.task(‘css’, function () {
return gulp.src(‘./src/less/*.less’)
.pipe(concat(‘dist.min.css’))
.pipe(less({
plugins: [autoprefix]
}))
.pipe(cssmin())
.pipe(gulp.dest(‘./dist/css’))
});
// 压缩 html
gulp.task(‘html’, () => {
return gulp.src(‘src/*.html’)
.pipe(htmlmin({
collapseWhitespace: true, // 去除空格
removeComments: true // 去掉注释
}))
.pipe(gulp.dest(‘dist’));
});
// 自动化 –> 自动编译 –> 自动刷新浏览器(热更新)–> 自动打开浏览器
gulp.task(‘watch’, function() {
livereload.listen();
// 开启服务器
connect.server({
name: ‘Dev App’,
root: [‘build’],
port: 3000,
livereload: true // 热更新
});
// 打开浏览器
open(‘http://localhost:3000’);
// 监视指定文件,一旦文件发生变化,就执行后面的任务
gulp.watch(‘src/less/*.less’, gulp.series(‘less’));
gulp.watch(‘src/js/*.js’, gulp.series(‘js-dev’));
});
// 配置默认任务 –> 执行以上多个任务
gulp.task(‘js-dev’, gulp.series(‘eslint’, ‘babel’, ‘browserify’));
gulp.task(‘js-prod’, gulp.series(‘js-dev’, ‘uglify’));
// gulp.task(‘default’, gulp.parallel(‘eslint’, ‘babel’, ‘browserify’));
gulp.task(‘build’, gulp.parallel(‘js-dev’, ‘less’));
// 生产环境的指令: gulp prod
gulp.task(‘prod’, gulp.parallel(‘js-prod’, ‘css’, ‘html’));
// 开发环境的指令:gulp start
gulp.task(‘start’, gulp.series(‘build’, ‘watch’));