手把手教你在小程序项目中配置Gulp

如果是做原生小程序开发,你是否想过在你的小程序项目中也加入一些工程的东西?本文将手把手教你在小程序中配置一些工程化的东西,基于我自身的痛点,目前有 支持Less支持路径别名图片自动压缩,上传七牛打包加入Eslint检查这么几个功能,后期有遇到其他需要再更新。

在小程序项目中我目前用的是Gulp。为啥不用热门的webpack?因为我觉得对于小程序项目来说gulp足够了,关键是配置非常简单,流式管理简单明了,不了解Gulp的大家可以去官网看看。

需要提醒的是,以下举例的gulpfie基于gulp 4.0,配置上与之前的版本略有不同,不过变化不大。详细的大家可以点这里去看看。

项目结构

项目结构

gulpfile.js 我们放在根目录下,初始长这样

  1. const { src, dest, parallel, watch, series } = require('gulp');
  2. function defaultTask(cb) {
  3. // place code for your default task here
  4. cb();
  5. }
  6. exports.default = defaultTask

接下来我们将一个任务一个任务往里面添加。

支持Less

由于平时项目中习惯了用CSS 预处理语言,wxss的原始css 写法让我写起项目来很难受。我个人比较习惯使用Less,习惯使用sass的大家自己找一下相关插件替换一下就行。gulp中处理less的插件是gulp-less,gulp-less把文件处理完成后我们还需要把文件名改成.wxss所以我们还需要一个重命名插件,这里用的是gulp-rename

gulpfile.js如下:

  1. const { src, dest, parallel, watch, series } = require('gulp');
  2. const Path = require('path');
  3. const Less = require('gulp-less');
  4. const Rename = require('gulp-rename');
  5. const path = {
  6. lessPath: ['src/**/*.less'],
  7. };
  8. function wxss() {
  9. return src(path.lessPath, { base: 'src/' })
  10. .pipe(Less())
  11. .pipe(Rename({
  12. extname: '.wxss',
  13. }))
  14. .pipe(dest('dist'));
  15. }
  16. exports.default = series(wxss);

需要注意的是上面的 src() 在第二个参数传入了 {base: 'src/'},至于原因嘛,跟我们配的匹配less文件路径 src/**/*.less有关。感兴趣的同学可以结合 Explaining Globs看看,这里我不细说。

当然如果你想对wxss进行压缩可以使用gulp-csso

  1. const { src, dest, parallel, watch, series } = require('gulp');
  2. const Path = require('path');
  3. const Less = require('gulp-less');
  4. const Rename = require('gulp-rename');
  5. const Csso = require('gulp-csso');
  6. const GulpIf = require('gulp-if');
  7. const path = {
  8. lessPath: ['src/**/*.less'],
  9. };
  10. function wxss() {
  11. return src(path.lessPath, { base: 'src/' })
  12. .pipe(Less())
  13. .pipe(GulpIf(process.env.NODE_ENV === 'production', Csso()))
  14. .pipe(Rename({
  15. extname: '.wxss',
  16. }))
  17. .pipe(dest('dist'));
  18. }
  19. exports.default = series(wxss);

支持路径别名

