background
The company has several small program projects that are developed in a native way. The native method has its own advantages, such as not having to step on the pits of the framework, but the disadvantages are also obvious, and the efficiency improvement brought by the framework cannot be used. Based on this, we simply use gulp to configure a set of workflows to help us save some repetitive operations in the development process.
Why use gulp instead of webpack? After practicing these two tools, I found that it is easier to use gulp for our problems. . .
This article will not introduce too much about gulp, the focus is on the realization of the function.
function list
- Support using less to write css
- css auto-completion
- js syntax support
- css and js code compression
- The picture is automatically uploaded to the cdn, after monitoring the picture change, it is automatically uploaded to the cdn
- Support static resource directories, such as di Sanfang JS, pictures that need to be placed locally
- Mini program's native npm function, automatically build npm packages applicable to the Mini Program through commands
- The unit is converted by default, that is, px is automatically converted to rpx, and it supports the adaptation of different end screens
- Support source map, able to locate where the built code is wrong
- Create page and component through commands, and automatically generate four files
- Support environment variables, automatically generate codes for different environments through commands
- Introduce miniprogram-ci, upload the code to the WeChat background
Directory Structure
Let's take a look at the directory structure after configuration. The content of the src directory is the code of the WeChat applet, and the external ones are all configuration files.
Command definition
The following are the commands defined in package.json, and these functions will be implemented one by one.
"scripts": {
"start": "rm -rf ./dist && cross-env NODE_ENV=development gulp",
"preview": "gulp preview",
"build-pro": "rm -rf ./dist && cross-env NODE_ENV=production gulp build",
"build-dev": "rm -rf ./dist && cross-env NODE_ENV=development gulp build",
"build-npm": "gulp npm",
"deploy-dev": "npm run build-dev && gulp upload",
"deploy-pro": "npm run build-pro && gulp upload",
"cp": "create-wxapp-page --type=page --dir=src --indent=2 --style=less",
"cc": "create-wxapp-page --type=component --dir=src --indent=2 --style=less"
},
gulpfile
The gulpfile file is all the configuration code, and each task will be explained in detail later.
const path = require('path');
const fileExists = require('file-exists');
const gulp = require('gulp');
const less = require('gulp-less');
const uglify = require('gulp-uglify');
const cleanCSS = require('gulp-clean-css');
const rename = require('gulp-rename');
const del = require('del');
const qcloud = require('qcloud-upload');
const gulpif = require('gulp-if');
const gutil = require('gulp-util');
const replace = require('gulp-replace');
const px2rpx = require('gulp-px2rpx');
const ci = require('miniprogram-ci');
const sourcemaps = require('gulp-sourcemaps');
const alias = require('gulp-path-alias');
const pkg = require('./package.json')
const projectConfig = require('./project.config.json')
const buildPath = path.join(__dirname, 'dist/')
const uploadFolder = path.join(__dirname, './src/images')
const isPro = process.env.NODE_ENV === 'production'
const config = {
// 腾讯CDN油漆桶配置
assetsCDN: 'https://xxx.cos.ap-guangzhou.myqcloud.com/',
cos: {
Bucket: 'xxx',
Region: 'xxx',
SecretId: 'xxx',
SecretKey: 'xxx',
prefix: `${pkg.name}/images`, // 上传到油漆桶的哪个文件夹
src: uploadFolder, // 上传哪个文件夹到油漆桶
overWrite: 1,
},
enablePx2Rpx: true,
enableCleanCSS: false,
enableAuto: true, // 自动补全css
enableUglify: false,
enableSourcemap: true,
};
const paths = {
styles: {
src: ['src/**/*.less'],
dest: buildPath
},
images: {
src: 'src/images/**/*.{png,jpg,jpeg,svg,gif}',
dest: buildPath
},
scripts: {
src: 'src/**/*.js',
dest: buildPath
},
copy: {
src: ['src/**', '!src/**/*.less', '!src/images/**', '!src/**/*.js', 'package.json'],
dest: buildPath
},
}
// 删除构建
function clean() {
return del([buildPath])
}
function log() {
const data = Array.prototype.slice.call(arguments)
gutil.log.apply(false, data)
}
function upload() {
return new Promise(function (resolve, reject) {
// 普通函数,resolve()的时候,qcloud不一定执行结束
qcloud(config.cos)
resolve()
})
}
// 任务处理函数
function styles() {
return gulp
.src(paths.styles.src, { base: 'src' })
.pipe(alias({
paths: {
'@': path.resolve(__dirname, './src/'),
}
}))
.pipe(less())
.pipe(replace('%CDN_IMG%/', config.assetsCDN + config.cos.prefix + '/'))
.pipe(gulpif(config.enableCleanCSS, cleanCSS()))
.pipe(gulpif(config.enablePx2Rpx, px2rpx({
screenWidth: 375, // 设计稿屏幕, 默认750
wxappScreenWidth: 750, // 微信小程序屏幕, 默认750
remPrecision: 6
})))
.pipe(replace('PX', 'px'))
.pipe(rename(path => (path.extname = '.wxss')))
.pipe(gulp.dest(paths.styles.dest))
}
function scripts() {
return gulp
.src(paths.scripts.src, { base: 'src' })
.pipe(alias({
paths: {
'@': path.resolve(__dirname, './src/'), // src 目录
}
}))
.pipe(gulpif(config.enableSourcemap, sourcemaps.init()))
.pipe(gulpif(isPro, replace('%ENV%', 'production'), replace('%ENV%', 'development'))) // 环境变量静态替换
.pipe(replace('%CDN_IMG%/', config.assetsCDN + config.cos.prefix + '/'))
.pipe(replace('%VERSION%', pkg.version))
.pipe(gulpif(config.enableUglify, uglify()))
.pipe(gulpif(config.enableSourcemap, sourcemaps.write('.')))
.pipe(gulp.dest(paths.scripts.dest))
}
// 不需要处理的文件直接复制过去
function copy() {
return gulp
.src(paths.copy.src)
.pipe(replace('%CDN_IMG%/', config.assetsCDN + config.cos.prefix + '/'))
.pipe(gulp.dest(paths.copy.dest))
}
function watchFiles() {
const w1 = gulp.watch(paths.styles.src, styles).on('unlink', function (file) {
log(gutil.colors.yellow(file) + ' is deleted')
const filePath = file.replace(/src\\/, 'dist\\')
del([filePath])
});
const w2 = gulp.watch(paths.scripts.src, scripts).on('unlink', function (file) {
log(gutil.colors.yellow(file) + ' is deleted')
const filePath = file.replace(/src\\/, 'dist\\')
del([filePath])
});
const w3 = gulp.watch(paths.copy.src, copy).on('unlink', function (file) {
log(gutil.colors.yellow(file) + ' is deleted')
const filePath = file.replace(/src\\/, 'dist\\')
del([filePath])
});
const w4 = gulp.watch(paths.images.src, upload).on('unlink', function (file) {
log(gutil.colors.yellow(file) + ' is deleted')
const filePath = file.replace(/src\\/, 'tmp\\')
del([filePath])
});
return Promise.all([w1, w2, w3, w4])
}
/**
* 小程序ci相关函数
*/
let project = {}
const keyFile = fileExists.sync(`./private.${projectConfig.appid}.key`)
if (keyFile) {
project = new ci.Project({
appid: projectConfig.appid,
type: 'miniProgram',
projectPath: './dist',
privateKeyPath: `./private.${projectConfig.appid}.key`,
ignores: [],
})
}
async function npmBuild() {
await ci.packNpmManually({
packageJsonPath: './package.json',
miniprogramNpmDistDir: './src/',
})
}
async function mpUpload() {
const uploadResult = await ci.upload({
project,
version: pkg.version,
desc: pkg.description,
setting: {
es6: true,
minify: true,
autoPrefixWXSS: true,
},
onProgressUpdate: console.log,
})
console.log('[uploadResult:]', uploadResult)
}
async function preview() {
const previewResult = await ci.preview({
project,
desc: pkg.description, // 此备注将显示在“小程序助手”开发版列表中
qrcodeFormat: 'image',
qrcodeOutputDest: './preview.jpg',
onProgressUpdate: console.log,
})
console.log('[previewResult:]', previewResult)
}
exports.watch = watchFiles
exports.preview = preview
// ci 自动构建npm
exports.npm = npmBuild
exports.upload = mpUpload
exports.default = gulp.series(styles, scripts, copy, upload, watchFiles)
exports.build = gulp.series(clean, styles, scripts, copy, upload)
Automatically create components and pages
The automatic creation of components and pages uses an npm package called create-wxapp-page. With it, a set of files can be created directly on the command line.
npm run cc # 然后输入组件名字
npm run cp # 然后输入页面名字
Build npm automatically
The applet supports npm, but you need to manually click compile after the developer tools are turned on to generate the corresponding npm package. Fortunately, WeChat provides the miniprogram-ci package, which can save the manual process.
const ci = require('miniprogram-ci');
async function npmBuild() {
await ci.packNpmManually({
packageJsonPath: './package.json',
miniprogramNpmDistDir: './src/',
})
}
exports.npm = npmBuild
Execute npm run build-npm, and the package we installed will be built into the miniprogram_npm directory of src.
Environment variable support
Environment variables can help us distinguish the code to be executed in different environments, such as the API address. The implementation method is static replacement.
pipe(gulpif(isPro, replace('%ENV%', 'production'), replace('%ENV%', 'development'))
const isPro = '%ENV%' === 'production'
if (isPro) {
// 生产环境
} else {
// 测试,体验环境
}
Image upload to CDN
When it detects that there is a picture change in the images folder, the upload operation will be executed.
function upload() {
return new Promise(function (resolve, reject) {
// 普通函数,resolve()的时候,qcloud不一定执行结束。qcloud没有提供上传成功的callback
qcloud(config.cos)
resolve()
})
}
Use CND pictures
<image src="%CDN_IMG%/index/empty" mode="aspectFit" class="empty__img" />
sourcemap
sourcemap is also very simple, it is also a package, gulp-sourcemap
.pipe(gulpif(config.enableSourcemap, sourcemaps.init())
Static directory
For some special static resources, such as tabbar icon images, you can put them in the src/static directory, and the files in this directory will be copied to the dist directory as they are.
js syntax support
The new syntax of js is recommended to use the "es6 to es5" and "enhanced compilation" that come with the small program tool. Practice has found that using glup-babel will cause js compilation to be too slow. The tools that come with it are enough.
Upload code using CI
miniprogram-ci provides upload code to the mini program management background. The first step is to download the key first, then name the file private.{appId}.key, and finally place it in the project root directory. For security reasons, it is better to put the ci function on the server side, and put it on the front end here.
Execute npm run deploy-dev to upload the code to the experience version, and finally the experience version is selected as the ci robot.
project.config.json changes
{
"description": "项目配置文件",
"miniprogramRoot": "dist/",
"packOptions": {
"ignore": [
{
"type": "folder",
"value": "images"
}
]
}
}
The dist directory is the built small program code, so you must specify the miniprogramRoot as "dist/"
Since the image is uploaded to the CDN, there is no need to package the src/images folder into a small program, which also reduces the size.
### Conclusion
In fact, the code of the glupfile file is relatively simple, and it feels a bit redundant to explain too much. The above configuration runs smoothly on our online small programs, and the cost of modification is also very low. If you have a small partner who wants to use your own small program, please leave a message if you encounter any problems.
Above, thanks for reading!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。