目前來講,對於構建小程序的,相似taro這些框架,生態已經挺完善的了,沒有什麼必要再搞一套來折騰本身。可是,我司的小程序,是很早以前就開發的,咱們負責人當時信不過這些開源的框架,因而本身用webpack搞了一套框架,但有一個比較嚴重的問題,有一些文件依賴重複打包了,致使小程序包體積比較大。css
持續了一個多月,主包體積在2M左右徘徊,開發都很難作下去。咱們負責人終於受不了了,給了我個任務,讓我寫一個構建小程序的工具,減小小程序包體積。html
咱們如今的框架對比一下原生小程序,其實差異不大,無非就是node
ts => js sass=>wxss wxml=>wxml json=>json
因爲我司小程序基礎庫是1.9.8的,不支持構建npm,因此node_modules的依賴包以及依賴路徑須要本身處理,因而寫了一個babel插件 babel-plugin-copy-npm。
這麼一想,其實不難,並且單文件編譯,那不是gulp的強項嗎!!!webpack
最終效果:
ios
並且因爲增量更新,只修改改變的文件,因此編譯的速度很是快。git
項目地址:https://github.com/m-Ryan/ry-wxgithub
最終流程大概以下:清除dist目錄下的文件 => 編譯文件到dist目錄下=> 開發模式監聽文件更改,生產環境壓縮文件。web
1、清除dist目錄下的文件 (clean.js)typescript
const del = require('del'); const fs = require('fs'); const path = require('path'); const cwd = process.cwd(); module.exports = function clean() { if (!fs.existsSync(path.join(cwd, 'dist'))) { fs.mkdirSync('dist'); return Promise.resolve(null); } return del([ '*', '!npm' ], { force: true, cwd: path.join(cwd, 'dist') }); };
2、編譯文件npm
const gulp = require('gulp'); const { babel } = require('gulp-load-plugins')(); const path = require('path'); const cwd = process.cwd(); module.exports = function compileJs(filePath) { let file = 'src/**/*.ts'; let dist = 'dist'; if (typeof filePath === 'string') { file = path.join(cwd, filePath); dist = path.dirname(file.replace(/src/, 'dist')); } return gulp.src(file).pipe(babel()).pipe(gulp.dest(dist)); };
const gulp = require('gulp'); const { sass, postcss, rename } = require('gulp-load-plugins')(); const path = require('path'); const cwd = process.cwd(); const plugins = [ require('autoprefixer')({ browsers: [ 'ios >= 8', 'ChromeAndroid >= 53' ], remove: false, add: true }), require('postcss-pxtorpx')({ multiplier: 2, propList: [ '*' ] }) ]; module.exports = function compileSass(filePath) { let file = 'src/**/*.scss'; let dist = 'dist'; if (typeof filePath === 'string') { file = path.join(cwd, filePath); dist = path.dirname(file.replace(/src/, 'dist')); } return gulp .src(file) .pipe(sass({ outputStyle: 'compressed' }).on('error', sass.logError)) .pipe(postcss(plugins)) .pipe( rename({ extname: '.wxss' }) ) .pipe(gulp.dest(dist)); };
(copyJson.js)
const gulp = require('gulp'); module.exports = function copyJson() { let file = 'src/**/*.json'; let dist = 'dist'; if (typeof filePath === 'string') { file = path.join(cwd, filePath); dist = path.dirname(file.replace(/src/, 'dist')); } return gulp.src([ file ]).pipe(gulp.dest(dist)); };
(copyWxml.js)
const gulp = require('gulp'); const minifyHtml = require('gulp-html-minify'); module.exports = function copyWxmlFiles() { let file = 'src/**/*.wxml'; let dist = 'dist'; if (typeof filePath === 'string') { file = path.join(cwd, filePath); dist = path.dirname(file.replace(/src/, 'dist')); } return gulp.src(file).pipe(minifyHtml()).pipe(gulp.dest(dist)); };
(copyAssets.js)
const gulp = require("gulp"); module.exports = function copyAssets() { let file = "src/**/**"; let dist = "dist"; if (typeof filePath === "string") { file = path.join(cwd, filePath); dist = path.dirname(file.replace(/src/, "dist")); } return gulp .src([ file, "!**/*.json", "!**/*.ts", "!**/*.js", "!**/*.scss", "!**/*.wxml" ]) .pipe(gulp.dest(dist)); };
const gulp = require("gulp"); const clean = require("./build/clean"); const compileJs = require("./build/compileJs"); const compileSass = require("./build/compileSass"); const copyJson = require("./build/copyJson"); const copyWxml = require("./build/copyWxml"); const copyAssets = require("./build/copyAssets"); const fs = require("fs-extra"); const path = require("path"); const chalk = require("chalk"); const cwd = process.cwd(); const dayjs = require("dayjs"); const tasks = [ clean, gulp.parallel([compileJs, compileSass, copyJson, copyWxml]), copyAssets ]; if (process.env.NODE_ENV === "development") { tasks.push(watch); } gulp.task("default", gulp.series(tasks)); gulp.task("watch", watch); function watch() { console.log(chalk.blue(`正在監聽文件... ${getNow()}`)); const watcher = gulp.watch("src/**/**"); watcher.on("change", function(filePath, stats) { compile(filePath); }); watcher.on("add", function(filePath, stats) { compile(filePath); }); watcher.on("unlink", function(filePath, stats) { let distFile = filePath.replace(/^src\b/, "dist"); let absolutePath = ""; if (distFile.endsWith(".ts")) { distFile = distFile.replace(/.ts$/, ".js"); } else if (distFile.endsWith(".scss")) { distFile = distFile.replace(/.scss$/, ".wxss"); } absolutePath = path.join(cwd, distFile); if (fs.existsSync(absolutePath)) { fs.unlinkSync(absolutePath); console.log( chalk.yellow(`刪除文件:${path.basename(distFile)} ${getNow()}`) ); } }); } function compile(filePath) { console.info( chalk.green(`編譯完成:${path.basename(filePath)} ${getNow()}`) ); if (filePath.endsWith(".ts")) { compileJs(filePath); } else if (filePath.endsWith(".scss")) { compileSass(filePath); } else if (filePath.endsWith(".wxml")) { copyWxml(filePath); } else if (filePath.endsWith(".json")) { copyJson(filePath); } else { copyAssets(filePath); } } function getNow() { return dayjs().format("HH:mm:ss"); }
babel的配置以下.babelrc.js
const babelOptions = { presets: [ '@babel/preset-typescript', [ '@babel/env' ] ], plugins: [ 'lodash', [ '@babel/plugin-proposal-decorators', { legacy: true } ], 'babel-plugin-add-module-exports', [ '@babel/plugin-transform-runtime', { corejs: false, helpers: true, regenerator: true, useESModules: false } ], [ 'module-resolver', { root: [ '.' ], alias: { '@': './src' } } ], [ 'babel-plugin-copy-npm', { rootDir: 'src', outputDir: 'dist', npmDir: 'npm', format: 'cjs', strict: false, minify: true, loose: true, cache: true } ] ] }; if (process.env.NODE_ENV === 'production') { babelOptions.presets.unshift([ 'minify', { mangle: { exclude: [ 'wx', 'module', 'exports', '__wxConfigx', 'process', 'global' ] }, keepFnName: true } ]); } module.exports = babelOptions;