使用gulp构建微信小程序开发工作流

3,538 阅读4分钟

本篇文章主要阐述了如何使用gulp来构建微信小程序原生开发的工作流。

前言

web开发基本上都是基于webpack或者其他的构建工具来进行开发,大大节约了开发者的时间。目前的微信小程序开发也有很多开源的框架可供选择,但是如果使用原生开发模式,虽然可以完美使用小程序原生的新特性和功能,但是工作流角度上却十分简陋。

19年末的时候公司要开发一个新的小程序,组里面的大佬同事提议使用gulp来构建下原生开发模式的工作流。一是为了摆脱简陋的工作流模式以节约开发时间,二是也是把技术用到刀刃上。在大佬的指导开发下,这个工作便进行了。总体来说这个工作并不难,增益可能也没有那么大,但是还是收获了很多。

项目地址:gulp-mp

工作流改进

我们把开发目录设置在src,输出目录设置在dist,定义开发与输出路径。

文件复制

微信小程序的page目录通常包含wxml,json,wxssjs文件,与原生开发模式不同的是我们使用sass预处理器来写样式,其他的文件保持原样不同。因此,对于wxml,json,js文件来说,仅仅需要copy就行。因为在项目中已经配置了eslint+prettier来进行语法检查和代码美化,因此不需要在工作流的js代码进行规范检查。如果没有配置,可以安装gulp-eslint执行eslint规范检查。

const srcPath = "./src/**";
const distPath = "./dist/";
const wxmlFiles = [`${srcPath}/*.wxml`];
const jsFiles = [`${srcPath}/*.js`, `!${srcPath}/env/*.js`];
const jsonFiles = [`${srcPath}/*.json`];

// copy wxml
const wxml = () => {
  return gulp
    .src(wxmlFiles, { since: gulp.lastRun(wxml) })
    .pipe(gulp.dest(distPath));
};
gulp.task(wxml);

// 其他copy流类似
...

sass处理

上面我们提到使用sass预处理来编写样式,在输出的时候我们需要把scss样式转换成wxsswxss就是普通的css样式。这里,我们使用gulp-sass插件转换scss样式。但是,需要注意的是在scss文件中,我们可能会import相关样式,可能是公共样式也可能是varibale和minxin。

经过测试发现,当import公共样式,会把这个公共样式打包进当前页面。我们知道小程序的包是有大小限制的,如果在引入公共样式的时候还打包到当前页面,无疑是消耗掉了不必要的内存。所以,针对公共样式的import处理为,不交给sass处理,保留import并把后缀的.scss改成.wxss。

当import的是变量和mixin时,我们需要保留对其的sass处理,因此新建独立的目录存放以便识别。在这一场景下,变量和mixin的文件不再递归处理。

//存放variable和mixin的sass文件在被引用时直接导入,不引入dist目录中
const DIRECTIMPORT = ["/scss/", "/font/"];
const sassFiles = [`${srcPath}/*.{scss, wxss}`];

const wxss = () => {
  return gulp
    .src([...sassFiles, ...DIRECTIMPORT.map(item => `!${srcPath}/${item}/*`)], {
      since: gulp.lastRun(wxss)
    })
    .pipe(plumber({ errorHandler: onError }))
    .pipe(
      tap(file => {
        const filePath = path.dirname(file.path);
        //console.log("filepath", filePath);
        file.contents = new Buffer(
            // 匹配@import
          String(file.contents).replace(
            /@import\s+['|"](.+)['|"];/g,
            ($1, $2) => {
              console.log("$1", $1);
              console.log("$2", $2);
              //如果不是变量或者mixin则注释掉
              return DIRECTIMPORT.some(item => {
                return $2.indexOf(item) > -1;
              })
                ? $1
                : `/** ${$1} **/`;
            }
          )
        );
      })
    )
    .pipe(sass())
    .pipe(postcss([autoprefixer(["iOS >= 8", "Android >= 4.1"])]))
    .pipe(
      replace(/(\/\*\*\s{0,})(@.+)(\s{0,}\*\*\/)/g, ($1, $2, $3) => {
        //console.log("$1", $1);
        //console.log("$2", $2);
        //console.log("$3", $3);
        //去掉注释并修改scss后缀为wxss
        return $3.replace(/\.scss/g, ".wxss");
      })
    )
    .pipe(rename({ extname: ".wxss" }))
    .pipe(gulp.dest(distPath));
};
gulp.task(wxss);

压缩图片文件

安装gulp-imagemin插件压缩图片。之前通过npm安装在使用的时候这个插件总是报错,后来发现是没有正确安装,瞎倒腾切换到cnpm或者yarn发现可以安装成功了。

错误信息

const imageFiles = [
  `${srcPath}/images/*.{png,jpg,gif,ico}`,
  `${srcPath}/images/**/*.{png,jpg,gif,ico}`
];
const img = () => {
  return gulp
    .src(imageFiles, { since: gulp.lastRun(img) })
    .pipe(imagemin())
    .pipe(gulp.dest(distPath));
};
gulp.task(img);

区分开发环境

正常开发过程中,开发,测试和发布环境通常会有不同的API接口和其他设置。在每次切换的时候手动去更改内部代码是一件很麻烦的事情,也容易遗忘,根据不同的命令自动加载相应的开发环境设置才是我们想要的效果。 在src/env/*目录下,配置了三个环境的变量:dev.jstest.jsprod.js

const envJs = env => {
  return () => {
    return gulp
      .src(`./src/env/${env}.js`)
      .pipe(rename("env.js"))
      .pipe(gulp.dest(distPath));
  };
};
gulp.task(envJs);

清除dist目录

在重新编译的时候我们都需要清除dist目录的资源,以免导致混乱

/* 清除dist目录 */
gulp.task("clean", done => {
  del.sync(["dist/**"]);
  done();
});

自动创建目录

使用命令新建page目录和component目录,只要把模版文件拷贝并重命名即可。

const newfile = done => {
  yargs
    .example("gulp newfile  -p mypage", "创建mypage的page目录")
    .example("gulp newfile  -c mycomponent", "创建mycomponent的component目录")
    .example(
      "gulp newfile  -s srcfile -p mypage",
      "以srcfile为模版创建mypage的page目录"
    )
    .option({
      s: {
        alias: "src",
        describe: "模板",
        type: "string",
        default: "template"
      },
      p: {
        alias: "page",
        describe: "page名称",
        type: "string"
      },
      c: {
        alias: "component",
        describe: "component名称",
        type: "string"
      }
    })
    .fail(msg => {
      done();
      console.error("创建失败");
      console.log(msg);
      console.log("help");
      yargs.parse(["--msg"]);
    })
    .help("msg");

  const args = yargs.argv;
  //console.log("args", args);
  const source = args.s;
  const filePaths = {
    p: "pages",
    c: "components"
  };

  let name,
    type,
    hasParam = false;
  for (let key in filePaths) {
    if (args[key]) {
      hasParam = true;
      name = args[key];
      type = filePaths[key];
    }
  }
  if (!hasParam) {
    done();
    yargs.parse(["--msg"]);
  }
  const defaultPath =
    source === "template"
      ? `src/${source}/${type}/*`
      : `src/${type}/${source}/*`;
  return gulp.src(defaultPath).pipe(gulp.dest(`src/${type}/${name}/`));
};
gulp.task(newfile);

总结

优化的工作流比较简单,无非就是复制文件,scss处理,资源处理,自动创建目录等。以上只是简单的示例,如果需要的话可以引入压缩插件及其他插件进行优化。

参考文章

武装你的小程序

基于Gulp构建的微信小程序开发工作流