在项目中,如果应用文件路径过深过长,不仅开发者写起来费劲,还容易出错且代码观赏性很差。小程序中路径别名我们用gulp-wechat-weapp-src-alisa,支持在 .wxml.wxss/less.js 中使用。

  1. const { src, dest, parallel, watch, series } = require('gulp');
  2. const Path = require('path');
  3. const Less = require('gulp-less');
  4. const Rename = require('gulp-rename');
  5. const Csso = require('gulp-csso');
  6. const GulpIf = require('gulp-if');
  7. const Alias = require('gulp-wechat-weapp-src-alisa');
  8. // 匹配文件路径
  9. const path = {
  10. lessPath: ['src/**/*.less'],
  11. jsPath: ['src/**/*.js'],
  12. copy: ['src/**/*.wxml', 'src/**/*.json', 'src/**/*.wxs'],
  13. };
  14. // 路径拼接
  15. function _join(dirname) {
  16. return Path.join(process.cwd(), 'src', dirname);
  17. }
  18. // 引用路径别名配置
  19. const aliasConfig = {
  20. '@Libs': _join('libs'),
  21. '@Utils': _join('utils'),
  22. '@Components': _join('components'),
  23. '@Style': _join('style'),
  24. '@Images': _join('images'),
  25. };
  26. function wxss() {
  27. return src(path.lessPath, { base: 'src/' })
  28. .pipe(Alias(aliasConfig))
  29. .pipe(Less())
  30. .pipe(GulpIf(process.env.NODE_ENV === 'production', Csso()))
  31. .pipe(Rename({
  32. extname: '.wxss',
  33. }))
  34. .pipe(dest('dist'));
  35. }
  36. function js() {
  37. return src(path.jsPath)
  38. .pipe(Alias(aliasConfig))
  39. .pipe(dest('dist'));
  40. }
  41. // 针对wxs,wxml,json文件直接复制
  42. function copy() {
  43. return src(path.copy)
  44. .pipe(Alias(aliasConfig))
  45. .pipe(dest('dist'));
  46. }
  47. exports.default = series(wxss js);

使用效果

.js
  1. import * as Utils from '@Utils/base';
  2. // require('@Libs/WXPage/index');
  3. // 编译后
  4. import * as Utils from '../../utils/base';
  5. // require('libs/WXPage/index');
.less
  1. // index.less
  2. @import '@Style/variables.less';
  3. .bg {
  4. background-image: url('@Images/32821027.jpgg');
  5. }
  6. .usermotto {
  7. margin-top: 200px;
  8. color: @txt-highlight;
  9. }
  10. // 编译后
  11. .bg {
  12. background-image: url('../../images/32821027.jpg');
  13. }
  14. .usermotto {
  15. margin-top: 200px;
  16. color: #FD7622;
  17. }
.wxml
  1. <!--logs.wxml-->
  2. <import src="@Utils/index.wxs" />
  3. <image src="@Images/32821027.jpg" mode="cover"></image>
  4. // 编译后
  5. <import src="../../utils/index.wxs" />
  6. <image src="../../images/32821027.jpg" mode="cover"></image>

图片自动压缩,上传七牛

由于小程序对代码包有限制,每1KB空间对小程序项目都十分珍贵,而且从用户体验来说,过大的代码包对首次进入小程序的用户来说下载时间会过长。基于这些原因我们几乎不会选择把图片放在小程序代码包中,那就只能上传图片服务器了。

上传图片之前需要对图片进行压缩,可能有些通许是通过手动来做这部分工作的,其实可以用工具来的嘛。压缩图片用的插件是gulp-imagemin, 我的图片是上传到七牛,对应的插件是gulp-qiniu-utils

