项目结构
项目整体结构如下:
|____public
| |____favicon.ico
|____src
| |____assets
| | |____fonts
| | | |____pages.eot
| | | |____pages.svg
| | | |____pages.ttf
| | | |____pages.woff
| | |____images
| | | |____brands.svg
| | | |____logo.png
| | |____scripts
| | | |____main.js
| | |____styles
| | | |_icons.scss
| | | |_variables.scss
| | | |main.scss
| |____layouts
| | |____basic.html
| |____partials
| | |____footer.html
| | |____header.html
| |____about.html
| |____index.html
|____package.json
pubilc中都是静态文件无需编译,src下是源代码,需要构建成浏览器认识的代码哦。
开始前先把今天的主角gulp安装上, 安装在开发依赖哦 yarn add gulp -D
进入正题
样式编译
当前项目下创建gulpfile.js文件,进入该文件开始写我们的构建任务,默认构建到dist文件
const {src, dest} = require('gulp')
const style = () => {
return src('src/assets/styles/*.scss', {base: 'src'})
.pipe(dest('dist'))
}
module.exports = {
style
}
执行命令
yarn gulp style
得到
将src/assets/styles的所有css拷贝到dist文件,其中base配置是保证基准路径,保证拷贝的文件路径与src下文件一致
接下来安装插件将scss装换成css
yarn add gulp-sass sass -D
引入sass根据文档
const sass = require('gulp-sass')(require('sass'));
此时style中添加sass转换
const style = () => {
return src('src/assets/styles/*.scss', {base: 'src'})
.pipe(sass({outputStyle: 'expanded'}))
.pipe(dest('dist'))
}
但是再次执行style命令
脚本编译
与样式的编写一致,切换下插件
yarn add gulp-babel -D
gulp-babel只是挂起babel,核心转换需要babel/core , @babel/preset-env是可以ecma新特性都进行转换
yarn add @babel/core @babel/preset-env -D
编写脚本任务,此时gulpfile.js文件内容是这样的
const { src, dest } = require('gulp')
const sass = require('gulp-sass')(require('sass'));
const babel = require('gulp-babel')
const style = () => {
return src('src/assets/styles/*.scss', { base: 'src' })
.pipe(sass({ outputStyle: 'expanded' }))
.pipe(dest('dist'))
}
const scripts = () => {
return src('src/assets/scripts/*.js', { base: 'src' })
.pipe(babel({ presets: ["@babel/preset-env"] }))
.pipe(dest('dist'))
}
module.exports = {
style,
scripts
}
执行脚本命令
页面html编译
此处需要安装模板引擎,这里用了gulp-swig
yarn add gulp-swig -D
const swig = require('gulp-swig')
// ... other code
const pages = () => {
return src('src/**/*.html', { base: 'src' })
.pipe(swig())
.pipe(dest('dist'))
}
**代表匹配src下任意子目录,此处html文件分别在几个文件里。
样式,脚本,页面组合
构建时同时调用
const { src, dest, parallel } = require('gulp')
// ...
const compile = parallel(style, scripts, pages)
module.exports = {
...,
compile
}
图片和字体文件转换
安装图片插件
yarn add gulp-imagemin -D
ps: 直接安装gulp-imagemin(当前版本^8.0.0)执行命令会报错,此处处理降了一个版本(^7.1.0)就正常执行了 【且是一个通过c++完成的模块,需要从github上下载,比较慢】 编写任务
const imagemin = require('gulp-imagemin');
//...
const images = () => {
return src('src/assets/images/**', { base: 'src' })
.pipe(imagemin())
.pipe(dest('dist'))
}
//遇到不是图片的文件直接略过,字体文件一般没办法压缩,拷贝就好了
const fonts = () => {
return src('src/assets/fonts/**', { base: 'src' })
.pipe(imagemin())
.pipe(dest('dist'))
}
//...
const compile = parallel(style, scripts, pages, images, fonts)
module.exports = {
compile
}
此处就直接并行执行所有了
查看dist文件【执行前已经删除了老dist文件】
其他文件public及文件清除
这里只有一个文件,直接拷贝就好
|____public
| |____favicon.ico
删除任务需要安装一个插件del【del不是gulp模块,但是可以使用,且返回一个promise方法,gulp支持的】
yarn add del -D
编写拷贝plblic任务
//...其他文件:public
const extra = () => {
return src('public/**', { base: 'public' })
.pipe(dest('dist'))
}
//清除任务
const clean = () => {
return del(['dist'])
}
之前一直手动删除dist文件,现在可执行yarn gulp clean自动删除dist
执行命令yarn gulp extra
改造下构建任务执行前先删除dist,这里执行build
const { src, dest, parallel, series } = require('gulp')
//...
const compile = parallel(style, scripts, pages, images, fonts)
//构建
const build = series(clean, parallel(compile, extra))
module.exports = {
compile,
clean,
build
}
看着木有问题哦,先执行的clean,clean结束在执行后续
自动加载插件
使用gulp-load-plugins来解决require插件过多的问题
yarn add gulp-load-plugins -D
ps: 碰到最新版sass单独使用,至少不会报错 插件使用:
const loadPlugins = require('gulp-load-plugins')
const plugins = loadPlugins()
const sass = require('gulp-sass')(require('sass'));
// const babel = require('gulp-babel')
// const swig = require('gulp-swig')
// const imagemin = require('gulp-imagemin');
// const del = require('del')
所有的gulp插件都会被挂载到plugins对象里面,对象的属性命名规则是去掉gulp-,再后面的名字是驼峰式 插件调用更加简单。 如:仅仅是去除了reauire('gulp-babel'), 使用的时候plugins.babel
const scripts = () => {
return src('src/assets/scripts/*.js', { base: 'src' })
.pipe(plugins.babel({ presets: ["@babel/preset-env"] }))
.pipe(dest('dist'))
}
添加开发服务器
安装插件,支持热更新,代码更新后唤醒浏览器
yarn add browser-sync -D
编写启动服务
const browserSync = require('browser-sync');
const bs = browserSync.create();//创建一个开发服务器
//...
// 创建启动服务
const serve = () => {
// 服务器配置
bs.init({
notify: false,//唤醒浏览器后右上角落的提示
// open: true,//是否自动打开
// port: 2000,//自定义端口, 默认3000
files: 'dist/**',//监听哪些文件发生了变化
server: {
baseDir: 'dist',//基础目录
}
})
}
好像还不错
监视变化及构建优化
监视变化:开发服务器只能监视dist下的代码变动,不能监视源代码的变动,所以需要加了监视任务,源代码变动了执行对应的构建任务,此时dist变动了开发服务器就能监视到了
gulp提供了watch方法监视源代码,watch两个参数,第一个监听的文件列表,第二个变化后执行的任务
const { src, dest, parallel, series, watch } = require('gulp')
//...
const serve = () => {
watch('src/assets/styles/*.scss', style)
watch('src/assets/scripts/*.js', scripts)
watch('src/**/*.html', pages)
watch('src/assets/images/**', images)
watch('src/assets/fonts/**', fonts)
// public一般不变动,这里不写了
// 服务器配置
bs.init({
notify: false,//唤醒浏览器后右上角落的提示
// open: true,//是否自动打开
// port: 2000,//自定义端口, 默认3000
files: 'dist/**',//监听哪些文件发生了变化
server: {
baseDir: 'dist',//基础目录
}
})
}
构建优化:主要是watch图片,字体,以及public等这些文件任务 如下:
const serve = () => {
watch('src/assets/styles/*.scss', style)
watch('src/assets/scripts/*.js', scripts)
watch('src/**/*.html', pages)
// watch('src/assets/images/**', images)
// watch('src/assets/fonts/**', fonts)
// public一般不变动,这里不写了
// 合并到一个监视任务,变动为刷新浏览器,不是执行构建任务,提高开发体验
watch(['src/assets/images/**', 'src/assets/fonts/**', 'public/**'], bs.reload)
// 服务器配置
bs.init({
notify: false,//唤醒浏览器后右上角落的提示
// open: true,//是否自动打开
// port: 2000,//自定义端口, 默认3000
files: 'dist/**',//监听哪些文件发生了变化
server: {
// baseDir: 'dist',//基础目录
baseDir: ['dist', 'src', 'public'],//dist下找到会到src, public下寻找
}
})
}
//执行命令修改
const compile = parallel(style, scripts, pages);
const build = series(clean, parallel(compile, extra, images, fonts));//生产前执行
const start = series(compile, serve);//开发环境,先编译再去启动服务
useref文件引用处理
当前dist下html文件,查看index.html文件
处理文件引用,插件gulp-useref
yarn add gulp-useref -D
编写任务
// 文件引用处理
const useref = () => {
return src('dist//**/*.html', { base: 'dist' })//此时创建html
.pipe(plugins.useref({ searchPath: ['dist', '.'] }))//两个地址, 使用更多的放在前面
.pipe(dest("release"));
}
防止读写冲突,换了release文件作为导出文件
执行这个命令,可以看到引用的css文件已经被处理
文件压缩
安装插件
yarn add gulp-htmlmin gulp-uglify gulp-clean-css -D
修改引用任务:修改前安装gulp-if插件【yarn add gulp-if -D】,判断使用
const useref = () => {
return src('dist/**/.html', { base: 'dist' })//此时创建html
.pipe(plugins.useref({ searchPath: ['dist', '.'] }))//两个地址, 使用更多的放在前面
// useref创建了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,//内联js压缩
})))
.pipe(dest("release"));
}
执行命令
优化构建命令与配置npm Scripts
整体代码:
// 实现这个项目的构建任务
const { src, dest, parallel, series, watch } = require('gulp')
const loadPlugins = require('gulp-load-plugins')
const plugins = loadPlugins()
const sass = require('gulp-sass')(require('sass'));
// const babel = require('gulp-babel')
// const swig = require('gulp-swig')
// const imagemin = require('gulp-imagemin');
const del = require('del')
const browserSync = require('browser-sync');
const bs = browserSync.create();//创建一个开发服务器
//style, scripts,page任务放在临时文件dist,防止读写冲突
const style = () => {
return src('src/assets/styles/*.scss', { base: 'src' })
.pipe(sass({ outputStyle: 'expanded' }))
.pipe(dest('dist'))
}
const scripts = () => {
return src('src/assets/scripts/*.js', { base: 'src' })
.pipe(plugins.babel({ presets: ["@babel/preset-env"] }))
.pipe(dest('dist'))
}
const pages = () => {
return src('src/**/*.html', { base: 'src' })
.pipe(plugins.swig())
.pipe(dest('dist'))
}
const images = () => {
return src('src/assets/images/**', { base: 'src' })
.pipe(plugins.imagemin())
.pipe(dest('release'))
}
const fonts = () => {
return src('src/assets/fonts/**', { base: 'src' })
.pipe(plugins.imagemin())
.pipe(dest('release'))
}
const extra = () => {
return src('public/**', { base: 'public' })
.pipe(dest('release'))
}
const clean = () => {
return del(['dist', 'release'])
}
// 文件引用处理
const useref = () => {
return src('dist/**/*.html', { base: 'dist' })//此时创建html
.pipe(plugins.useref({ searchPath: ['dist', '.'] }))//两个地址, 使用更多的放在前面
// useref创建了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,//内联js压缩
})))
.pipe(dest("release"));
}
// 创建启动服务
const serve = () => {
watch('src/assets/styles/*.scss', style)
watch('src/assets/scripts/*.js', scripts)
watch('src/**/*.html', pages)
// watch('src/assets/images/*', images)
// watch('src/assets/fonts/*', fonts)
// public一般不变动,这里不写了
// 合并到一个监视任务,变动为刷新浏览器,不是执行构建任务,提高开发体验
watch(['src/assets/images/**', 'src/assets/fonts/**', 'public/**'], bs.reload)
// 服务器配置
bs.init({
notify: false,//唤醒浏览器后右上角落的提示
// open: true,//是否自动打开
// port: 2000,//自定义端口, 默认3000
files: 'dist/**',//监听哪些文件发生了变化
server: {
// baseDir: 'dist',//基础目录
baseDir: ['dist', 'src', 'public'],//dist下找到会到src, public下寻找
routes: {
'/node_modules': 'node_modules'
}
}
})
}
//优化后命令compile, build, start
const compile = parallel(style, scripts, pages);
const build = series(
clean,
parallel(
series(
compile,
useref
),
extra,
images,
fonts
)
);//生产前执行
const start = series(compile, serve);//开发环境
module.exports = {
compile,
clean,
build,
start,
useref,
serve
}
package.json命令