开发小程序时,最麻烦的事情莫过于在上线前须要反复切换测试和正式环境接口地址。javascript
本文介绍一种小程序工程化改造的思路,基于这个咱们可以实现小程序自动根据多环境打包。css
https://github.com/mecoepcoo/miniprogram-boilerplatejava
阅读本文,你须要有对如下内容的基本认知:git
原生的小程序只有一个简单的启动脚手架,不支持less、sass等样式预处理器,对npm的支持也不是太好,咱们本身作一个简单的构建工具,来加强小程序的功能。本节起一个抛砖引玉的做用,基于这个思路,能够改造出更多更强大的功能。github
dist 输出/发布目录,在微信开发者工具中打开这个目录npm
srcjson
miniprogramgulp
本文写做时,gulp的版本是v4
,api与以前的版本有一些变化。小程序
建立一个空目录后,先安装依赖:api
$ npm init $ npm i -D gulp gulp-plumber gulp-rename del
在根目录新建gulpfile.js
文件,引入依赖:
const gulp = require('gulp'); const plumber = require('gulp-plumber'); // 发生错误时阻止gulp退出并输出日志 const rename = require('gulp-rename'); // 输出时重命名文件 const del = require('del');
用less等预处理器书写样式,可能会更方便,安装依赖:
$ npm i -D gulp-less gulp-cssnano
假设咱们的源码放在/src/miniprogram
目录下,输出到/dist
目录下。
如今让gulp支持less编译:
const less = require('gulp-less'); // 处理less const cssnano = require('gulp-cssnano'); // 压缩代码 // 编译样式 gulp.task('build:style', () => { return gulp.src([ // 千万不要漏掉return,不然gulp不知道这个任务什么时候完成 'src/miniprogram/pages/**/*.less', 'src/miniprogram/components/**/*.less', 'src/miniprogram/spreadpack/**/*.less', 'src/miniprogram/app.less' ], {base: 'src/miniprogram'}) .pipe(plumber()) .pipe(less()) .pipe( cssnano({ zindex: false, autoprefixer: false, discardComments: { removeAll: true } }) ) .pipe( rename(path => { path.extname = '.wxss'; // 咱们用less作后缀名,但小程序只支持wxss,因此须要修改输出的后缀 }) ) .pipe(gulp.dest('dist')); // 写入到dist文件夹中 });
本文只作简单的思路介绍,因此咱们仍是按照原来的方法编写小程序的js和模板。
这里只是把js,wxml和json复制到输出目录:
// 编译示例 gulp.task('build:main', gulp.series('build:style', () => { return gulp.src([ 'src/miniprogram/**/*', '!src/miniprogram/**/*.less', // 排除less后缀文件 '!src/project.config.json', // 配置文件不写入到dist文件夹,开发时需手动拷贝到dist文件夹中 !!! ], {base: 'src/miniprogram', allowEmpty: true}) .pipe(plumber()) .pipe(gulp.dest('dist')); }));
在发布前,咱们须要删除掉多余的文件,这里新增一个工做流用来清理输出目录:
gulp.task('clean', cb => { return del([ 'dist/**/*', '!dist/project.config.json' ], cb); });
最后咱们补全功能,首先增长一个开发环境启动配置:
gulp.task('build', gulp.series('build:main')); // 监听文件(若文件修改则执行相关的任务) function watch() { let watcher = gulp.watch('src/**', cb => cb()); watcher.on('all', (event, path, stats) => { console.log('File ' + path + ' was ' + event + ', running tasks...'); }); return watcher; } gulp.task('default', gulp.series(watch));
在package.json
中增长脚本:
"scripts": { "start": "npm run clean && npm run build", "dev": "gulp", "build": "gulp build", "watch": "gulp watch", "clean": "gulp clean", }
如今执行npm start
或者npm run dev
,用小程序开发工具打开dist目录,就能看到效果了。
有了gulp,一切关于构建的问题都简单了。使用gulp-preprocess
来支持环境变量。
gulp-preprocess的用法见官方文档。
安装依赖:
$ npm i -D cross-env gulp-preprocess
因为操做系统之间设置环境变量命令的差别,引入cross-env
来解决,先修改package.json
:
"scripts": { "start": "cross-env NODE_ENV=prod npm run clean && npm run build", "dev": "cross-env NODE_ENV=dev gulp", "build": "cross-env NODE_ENV=prod gulp build", "watch": "cross-env NODE_ENV=dev gulp watch", "clean": "gulp clean", }
这里增长了一个名为NODE_ENV
的环境变量,并设置了dev
和prod
两个值,这样开发时会取dev变量,打包发布时会取prod变量。
而后增长gulp配置:
const preprocess = require('gulp-preprocess'); // 注入环境变量 gulp.task('build:main', gulp.series('build:style', () => { return gulp.src([ 'src/miniprogram/**/*', '!src/miniprogram/assets/**/*', // 新增配置在这里 '!src/miniprogram/**/*.less', '!src/project.config.json', ], {base: 'src/miniprogram', allowEmpty: true}) .pipe(plumber()) .pipe(preprocess()) // 新增配置在这里 .pipe(gulp.dest('dist')); })); // 因为preprocess这个插件会影响静态资源,因此须要把静态资源的打包拿出去 /* 处理静态资源 */ gulp.task('build:assets', () => { return gulp.src([ "src/miniprogram/assets/**/*" ], { base: 'src/miniprogram', allowEmpty: true }) .pipe(plumber()) .pipe(gulp.dest('dist')); }); // 修改构建配置 gulp.task('build', gulp.parallel('build:main', 'build:assets')); function watch() { let watcher = gulp.watch('src/**', gulp.parallel('build:main', 'build:assets'), cb => cb()); watcher.on('all', (event, path, stats) => { console.log('File ' + path + ' was ' + event + ', running tasks...'); }); return watcher; }
用这种方法注入环境变量:
let env = '/* @echo NODE_ENV */'; let apiRoot = ''; switch (env) { case 'dev': apiRoot = 'http://dev-api.tianzhen.tech'; break; case 'prod': apiRoot = 'http://api.tianzhen.tech'; break; }
写一个demo,运行npm start
试试吧!