接下来我们在gulpfile中添加图片相关任务

  1. const { src, dest, parallel, watch, series } = require('gulp');
  2. const Path = require('path');
  3. const Less = require('gulp-less');
  4. const Rename = require('gulp-rename');
  5. const Csso = require('gulp-csso');
  6. const GulpIf = require('gulp-if');
  7. const Alias = require('gulp-wechat-weapp-src-alisa');
  8. const ImageMin = require('gulp-imagemin');
  9. const UrlPrefixer = require('gulp-url-prefixer');
  10. const Qiniu = require('gulp-qiniu-utils');
  11. // 匹配文件路径
  12. const path = {
  13. lessPath: ['src/**/*.less'],
  14. jsPath: ['src/**/*.js'],
  15. copy: ['src/**/*.wxml', 'src/**/*.json', 'src/**/*.wxs'],
  16. };
  17. // 七牛相关配置
  18. const qiniuOptions = {
  19. ak: 'ac key',
  20. sk: 'sk key',
  21. zone: 'Zone_z0', // 空间对应存储区域(华东:z0,华北:z1,华南:z2,北美:na0)
  22. bucket: 'hynal-com', // 七牛对应空间
  23. upload: {
  24. dir: './dist/images', // 上传本地目录
  25. // prefix: 'test/', // 上传时添加的前缀,可省略
  26. except: /\.(html|js)$/, // 上传时不上传文件的正则匹配
  27. },
  28. remote: {
  29. url: 'https://*****.com', // 七牛空间域名
  30. prefix: {
  31. default: 'test/', // 七牛空间默认前缀,如果下面三个相同可省略
  32. remove: 'test/', // 七牛空间删除前缀
  33. prefetch: 'test/', // 七牛空间预取前缀
  34. refresh: 'test/', // 七牛空间刷新前缀
  35. },
  36. },
  37. };
  38. const urlPrefix = {
  39. prefix: 'https://cdn.liayal.com/dist',
  40. tags: ['image'],
  41. };
  42. // 路径拼接
  43. function _join(dirname) {
  44. return Path.join(process.cwd(), 'src', dirname);
  45. }
  46. // 引用路径别名配置
  47. const aliasConfig = {
  48. '@Libs': _join('libs'),
  49. '@Utils': _join('utils'),
  50. '@Components': _join('components'),
  51. '@Style': _join('style'),
  52. '@Images': _join('images'),
  53. };
  54. function wxss() {
  55. return src(path.lessPath, { base: 'src/' })
  56. .pipe(Alias(aliasConfig))
  57. .pipe(Less())
  58. .pipe(UrlPrefixer.css(urlPrefix))
  59. .pipe(GulpIf(process.env.NODE_ENV === 'production', Csso()))
  60. .pipe(Rename({
  61. extname: '.wxss',
  62. }))
  63. .pipe(dest('dist'));
  64. }
  65. function js() {
  66. return src(path.jsPath)
  67. .pipe(Alias(aliasConfig))
  68. .pipe(dest('dist'));
  69. }
  70. function imagemin() {
  71. return src(path.images)
  72. .pipe(ImageMin())
  73. .pipe(dest('dist/images'));
  74. }
  75. const images = series(imagemin, (cb) => {
  76. const qiniu = new Qiniu(qiniuOptions);
  77. qiniu.upload();
  78. cb();
  79. });
  80. // 针对wxs,wxml,json文件直接复制
  81. function copy() {
  82. return src(path.copy)
  83. .pipe(Alias(aliasConfig))
  84. .pipe(UrlPrefixer.html(urlPrefix))
  85. .pipe(dest('dist'));
  86. }
  87. exports.default = series(wxss js images);

上面我们还添加了一个 UrlPrefixer() 流,这个是把我们项目中引用的图片替换成上传七牛后的地址,需要配合七牛对应配置来设定。
如:

  1. // 替换前
  2. <image src="@Images/32821027.jpg" mode="cover"></image>
  3. // 替换后
  4. <image src="https://cdn.liayal.com/dist/images/32821027.jpg" mode="cover"></image>

打包加入Eslint检查

打包时加入Eslint检查可以让我们提早发现一些由代码引发问题,也方便推行代码规范。

下面我们在js任务中加入gulp-eslint

  1. const { src, dest, parallel, watch, series } = require('gulp');
  2. const Path = require('path');
  3. const Less = require('gulp-less');
  4. const Rename = require('gulp-rename');
  5. const Csso = require('gulp-csso');
  6. const GulpIf = require('gulp-if');
  7. const Alias = require('gulp-wechat-weapp-src-alisa');
  8. const ImageMin = require('gulp-imagemin');
  9. const UrlPrefixer = require('gulp-url-prefixer');
  10. const Qiniu = require('gulp-qiniu-utils');
  11. const ESLint = require('gulp-eslint');
  12. // 匹配文件路径
  13. const path = {
  14. lessPath: ['src/**/*.less'],
  15. jsPath: ['src/**/*.js'],
  16. copy: ['src/**/*.wxml', 'src/**/*.json', 'src/**/*.wxs'],
  17. };
  18. // 七牛相关配置
  19. const qiniuOptions = {
  20. ak: 'ac key',
  21. sk: 'sk key',
  22. zone: 'Zone_z0', // 空间对应存储区域(华东:z0,华北:z1,华南:z2,北美:na0)
  23. bucket: 'hynal-com', // 七牛对应空间
  24. upload: {
  25. dir: './dist/images', // 上传本地目录
  26. // prefix: 'test/', // 上传时添加的前缀,可省略
  27. except: /\.(html|js)$/, // 上传时不上传文件的正则匹配
  28. },
  29. remote: {
  30. url: 'https://*****.com', // 七牛空间域名
  31. prefix: {
  32. default: 'test/', // 七牛空间默认前缀,如果下面三个相同可省略
  33. remove: 'test/', // 七牛空间删除前缀
  34. prefetch: 'test/', // 七牛空间预取前缀
  35. refresh: 'test/', // 七牛空间刷新前缀
  36. },
  37. },
  38. };
  39. const urlPrefix = {
  40. prefix: 'https://cdn.liayal.com/dist',
  41. tags: ['image'],
  42. };
  43. // 路径拼接
  44. function _join(dirname) {
  45. return Path.join(process.cwd(), 'src', dirname);
  46. }
  47. // 引用路径别名配置
  48. const aliasConfig = {
  49. '@Libs': _join('libs'),
  50. '@Utils': _join('utils'),
  51. '@Components': _join('components'),
  52. '@Style': _join('style'),
  53. '@Images': _join('images'),
  54. };
  55. function wxss() {
  56. return src(path.lessPath, { base: 'src/' })
  57. .pipe(Alias(aliasConfig))
  58. .pipe(Less())
  59. .pipe(UrlPrefixer.css(urlPrefix))
  60. .pipe(GulpIf(process.env.NODE_ENV === 'production', Csso()))
  61. .pipe(Rename({
  62. extname: '.wxss',
  63. }))
  64. .pipe(dest('dist'));
  65. }
  66. function js() {
  67. return src(path.jsPath)
  68. .pipe(Alias(aliasConfig))
  69. .pipe(ESLint())
  70. .pipe(ESLint.format())
  71. .pipe(dest('dist'));
  72. }
  73. function imagemin() {
  74. return src(path.images)
  75. .pipe(ImageMin())
  76. .pipe(dest('dist/images'));
  77. }
  78. const images = series(imagemin, (cb) => {
  79. const qiniu = new Qiniu(qiniuOptions);
  80. qiniu.upload();
  81. cb();
  82. });
  83. // 针对wxs,wxml,json文件直接复制
  84. function copy() {
  85. return src(path.copy)
  86. .pipe(Alias(aliasConfig))
  87. .pipe(UrlPrefixer.html(urlPrefix))
  88. .pipe(dest('dist'));
  89. }
  90. exports.default = series(wxss js images);

效果大概是这样的

也可以通过eslint.failOnError()或者eslint.failAfterError()在编译报错时中断编译。

END

