400-028-6601
建站资讯

网站建设资讯

为你提供网站建设行业资讯、网站优化知识、主机域名邮箱、网站开发常见问题等。

前端工程师:我用gulp4.0搭建一个前端脚手架

本文将会介绍如何使用gulp4来搭建项目脚手架,如果您还在使用gulp3或更老的版本,您也以通过本文的一些思想将之前的项目进行完善,更新。如果gulp不是你们团队的重点,也可以移步我的Webpack4.0搭建文章.

专业网站制作公司,专做排名好的好网站,排在同行前面,为您带来客户和效益!成都创新互联公司为您提供品质好成都网站建设,五站合一网站设计制作,服务好的网站设计公司,负责任的成都网站制作公司!

前言

由于本文重点是介绍gulp4.0搭建脚手架的思路,相关插件的用法以及项目结构的设计,由于gulp的基本用法很简单,如果不熟悉可以移步官网自行研究学习。该脚手架的设计思路和功能如下:

 

同时为了提高开发环境的效率,这里我们参考webpack的配置,区分开发环境和生产环境,在接下来将会具体介绍。

脚手架用到的第三方插件介绍

  • gulp-jshint ——js语法检测
  • gulp-util ——终端控制台打印自定义错误信息
  • http-proxy-middleware ——设置代理,配合gulp-connect使用
  • gulp-less ——将less编译成css
  • gulp-file-include ——用于文件模块化导入,如用include的方式导入公共部分
  • gulp-connect ——用于启动本地服务器
  • gulp-clean ——清理目录
  • gulp-uglify --压缩js
  • gulp-minify-css ——压缩css
  • gulp-autoprefixer ——自动添加浏览器前缀
  • imagemin-pngquant ——png图片压缩
  • gulp-imagemin ——图压缩
  • gulp-cache ——设置gulp打包的缓存,一般用于img
  • gulp-md5-plus ——将文件名进行md5处理便于打包更新

当然gulp还有很多常用的插件可以更好的为我们的项目服务,大家也可以整合自己的插件让项目更加完善。

项目目录设计

1.src目录,即我们开发项目时的源目录,具体结构如下:

我们定义views是我们视图层,即页面文件的目录,js目录为业务逻辑的脚本文件,lib存放第三方框架,include目录为公共部分的存放目录,我们可以用gulp-file-include来导入到html中,images和css大家都比较清楚,分别时存放image和css文件的目录。

2. dist目录,即输出的目录,具体结构如下:

可以看到我们会看到src打包后的目录对应static目录,为什么我们会加一层static呢?我的设计是如果项目使用node等服务层框架,我们可以用gulp一并打包放入dist下,这样dist就是一个完整的包括前后端服务的项目目录了,当然大家也可以直接将src打包后的文件和文件夹直接放到dist下,根具业务需求灵活设计吧。

在这里我要说一点,由于笔者亲测gulp-md5-plus有时候打包不稳定,可能不会给html自动添加对应的md5后缀,所以笔者在这块做了特殊的处理,如果大家在工作中有更好的方案,可以及时和笔者沟通交流。

3. gulpfile文件配置

由于我们要区分开发环境和生产环境,所以这里我们使用两个不同的配置文件,根据NODE_ENV来区分用哪个文件。

我们将配置文件统一放到build目录下,config为公共配置文件,gulp.dev.js和gulp.prod.js分别为开发和生产环境配置文件。我们整体的目录结构如下:

脚手架完整源码(部分插件和配置会给出详细注释)

1 config.js

 
 
 
 
  1. module.exports = { 
  2.     dist: './dist/static',  // 配置构建目录 
  3. } 

2 gulp.dev.js

 
 
 
 
  1. const gulp = require('gulp'); 
  2. // js 
  3. const Jshint = require("gulp-jshint");          //js检查 
  4. const Gutil = require('gulp-util'); 
  5. const Proxy = require('http-proxy-middleware'); 
  6. // const Webpack = require('webpack'); 
  7. // const WebpackConfig = require('./webpack.config.js'); 
  8.  
  9. // css 
  10. const Less = require('gulp-less');              // 编译less 
  11.  
  12. // html 
  13. const FileInclude = require('gulp-file-include'); // 文件模块化 
  14.  
  15. // server 
  16. const Connect = require('gulp-connect');        //引入gulp-connect模块  
  17.  
  18. const Clean = require('gulp-clean');            // 清理目录 
  19.  
  20. // 配置文件 
  21. const config = require('./config'); 
  22. const { dist } = config; 
  23.  
  24. // html 
  25. async function html() { 
  26.     return gulp.src('src/views/*.html') 
  27.         .pipe(FileInclude({ // HTML模板替换,具体用法见下文 
  28.             prefix: '##', 
  29.             basepath: '@file' 
  30.         })).on('error', function(err) { 
  31.             console.error('Task:copy-html,', err.message); 
  32.             this.end(); 
  33.         }) 
  34.         .pipe(gulp.dest(dist)) // 拷贝  
  35.         .pipe(Connect.reload()) 
  36. } 
  37.  
  38. // css 
  39. async function css() { 
  40.     return await gulp.src('src/css/*.less') 
  41.     .pipe(Less())       //编译less 
  42.     .pipe(gulp.dest(dist + '/css')) //当前对应css文件 
  43.     .pipe(Connect.reload());//更新 
  44. } 
  45.  
  46. // js 
  47. // const compilerJS = Webpack(WebpackConfig); 
  48.  
  49. async function js() { 
  50.     return await gulp.src('src/js/**') 
  51.     .pipe(Jshint())//检查代码 
  52.     // .pipe(Babel({ 
  53.     //     presets: ['es2015'] 
  54.     // })) 
  55.     .on('error', function(err) { 
  56.         Gutil.log(Gutil.colors.red('[Error]'), err.toString()); 
  57.     }) 
  58.     .pipe(gulp.dest(dist + '/js')) // 拷贝 
  59.     .pipe(Connect.reload()); //更新 
  60.      
  61.     // 使用es6+可以单独配置 
  62.     // compilerJS.run(function(err, stats) { 
  63.     //     if(err) throw new Gutil.PluginError("webpack:js", err); 
  64.     //     Gutil.log("[webpack]", stats.toString({ 
  65.     //         colors: true 
  66.     //     })); 
  67.     //     cb() 
  68.     // }); 
  69. } 
  70.  
  71. // image 
  72. async function image() { 
  73.     return await gulp.src('src/images/*') 
  74.     .pipe(gulp.dest(dist + '/images')); 
  75. } 
  76.  
  77. // clean dir 
  78. async function clean() { 
  79.     // 不设置allowEmpty: true会报File not found with singular glob 
  80.     return await gulp.src(dist, {allowEmpty: true}).pipe(Clean()); 
  81. } 
  82.  
  83. // 服务器函数 
  84. async function server() { 
  85.     Connect.server({ 
  86.         root:dist, //根目录 
  87.         // ip:'192.168.11.62',//默认localhost:8080 
  88.         livereload:true, //自动更新 
  89.         port:9909, //端口 
  90.         middleware: function(connect, opt) { 
  91.             return [ 
  92.                 Proxy('/api', { 
  93.                     target: 'http://localhost:8080', 
  94.                     changeOrigin:true 
  95.                 }), 
  96.                 Proxy('/otherServer', { 
  97.                     target: 'http://IP:Port', 
  98.                     changeOrigin:true 
  99.                 }) 
  100.             ] 
  101.         } 
  102.     }) 
  103. } 
  104.  
  105. module.exports = { 
  106.     html, 
  107.     css, 
  108.     js, 
  109.     image, 
  110.     clean, 
  111.     server 
  112. } 

3 gulp.prod.js

 
 
 
 
  1. const gulp = require('gulp'); 
  2. // const Rename = require('gulp-rename');          // 重命名 
  3. // js 
  4. const Uglify = require('gulp-uglify');          // 压缩js 
  5. // const Babel = require('gulp-babel'); 
  6. // css 
  7. const Minifycss = require('gulp-minify-css');   // 压缩css 
  8. const Less = require('gulp-less');              // 编译less 
  9. const Autoprefixer = require('gulp-autoprefixer');  // 浏览器前缀 
  10. // html 
  11. const MinifyHtml = require("gulp-minify-html"); //压缩html 
  12. const FileInclude = require('gulp-file-include'); // 文件模块化 
  13. // image 
  14. const Imagemin = require('gulp-imagemin'); 
  15. const Pngquant = require('imagemin-pngquant');  //png图片压缩插件 
  16. const Cache = require('gulp-cache');  
  17.  
  18. const Clean = require('gulp-clean');            // 清理目录 
  19.  
  20. // md5 发版本的时候为了避免浏览器读取了旧的缓存文件,需要为其添加md5戳 
  21. const md5 = require("gulp-md5-plus"); 
  22.  
  23. const config = require('./config'); 
  24. const { dist } = config; 
  25. // html 
  26. async function html() { 
  27.     return gulp.src('src/views/*.html') 
  28.         .pipe(FileInclude({ // HTML模板替换,具体用法见下文 
  29.             prefix: '##', 
  30.             basepath: '@file' 
  31.         })) 
  32.         // .pipe(MinifyHtml()) 
  33.         .on('error', function(err) { 
  34.             console.error('Task:copy-html,', err.message); 
  35.             this.end(); 
  36.         }) 
  37.         .pipe(gulp.dest(dist)) // 拷贝  
  38. } 
  39.  
  40. // css 
  41. async function css() { 
  42.     return await gulp.src('src/css/**') 
  43.     .pipe(Less())       //编译less 
  44.     .pipe(Autoprefixer({ 
  45.         cascade: true, //是否美化属性值 默认:true 像这样: 
  46.         //-webkit-transform: rotate(45deg); 
  47.         //        transform: rotate(45deg); 
  48.         remove: true //是否去掉不必要的前缀 默认:true 
  49.     })) 
  50.     .pipe(Minifycss({   // 压缩css 
  51.         //类型:Boolean 默认:true [是否开启高级优化(合并选择器等)] 
  52.         advanced: true, 
  53.         //保留ie7及以下兼容写法 类型:String 默认:''or'*' [启用兼容模式; 'ie7':IE7兼容模式,'ie8':IE8兼容模式,'*':IE9+兼容模式] 
  54.         compatibility: '', 
  55.         //类型:Boolean 默认:false [是否保留换行] 
  56.         keepBreaks: false, 
  57.         //保留所有特殊前缀 当你用autoprefixer生成的浏览器前缀,如果不加这个参数,有可能将会删除你的部分前缀         
  58.         keepSpecialComments: '*' 
  59.     })) 
  60.     .pipe(gulp.dest(dist + '/css')) 
  61.     .pipe(md5(10, dist + '/*.html', { 
  62.         mappingFile: 'manifest.json', 
  63.         connector: '.' // 文件名和hash的连接符 
  64.     })) 
  65.     .pipe(gulp.dest(dist + '/css')) //当前对应css文件 
  66. } 
  67.  
  68. // js 
  69. async function js() { 
  70.     return await gulp.src('src/js/**') 
  71.     // .pipe(Babel({ 
  72.     //     presets: ['es2015'] 
  73.     // })) 
  74.     .pipe(Uglify()) // 压缩js 
  75.     .pipe(gulp.dest(dist + '/js')) 
  76.     .pipe(md5(10, dist + '/*.html', { 
  77.         mappingFile: 'manifest.json', 
  78.         connector: '.' 
  79.     })) 
  80.     .pipe(gulp.dest(dist + '/js')) // 拷贝 
  81. } 
  82.  
  83. // image 
  84. async function image() { 
  85.     return await gulp.src('src/images/*') 
  86.     .pipe(Cache(Imagemin({ 
  87.         optimizationLevel: 5, //类型:Number  默认:3  取值范围:0-7(优化等级) 
  88.         progressive: true, //类型:Boolean 默认:false 无损压缩jpg图片 
  89.         interlaced: true, //类型:Boolean 默认:false 隔行扫描gif进行渲染 
  90.         multipass: true, //类型:Boolean 默认:false 多次优化svg直到完全优化 
  91.         svgoPlugins: [{removeViewBox: false}],//不要移除svg的viewbox属性 
  92.         use: [Pngquant()] //使用pngquant深度压缩png图片的imagemin插件 
  93.     }))) 
  94.     .pipe(gulp.dest(dist + '/images')); 
  95. } 
  96.  
  97.  
  98. // clean dir 
  99. async function clean() { 
  100.     // 不设置allowEmpty: true会报File not found with singular glob 
  101.     return await gulp.src(dist, {allowEmpty: true}).pipe(Clean()); 
  102. } 
  103.  
  104.  
  105.  
  106. module.exports = { 
  107.     html, 
  108.     css, 
  109.     js, 
  110.     image, 
  111.     clean 
  112. } 

