gulp構建小程序

目前來說,對於構建小程序的,類似taro這些框架,生態已經挺完善的了,沒有什麼必要再搞一套來折騰自己。但是,我司的小程序,是很早之前就開發的,我們負責人當時信不過這些開源的框架,於是自己用webpack搞了一套框架,但有一個比較嚴重的問題,有一些文件依賴重複打包了,導致小程序包體積比較大。

持續了一個多月,主包體積在2M左右徘徊,開發都很難做下去。我們負責人終於受不了了,給了我個任務,讓我寫一個構建小程序的工具,減少小程序包體積。

我們現在的框架對比一下原生小程序,其實差別不大,無非就是

 ts => js
sass=>wxss
wxml=>wxml
json=>json

由於我司小程序基礎庫是1.9.8的,不支持構建npm,所以node_modules的依賴包以及依賴路徑需要自己處理,於是寫了一個babel插件 babel-plugin-copy-npm
這麼一想,其實不難,而且單文件編譯,那不是gulp的強項嗎!!!

最終效果:
圖片1

圖片1

圖片1

而且由於增量更新,只修改改變的文件,所以編譯的速度非常快。

項目地址:https://github.com/m-Ryan/ry-wx

最終流程大概如下:清除dist目錄下的文件 => 編譯文件到dist目錄下=> 開發模式監聽文件更改,生產環境壓縮文件。

一、清除dist目錄下的文件 (clean.js)

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')
    });
};

二、編譯文件

  • 1.編譯typescript(compileJs.js)
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));
};

  • 2.編譯sass(compileSass.js)
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));
};

    1. 編譯json,wxml,由於需要壓縮,所以需要分開處理

(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));
};

  • 4.拷貝其他靜態資源,例如字體、圖片

(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));
};

  • 5.引入文件(gulpfile.js)
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;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章