最后完善一下gulpfile, 添加监测任务,添加一个clean任务

  1. const { src, dest, parallel, watch, series } = require('gulp');
  2. const Path = require('path');
  3. const Less = require('gulp-less');
  4. const Rename = require('gulp-rename');
  5. const Csso = require('gulp-csso');
  6. const GulpIf = require('gulp-if');
  7. const Alias = require('gulp-wechat-weapp-src-alisa');
  8. const ImageMin = require('gulp-imagemin');
  9. const UrlPrefixer = require('gulp-url-prefixer');
  10. const Qiniu = require('gulp-qiniu-utils');
  11. const ESLint = require('gulp-eslint');
  12. const Clean = require('gulp-clean');
  13. // 匹配文件路径
  14. const path = {
  15. lessPath: ['src/**/*.less'],
  16. jsPath: ['src/**/*.js'],
  17. copy: ['src/**/*.wxml', 'src/**/*.json', 'src/**/*.wxs'],
  18. };
  19. // 七牛相关配置
  20. const qiniuOptions = {
  21. ak: 'ac key',
  22. sk: 'sk key',
  23. zone: 'Zone_z0', // 空间对应存储区域(华东:z0,华北:z1,华南:z2,北美:na0)
  24. bucket: 'hynal-com', // 七牛对应空间
  25. upload: {
  26. dir: './dist/images', // 上传本地目录
  27. // prefix: 'test/', // 上传时添加的前缀,可省略
  28. except: /\.(html|js)$/, // 上传时不上传文件的正则匹配
  29. },
  30. remote: {
  31. url: 'https://*****.com', // 七牛空间域名
  32. prefix: {
  33. default: 'test/', // 七牛空间默认前缀,如果下面三个相同可省略
  34. remove: 'test/', // 七牛空间删除前缀
  35. prefetch: 'test/', // 七牛空间预取前缀
  36. refresh: 'test/', // 七牛空间刷新前缀
  37. },
  38. },
  39. };
  40. const urlPrefix = {
  41. prefix: 'https://cdn.liayal.com/dist',
  42. tags: ['image'],
  43. };
  44. // 路径拼接
  45. function _join(dirname) {
  46. return Path.join(process.cwd(), 'src', dirname);
  47. }
  48. // 引用路径别名配置
  49. const aliasConfig = {
  50. '@Libs': _join('libs'),
  51. '@Utils': _join('utils'),
  52. '@Components': _join('components'),
  53. '@Style': _join('style'),
  54. '@Images': _join('images'),
  55. };
  56. function wxss() {
  57. return src(path.lessPath, { base: 'src/' })
  58. .pipe(Alias(aliasConfig))
  59. .pipe(Less())
  60. .pipe(UrlPrefixer.css(urlPrefix))
  61. .pipe(GulpIf(process.env.NODE_ENV === 'production', Csso()))
  62. .pipe(Rename({
  63. extname: '.wxss',
  64. }))
  65. .pipe(dest('dist'));
  66. }
  67. function js() {
  68. return src(path.jsPath)
  69. .pipe(Alias(aliasConfig))
  70. .pipe(ESLint())
  71. .pipe(ESLint.format())
  72. .pipe(dest('dist'));
  73. }
  74. function imagemin() {
  75. return src(path.images)
  76. .pipe(ImageMin())
  77. .pipe(dest('dist/images'));
  78. }
  79. const images = series(imagemin, (cb) => {
  80. const qiniu = new Qiniu(qiniuOptions);
  81. qiniu.upload();
  82. cb();
  83. });
  84. // 针对wxs,wxml,json文件直接复制
  85. function copy() {
  86. return src(path.copy)
  87. .pipe(Alias(aliasConfig))
  88. .pipe(UrlPrefixer.html(urlPrefix))
  89. .pipe(dest('dist'));
  90. }
  91. function clean() {
  92. return src('dist/*', { read: false })
  93. .pipe(Clean());
  94. }
  95. watch(path.lessPath, wxss);
  96. watch(path.jsPath, js);
  97. watch(path.copy, copy);
  98. watch(path.images, images);
  99. exports.default = series(clean, parallel(copy, wxss, js, images));

整个项目我放在github :point_right: gulp-wechat-weapp

写于 2019年02月19日小程序 Gulp 5667

如非特别注明,文章皆为原创。

转载请注明出处: https://www.liayal.com/article/5c6b76a6c0ab13505eeefaaf

记小栈小程序上线啦~搜索【记小栈】【点击扫码】体验

你不想说点啥么?
😀😃😄😁😆😅😂🤣☺️😊😇🙂🙃😉😌😍😘😗😙😚😋😜😝😛🤑🤗🤓😎🤡🤠😏😒😞😔😟😕🙁☹️😣😖😫😩😤😠😡😶😐😑😯😦😧😮😲😵😳😱😨😰😢😥🤤😭😓😪😴🙄🤔🤥😬🤐🤢🤧😷🤒🤕😈👿👹👺💩👻💀☠️👽👾🤖🎃😺😸😹😻😼😽🙀😿😾👐👐🏻👐🏼👐🏽👐🏾👐🏿🙌🙌🏻🙌🏼🙌🏽🙌🏾🙌🏿👏👏🏻👏🏼👏🏽👏🏾👏🏿🙏🙏🏻🙏🏼🙏🏽🙏🏾🙏🏿🤝👍👍🏻👍🏼👍🏽👍🏾👍🏿👎👎🏻👎🏼👎🏽👎🏾👎🏿👊👊🏻👊🏼👊🏽👊🏾👊🏿✊🏻✊🏼✊🏽✊🏾✊🏿

评论

~ 评论还没有,沙发可以有 O(∩_∩)O~