開發小程序時,最麻煩的事情莫過於在上線前須要反覆切換測試和正式環境接口地址。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
試試吧!