小程序系列之-工程化

前段时间刚做了公司小程序的工程化,那么接下来总结一下做了什么,希望对大家可以有些帮助。

首先我先简单的列举一下做了哪些功能:

  1. lint

  2. git commit

  3. 环境变量和公共配置使用node设置,私有配置引入config.js

    ​ "dev": "NODE_ENV=dev node ./set-env.js",

    ​ "build": "NODE_ENV=online node ./set-env.js",

  4. 工程内本地cli,加入生成路由页面、组件以及新小程序项目

  5. 项目压缩--JS、CSSS Tree-Shaking

  6. 项目分包配置、预加载配置、自定义组件懒加载配置

  7. 针对老项目添加node脚本,匹配无用css代码

小程序一些基本的信息这里就不多讲解,有兴趣的可以点击查看

打包工具

首先我们说一下打包工具的选择,我这里打包工具选择了gulp,抛弃了我更熟悉的webpack,那这是为什么呢?

小程序发布中需要上传代码,与以往前端代码不同的是,小程序发布上传代码上传的是源文件,微信会编译。那么问题就来了,我们如果做了编译之后微信那边还认吗---还是认的,前提是符合他的代码规范。

webpack打包出来的代码,总会多加一些东西,而多出来的这些东西是我们不需要的,所以我选择gulp只对代码做一些清洗工作。

话不多说了,直接贴代码

const { src, dest, series, watch } = require('gulp');
const gulpClean = require('gulp-clean');
const gulpif = require('gulp-if');
const prettyData = require('gulp-pretty-data');
const postcss = require('gulp-postcss');
const cssnano = require('cssnano');//css tree-shaking
const uglify = require('gulp-uglify-es').default;//js tree-shaking抛弃了gulp-uglify,选择了gulp-uglify-es,这个版本可以保留es6的代码,小程序中可以使用es6的写法
const changed = require('gulp-changed');
const gutil = require('gulp-util');
const { currentProject } = require('./current-project.js');//本地项目配置currentProject表示具体某个小程序的项目名
const yargs = require('yargs');// cli命令处理用的
const rename = require('gulp-rename');

const srcPath = `src/${currentProject}/**`;
const distPath = `dist/${currentProject}`;

function isOnline() {
    // 判断文件的扩展名是否是 '.wxss'
    return process.env.NODE_ENV === 'online';
}

function isJS(file) {
    return process.env.NODE_ENV === 'online' && file.extname === '.js';
}

function isWxss(file) {
    return process.env.NODE_ENV === 'online' && file.extname === '.wxss';
}

function clean() {
    return src(distPath, { read: false, allowEmpty: true }).pipe(gulpClean());
}

function copy() {
    return src(srcPath)
        .pipe(changed(distPath))
        .pipe(
            gulpif(
                isOnline,
                prettyData({
                    type: 'minify',
                    extensions: {
                        wxml: 'xml'
                    }
                })
            )
        )
        .pipe(gulpif(isJS, uglify({ compress: {
            drop_console: true
        }})))
        .pipe(gulpif(isWxss, postcss([cssnano()])))
        .on('error', function(err) {
            gutil.log(gutil.colors.red('[Error]'), err.toString());
        })
        .pipe(dest(`dist/${currentProject}`));
}

function watchTask() {
    watch([srcPath], function(cb) {
        copy();
        cb();
    });
}

function newfile(done) {
    yargs
        .example('gulp newfile  -p myPage', '创建myPage的page目录')
        .example('gulp newfile  -c myComponent', '创建myComponent的component目录')
        .example('gulp newfile  -n myProject', '创建myProject小程序')
        .option({
            n: {
                alias: 'newProject',
                describe: '模板',
                type: 'string'
            },
            p: {
                alias: 'page',
                describe: 'page名称',
                type: 'string'
            },
            c: {
                alias: 'component',
                describe: 'component名称',
                type: 'string'
            }
        })
        .fail(msg => {
            done();
            console.error('创建失败');
            console.log(msg);
            console.log('help');
            yargs.parse(['--msg']);
        })
        .help('msg');

    const args = yargs.argv;
    const filePaths = {
        p: 'pages',
        c: 'components',
        n: 'project'
    };

    let name;
    let type;
    let hasParam = false;
    for (const key in filePaths) {
        if (args[key]) {
            hasParam = true;
            name = args[key];
            type = filePaths[key];
        }
    }
    if (!hasParam) {
        done();
        yargs.parse(['--msg']);
    }
    const defaultPath = `template/${type}/**`;
    if (type == 'project') {
        return src(defaultPath)
            .pipe(dest(`src/${name}/`));
    }
    return src(defaultPath)
        .pipe(
            rename(function(path) {
                path.basename = name;
            })
        )
        .pipe(dest(`src/${currentProject}/${type}/${name}/`));
}

exports.copy = series(clean, copy);
exports.watch = watchTask;
exports.newfile = newfile;

复制代码

上述代码中我们完成了

4.工程内本地cli,加入生成路由页面、组件以及新小程序项目项目

5.压缩--JS、CSSS Tree-Shaking

在模板文件中完成了6.项目分包配置、预加载配置、自定义组件懒加载配置

具体的模板文件代码这里就不展示了,分包配置、预加载配置、自定义组件懒加载配置有兴趣的可查看微信的官方文档。

lint

lint方面JS这边没有什么稀奇古怪的,正常使用就可以,stylelint这边需要兼容到wxss,微信中使用了rpx做适配,这里推荐使用stylelint-config-standard-wxss

git commit

这里我们使用的是

"commit": "./node_modules/.bin/git-cz",
复制代码

有兴趣的可以自己研究一下,这里不细说了。

环境变量设置

脚本执行

"dev": "NODE_ENV=dev node ./set-env.js",
"build": "NODE_ENV=online node ./set-env.js",

# 上传时候自动执行npm run build,保证线上环境域名正确
 "husky": {
        "hooks": {
            "pre-commit": "npm run build && git add . && lint-staged",
        }
 },
复制代码

具体代码

// 切换环境
const { createWriteStream } = require('fs');
const { resolve } = require('path');
const { currentProject, currentVersion, appId } = require('./current-project');
// 当前环境变量
const CUR_ENV = process.env.NODE_ENV || 'online';
const mark = CUR_ENV == 'online' ? '域名' : '域名';
const upload = CUR_ENV == 'online' ? '域名' : '域名';

// 要写入的内容
const content = `import privateConfig from './config.js';
const env = '${CUR_ENV}';
const version = '${currentVersion}';
const appId = '${appId}';
export default {
    appId,
    env,
    version,
    updateAppAuto: true,
    api: 'https://${mark}',
    uploadApi: 'https://${upload}',
    ...privateConfig
};
`;
// 创建流
const fileName = resolve(__dirname, `./src/${currentProject}/config/env.js`);
console.log(fileName);
const ws = createWriteStream(fileName, {
    encoding: 'utf8',
    autoClose: true
});
ws.on('open', function() {
    console.log(`正在设置环境变量....`);
});
ws.on('finish', function() {
    console.log(`设置环境变量成功: ${CUR_ENV || '线上环境'}`);
    process.exit();
});
ws.on('error', function() {
    process.exit(1);
});
ws.write(content);
ws.end();

复制代码

结尾

更多的没有想到太多更好的想法,欢迎大家提供意见

分享我私藏的TS教程,从0到高阶全系列,点击链接,0元获取

www.yidengxuetang.com/pub-page/in…

分类:
前端
标签: