微信小程序转换为支付宝小程序

最近写了个脚手架,可以在写微信小程序的同时,实时生成支付宝小程序,开发者工具同步自动刷新。 可以转换现有微信小程序为支付宝小程序

实现的思路很简单,将微信小程序的文件更改名称,复制到支付宝小程序的文件夹,并且转换标签语法,做兼容处理。

代码放在GitHub,有需要的同学可以试用

https://github.com/ahnuchen/miniprogram-helper

觉得好用给个star吧

安装教程

npm install

实时编译:

npm start

转换小程序:

npm run build

使用说明

一. 找到根目录下gulpfile.js,将resourceDir(小程序小程序)目录和compileTargetDir(支付宝小程序)替换为你自己放置的目录

const config = {
    copyFileLog: true,
    resourceDir: path.join(__dirname, 'wechat-app/'),
    compileTargetDir: path.join(__dirname, 'ali-app/')
};

运行npm start命令, 然后分别打开支付宝小程序和微信小程序开发者工具,打开对应文件夹。 现在你只需要写微信小程序,就能看到两边的代码同时刷新啦

二. 如果是现有小程序,需要在app.js引入core.js以及核心库代码

//app.js
let wm = null;
let platform
if (typeof wx !== 'undefined') {
    wm = wx
    platform = 'wx'
}
if (typeof my !== 'undefined') {
    wm = my
    platform = 'my'
}
App({
    core: require('/core/core'),
    utils: require('/utils/util.js'),
    platform,
})

并且将所有js文件中的wx.替换为getApp().core.,app.js中的wx.替换为wm. 执行一次npm run build,再回到第一步

注意事项

支付宝小程序不支持p、i 等html标签,因此请不要用这些标签

部分api需要执行兼容处理,可利用getApp().platform判断wx(微信)或my(支付宝)小程序环境

css请尽量使用rpx单位,其他单位可能不兼容

未来feature

  •  支持wxs转换为sjs
  •  getUserInfo等需要用户主动操作的api在框架层面的兼容
  •  支持头条、美团等更多类型小程序转换
const gulp = require('gulp');
const watch = require('gulp-watch');
const path = require('path')
const fs = require('fs-extra')
const {transFormFileContent} = require("./ast");

const config = {
    copyFileLog: true,
    resourceDir: path.join(__dirname, 'app/'),
    compileTargetDir: path.join(__dirname, 'myapp/')
};

const utils = {
    copyFiles(filePath, isDir, resourceDir, compileTargetDir) {
        fs.ensureDirSync(compileTargetDir)
        var subFilePath = filePath.replace(path.resolve(resourceDir), '')
        var copyTargetPath = utils.replaceTargetPath(path.join(path.resolve(compileTargetDir), subFilePath))
        if (isDir) {
            fs.ensureDirSync(copyTargetPath)
        } else {
            fs.ensureFile(copyTargetPath).then(copy)
        }
        if (config.copyFileLog) {
            console.info(`hot-reload-file:${filePath} \n`)
        }

        function copy() {
            fs.copyFileSync(path.resolve(filePath), copyTargetPath)
            transFormFileContent(copyTargetPath)
        }
    },
    replaceTargetPath(p) {
        const wxExtList = ['.wxss', '.wxml', '.wxs']
        const aliExtList = ['.acss', '.axml', '.sjs']
        wxExtList.forEach((ext, index) => {
            if (p.includes(ext)) {
                p = p.replace(ext, aliExtList[index])
            }
        })
        return p
    },
    build(resourceDir, compileTargetDir) {
        function readDir(rootPath) {
            const fileList = fs.readdirSync(rootPath)
            fileList.forEach(f => {
                let fPath = path.join(rootPath, f)
                let fisDir = !fs.statSync(fPath).isFile()
                utils.copyFiles(fPath, fisDir, resourceDir, compileTargetDir)
                if (fisDir) {
                    readDir(fPath)
                }
            })
        }

        readDir(resourceDir)
    }
};
/**
 * ================ 任务 =======================
 */
gulp.task('hot-reload', function () {
    return watch(config.resourceDir + '**', {events: ['add', 'change']}, function (file) {
        return utils.copyFiles(file.path, file.isDirectory(), config.resourceDir, config.compileTargetDir)
    })
})

gulp.task('build', function () {
    return utils.build(config.resourceDir, config.compileTargetDir)
})

/**
 *  =============== 运行 ======================
 */
// 打开web服务: gulp
gulp.task('default', ['hot-reload']);

const fs = require('fs-extra')

const astMap = {
    'wx:if=': 'a:if=',
    'wx:elif=': 'a:elif=',
    'wx:else': 'a:else',
    'wx:for-index=': 'a:for-index=',
    'wx:key=': 'a:key=',
    'wx:for-item=': 'a:for-item=',
    'wx:for=': 'a:for=',
    '<wxs module=': '<import-sjs name=',
    '<wxs src=': '<import-sjs from=',
    '</wxs>': '</import-sjs>',
    '.wxs"': '.sjs"',
    '.wxml"': '.axml"',
    'module="': 'name="',
    'bindtap=': 'onTap=',
    'bindTouchstart=': 'onTouchstart=',
    'bindTouchmove=': 'onTouchmove=',
    'bindTouchcancel=': 'onTouchcancel=',
    'bindTouchend=': 'onTouchend=',
    'bindLongtap=': 'onLongtap=',
    'bindInput=': 'onInput=',
    'bindChange=': 'onChange=',
    'bindSubmit=': 'onSubmit=',
    'bindBlur=': 'onBlur=',
    'bindFocus=': 'onFocus=',
    'bindReset=': 'onReset=',
    'bindConfirm=': 'onConfirm=',
    'bindColumnchange=': 'onColumnchange=',
    'bindLinechange=': 'onLinechange=',
    'bindError=': 'onError=',
    'bindScrolltoupper=': 'onScrolltoupper=',
    'bindScrolltolower=': 'onScrolltolower=',
    'bindScroll=': 'onScroll=',
    'bindLoad=': 'onLoad=',
}

const astMapReg = {}
const astMapKeys = Object.keys(astMap)
astMapKeys.forEach(key => {
    astMapReg[key] = new RegExp(key, 'gi')
})
const transForm = text => {
    astMapKeys.forEach(key => {
        if (text.includes(key)) {
            text = text.replace(astMapReg[key], astMap[key])
        }
    })
    return text
}

const reg = new RegExp(`([1-9]\\d*\\.\\d*)rem|(0\\.\\d*[1-9]\\d*)rem|(\\d*)rem`, 'gi')
function calcRem(file){
    let a = reg.exec(file);
    while (a) {
        let str = a[0]
        let index = a['index']
        let replacedIndex = str.replace('rem', '')
        let completedRem = replacedIndex * 1 / 2.5
        file = file.slice(0, index) + completedRem + 'rem' + file.slice(index + str.length, file.length)
        a = reg.exec(file)
    }
    return file
}

const transFormFileContent = filePath => {
    let fileContent = fs.readFileSync(filePath).toString()
    if (filePath.endsWith('.axml')) {
        fs.unlinkSync(filePath)
        fs.writeFileSync(filePath, transForm(fileContent))
    }
    if (filePath.endsWith('.acss')) {
        fs.unlinkSync(filePath)
        fs.writeFileSync(filePath, calcRem(fileContent))
    }
}

module.exports = {
    transFormFileContent
}

 

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