4 gulpfile.js

 
 
 
 
  1. const gulp = require('gulp'); 
  2.  
  3. // 根据环境引入不同的配置文件 
  4. let buildConfig; 
  5. if(process.env.NODE_ENV === 'dev') { 
  6.     buildConfig = require('./build/gulp.dev'); 
  7.     gulp.task('server', buildConfig.server);  // 本地服务 
  8.      
  9. } else { 
  10.     buildConfig = require('./build/gulp.prod'); 
  11.     // gulp.task('md5', gulp.series(buildConfig.md5Css, buildConfig.md5Js)); 
  12.     gulp.task('clean', buildConfig.clean);    // 清理目录    
  13. } 
  14.  
  15. gulp.task('html', buildConfig.html);      // 打包html 
  16. gulp.task('js', buildConfig.js);          // 打包js 
  17. gulp.task('css', buildConfig.css);        // 打包css 
  18. gulp.task('images', buildConfig.image);   // 打包image 
  19. gulp.task('sources', gulp.series('html', gulp.parallel('js', 'css', 'images'))); 
  20.  
  21.  
  22. // 监听文件变化 
  23. gulp.task('watch', async () => { 
  24.     gulp.watch('src/views/*', gulp.series('html')); // 监听HTML变化 
  25.     gulp.watch('src/js/**', gulp.series('js')); // 监听js变化 
  26.     gulp.watch('src/css/*', gulp.series('css')); // 监听css变化 
  27.     gulp.watch('src/images/*', gulp.series('images')); // 监听image变化 
  28. }); 
  29.  
  30. // build 
  31. if(process.env.NODE_ENV === 'dev') { 
  32.     gulp.task('dev', gulp.series('sources', 'server', 'watch')); 
  33. } else { 
  34.     gulp.task('build', gulp.series('sources')); 
  35. } 

5 package.json

 
 
 
 
  1. { 
  2.   "dependencies": { 
  3.     "@babel/core": "^7.4.5", 
  4.     "babel-preset-es2015": "^6.24.1", 
  5.     "gulp": "^4.0.2", 
  6.     "gulp-autoprefixer": "^6.1.0", 
  7.     "gulp-babel": "^8.0.0", 
  8.     "gulp-cache": "^1.1.2", 
  9.     "gulp-clean": "^0.4.0", 
  10.     "gulp-connect": "^5.7.0", 
  11.     "gulp-file-include": "^2.0.1", 
  12.     "gulp-imagemin": "^6.0.0", 
  13.     "gulp-jshint": "^2.1.0", 
  14.     "gulp-less": "^4.0.1", 
  15.     "gulp-md5-plus": "^1.0.3", 
  16.     "gulp-minify-css": "^1.2.4", 
  17.     "gulp-minify-html": "^1.0.6", 
  18.     "gulp-rename": "^1.4.0", 
  19.     "gulp-uglify": "^3.0.2", 
  20.     "gulp-util": "^3.0.8", 
  21.     "http-proxy-middleware": "^0.19.1", 
  22.     "http-server": "^0.11.1", 
  23.     "imagemin-pngquant": "^8.0.0", 
  24.     "jshint": "^2.10.2", 
  25.     "jsonfile": "^5.0.0", 
  26.     "webpack": "^4.35.2" 
  27.   }, 
  28.   "scripts": { 
  29.     "start": "NODE_ENV=dev gulp dev", 
  30.     "build": "NODE_ENV=prod gulp clean && gulp build", 
  31.     "serve": "http-server dist/static -p 3000" 
  32.   }, 
  33.   "devDependencies": {} 
  34. } 

要想获取项目完整源码和demo,请移步gulp4_multi_pages。

最后 

该脚手架任然有需要完善的地方,比如如何兼容uglify和babel,md5需要使用两次的情况,如果更好的解决方案,欢迎随时交流。在脚手架选型上,也不一定非要用gulp,webpack,一般的经验是传统型的静态网站适合用gulp,由于不需要编译es6,所以有更小的体积,当然也可以用webpack,本文主要是给大家提供一使用gulp4搭建个脚手架的思路,希望能有所收获。


网站标题:前端工程师:我用gulp4.0搭建一个前端脚手架
文章URL:http://www.hnjierui.cn/article/cceipcg.html

其他资讯