@morjs/plugin-compiler-alipay
Version:
mor complier plugin for alipay mini program
151 lines • 7.79 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.getModuleExportsName = void 0;
const utils_1 = require("@morjs/utils");
const constants_1 = require("../constants");
/**
* 从 module.exports.xxx 中提取 xxx 变量名
*/
function getModuleExportsName(content) {
const result = [];
const regex = /module\.exports\.(\w+)/gim;
const matchResult = content.match(regex);
if (!matchResult)
return result;
matchResult.map((param) => {
const name = param.split('.')[2];
result.push(name);
});
return result;
}
exports.getModuleExportsName = getModuleExportsName;
/**
* 支付宝 sjs 文件转译
*/
class AlipayCompilerSjsParserPlugin {
constructor() {
this.name = 'AlipayCompilerSjsParserPlugin';
}
apply(runner) {
runner.hooks.beforeRun.tap(this.name, () => {
const { sourceType, target } = runner.userConfig;
const isAlipaySimilarTarget = (0, constants_1.isSimilarTarget)(target);
// 微信 DSL 转 支付宝或者类似小程序平台时的兼容逻辑
if (sourceType === utils_1.SourceTypes.wechat && isAlipaySimilarTarget) {
return this.transformCommonjsToESModule(runner);
}
// 仅当 sjs 是 支付宝 源码 且 编译目标不是 支付宝小程序 时执行后续逻辑
if (sourceType !== utils_1.SourceTypes.alipay)
return;
if (sourceType === target)
return;
if (isAlipaySimilarTarget)
return;
runner.hooks.beforeBuildEntries.tap(this.name, (entryBuilder) => {
this.entryBuilder = entryBuilder;
});
runner.hooks.sjsParser.tap(this.name, (transformers, options) => {
this.removeEsModuleMarkAndFixVoidZeroExpression(transformers);
if (options.fileInfo.content.includes('import') ||
options.fileInfo.content.includes('export')) {
this.transformESModuleToCommonjs(transformers);
}
return transformers;
});
});
}
/**
* 微信转支付宝的场景下 ,wxs 内联文件中使用 module.exports.property 在支付宝中无法正常通过 name.var 调用,
* 需要将这种场景下的导出进行拓展,增加 export default { property }
* 这样在 webpack 打包时就可以正确导出 export default 文件
* NOTE: 该功能需要配合 cjsToEsmTransformer 使用,并放在 after 阶段
*/
transformCommonjsToESModule(runner) {
runner.hooks.sjsParser.tap(this.name, (transformers, options) => {
if (options.fileInfo.content.includes('module.exports.') &&
!/module.exports( |\t|\n)*=/.test(options.fileInfo.content)) {
// 提取 module.exports.var 中的变量名
const names = getModuleExportsName(options.fileInfo.content);
if (names.length <= 0 || names.indexOf('default') > -1)
return transformers;
transformers.after.push((0, utils_1.tsTransformerFactory)((node, ctx) => {
const factory = ctx.factory;
if (utils_1.typescript.isSourceFile(node)) {
return factory.updateSourceFile(node, [
...node.statements,
factory.createExportAssignment(void 0, void 0, void 0, factory.createObjectLiteralExpression(names.map((name) => factory.createShorthandPropertyAssignment(factory.createIdentifier(name)))))
]);
}
return node;
}));
}
return transformers;
});
}
transformESModuleToCommonjs(transformers) {
transformers.before.push((0, utils_1.tsTransformerFactory)((node, ctx) => {
var _a;
const factory = ctx.factory;
/**
* export {} 替换为 module.exports
*/
if (utils_1.typescript.isExportAssignment(node)) {
const expression = node.expression;
return factory.createExpressionStatement(factory.createBinaryExpression(factory.createPropertyAccessExpression(factory.createIdentifier('module'), factory.createIdentifier('exports')), factory.createToken(utils_1.typescript.SyntaxKind.EqualsToken), expression));
}
/**
* 处理 export default function name() {} 的情况
* 原因: 微信不支持 exports.default = name 这种语法,会报错
* 这里转换为 module.exports = function name() {}
*/
if (utils_1.typescript.isFunctionDeclaration(node) && ((_a = node.modifiers) === null || _a === void 0 ? void 0 : _a.length)) {
const exportKeyword = node.modifiers[0];
const exportDefaultKeyword = node.modifiers[1];
if (utils_1.typescript.isToken(exportKeyword) &&
exportKeyword.kind === utils_1.typescript.SyntaxKind.ExportKeyword &&
utils_1.typescript.isToken(exportDefaultKeyword) &&
exportDefaultKeyword.kind === utils_1.typescript.SyntaxKind.DefaultKeyword) {
return factory.createExpressionStatement(factory.createBinaryExpression(factory.createPropertyAccessExpression(factory.createIdentifier('module'), factory.createIdentifier('exports')), factory.createToken(utils_1.typescript.SyntaxKind.EqualsToken), factory.createFunctionExpression(undefined, node.asteriskToken, node.name, node.typeParameters, node.parameters, node.type, node.body)));
}
}
return node;
}));
}
/**
* 支付宝小程序的 sjs 是 esmodule
* 这里主要是用于处理 esmodule 转换为 commonjs 之后的兼容性问题
*/
removeEsModuleMarkAndFixVoidZeroExpression(transformers) {
transformers.after.push((0, utils_1.tsTransformerFactory)((node, ctx) => {
/**
* 移除表达式:
* Object.defineProperty(exports, "__esModule", { value: true })
*/
if (utils_1.typescript.isExpressionStatement(node) &&
utils_1.typescript.isCallExpression(node.expression) &&
utils_1.typescript.isPropertyAccessExpression(node.expression.expression) &&
utils_1.typescript.isIdentifier(node.expression.expression.expression) &&
node.expression.expression.expression.escapedText === 'Object' &&
utils_1.typescript.isIdentifier(node.expression.expression.name) &&
node.expression.expression.name.escapedText === 'defineProperty' &&
node.expression.arguments.length &&
utils_1.typescript.isIdentifier(node.expression.arguments[0]) &&
node.expression.arguments[0].escapedText === 'exports') {
return undefined;
}
/*
* 在微信的 wxs 中, 存在如下 BUG
* x = a === void 0 ? [] : a 这样的三目运算符会返回 true 而不是表达式中的值
* 经过测试是 void 0 引起的,为了兼容这个问题,统一改为 undefined
*/
if (utils_1.typescript.isVoidExpression(node) &&
utils_1.typescript.isNumericLiteral(node.expression) &&
node.expression.text === '0') {
return ctx.factory.createIdentifier('undefined');
}
return node;
}));
}
}
exports.default = AlipayCompilerSjsParserPlugin;
//# sourceMappingURL=SjsParserPlugin.js.map