新增复用OakComponent的插件支持

This commit is contained in:
pqcqaq 2024-11-16 09:53:59 +08:00
parent 61f5a2c1c1
commit 784f5433d6
3 changed files with 189 additions and 118 deletions

View File

@ -0,0 +1,63 @@
const t = require('@babel/types');
const generate = require('@babel/generator').default;
const { relative, dirname, parse, join } = require('path');
const fs = require('fs');
const { getStatements } = require('../utils/injectGetRender');
module.exports = (babel) => {
return {
visitor: {
ExportDefaultDeclaration(path, state) {
const { declaration } = path.node;
const { cwd, filename } = state;
const { base } = parse(filename);
if (['index.ts', 'index.js'].includes(base) && t.isIdentifier(declaration) && declaration.name === 'OakComponent') {
const dir = dirname(filename);
const statements = getStatements(dir);
const resetRenderFunction = t.arrowFunctionExpression(
[],
t.blockStatement([
...statements
])
);
const newComponent = t.arrowFunctionExpression(
[t.identifier('props')],
t.blockStatement([
t.returnStatement(
t.callExpression(
t.memberExpression(t.identifier('React'), t.identifier('createElement')),
[
t.identifier('OakComponent'),
t.objectExpression([
t.spreadElement(t.identifier('props')),
// #开头的不是identifier而是StringLiteral
t.objectProperty(t.stringLiteral('#resetRender'), resetRenderFunction)
])
]
)
)
])
);
// 输出一下生成的内容:
// const { code } = generate(newComponent);
// console.log(code);
path.replaceWith(
t.exportDefaultDeclaration(newComponent)
);
// 先判断有没有import React没有的话插入
if (!path.findParent(t.File).node.body.some(node => t.isImportDeclaration(node) && node.source.value === 'react')) {
path.insertBefore(t.importDeclaration([t.importDefaultSpecifier(t.identifier('React'))], t.stringLiteral('react')));
}
}
}
}
};
};

View File

@ -4,6 +4,127 @@ const t = require('@babel/types');
const traverse = require('@babel/traverse').default;
const assert = require('assert');
function getStatements(dir) {
// web要根据this.props.width的宽度决定注入web.tsx还是web.pc.tsx
const tsxFile = join(dir, 'web.tsx');
const jsFile = join(dir, 'web.js');
const jsxFile = join(dir, 'web.jsx');
let webDestFile;
if (fs.existsSync(tsxFile)) {
webDestFile = './web.tsx';
}
else if (fs.existsSync(jsFile)) {
webDestFile = './web.js';
}
else if (fs.existsSync(jsxFile)) {
webDestFile = './web.jsx';
}
const acquireWebFileStmt = webDestFile && t.variableDeclaration('const', [
t.variableDeclarator(
t.identifier('oakRenderFn'),
t.memberExpression(
t.callExpression(t.identifier('require'), [
t.stringLiteral(webDestFile),
]),
t.identifier('default')
)
),
]);
let pcDestFile;
const pcTsxFile = join(dir, 'web.pc.tsx');
const pcJsFile = join(dir, 'web.pc.js');
const pcJsxFile = join(dir, 'web.pc.jsx');
if (fs.existsSync(pcTsxFile)) {
pcDestFile = './web.pc.tsx';
}
else if (fs.existsSync(pcJsFile)) {
pcDestFile = './web.pc.js';
}
else if (fs.existsSync(pcJsxFile)) {
pcDestFile = './web.pc.jsx';
}
const acquirePcFileStmt = pcDestFile && t.variableDeclaration('const', [
t.variableDeclarator(
t.identifier('oakRenderFn'),
t.memberExpression(
t.callExpression(t.identifier('require'), [
t.stringLiteral(pcDestFile),
]),
t.identifier('default')
)
),
]);
const getStatementsInner = () => {
/** tsxgetRender
* if (this.props.width === 'xs') {
const oakRenderFn = require('./web.tsx').default;
return oakRenderFn;
}
else {
const oakRenderFn = require('./web.pc.tsx').default;
return oakRenderFn;
}
*/
const statements = [];
if (acquirePcFileStmt && acquireWebFileStmt) {
statements.push(
t.ifStatement(
t.binaryExpression(
'===',
t.memberExpression(
t.memberExpression(
t.thisExpression(),
t.identifier('props')
),
t.identifier('width')
),
t.stringLiteral('xs')
),
t.blockStatement([
acquireWebFileStmt,
t.returnStatement(
t.identifier('oakRenderFn')
)
]),
t.blockStatement([
acquirePcFileStmt,
t.returnStatement(
t.identifier('oakRenderFn')
)
])
)
);
}
else if (acquirePcFileStmt) {
statements.push(
acquirePcFileStmt,
t.returnStatement(
t.identifier('oakRenderFn')
)
);
}
else if (acquireWebFileStmt) {
statements.push(
acquireWebFileStmt,
t.returnStatement(
t.identifier('oakRenderFn')
)
);
} else {
assert(
false,
`${dir}文件夹中不存在web.tsx或者web.pc.tsx无法渲染`
);
}
return statements;
};
return getStatementsInner();
}
/**
*
* @param {*} node
@ -15,123 +136,7 @@ function injectGetRender(node, projectRoot, filename, env) {
assert(t.isCallExpression(node) && t.isIdentifier(node.callee) && node.callee.name === 'OakComponent');
const dir = dirname(filename);
if (env === 'web') {
// web要根据this.props.width的宽度决定注入web.tsx还是web.pc.tsx
const tsxFile = join(dir, 'web.tsx');
const jsFile = join(dir, 'web.js');
const jsxFile = join(dir, 'web.jsx');
let webDestFile;
if (fs.existsSync(tsxFile)) {
webDestFile = './web.tsx';
}
else if (fs.existsSync(jsFile)) {
webDestFile = './web.js';
}
else if (fs.existsSync(jsxFile)) {
webDestFile = './web.jsx';
}
const acquireWebFileStmt = webDestFile && t.variableDeclaration('const', [
t.variableDeclarator(
t.identifier('oakRenderFn'),
t.memberExpression(
t.callExpression(t.identifier('require'), [
t.stringLiteral(webDestFile),
]),
t.identifier('default')
)
),
]);
let pcDestFile;
const pcTsxFile = join(dir, 'web.pc.tsx');
const pcJsFile = join(dir, 'web.pc.js');
const pcJsxFile = join(dir, 'web.pc.jsx');
if (fs.existsSync(pcTsxFile)) {
pcDestFile = './web.pc.tsx';
}
else if (fs.existsSync(pcJsFile)) {
pcDestFile = './web.pc.js';
}
else if (fs.existsSync(pcJsxFile)) {
pcDestFile = './web.pc.jsx';
}
const acquirePcFileStmt = pcDestFile && t.variableDeclaration('const', [
t.variableDeclarator(
t.identifier('oakRenderFn'),
t.memberExpression(
t.callExpression(t.identifier('require'), [
t.stringLiteral(pcDestFile),
]),
t.identifier('default')
)
),
]);
const getStatements = () => {
/** tsxgetRender
* if (this.props.width === 'xs') {
const oakRenderFn = require('./web.tsx').default;
return oakRenderFn;
}
else {
const oakRenderFn = require('./web.pc.tsx').default;
return oakRenderFn;
}
*/
const statements = [];
if (acquirePcFileStmt && acquireWebFileStmt) {
statements.push(
t.ifStatement(
t.binaryExpression(
'===',
t.memberExpression(
t.memberExpression(
t.thisExpression(),
t.identifier('props')
),
t.identifier('width')
),
t.stringLiteral('xs')
),
t.blockStatement([
acquireWebFileStmt,
t.returnStatement(
t.identifier('oakRenderFn')
)
]),
t.blockStatement([
acquirePcFileStmt,
t.returnStatement(
t.identifier('oakRenderFn')
)
])
)
);
}
else if (acquirePcFileStmt) {
statements.push(
acquirePcFileStmt,
t.returnStatement(
t.identifier('oakRenderFn')
)
);
}
else if (acquireWebFileStmt) {
statements.push(
acquireWebFileStmt,
t.returnStatement(
t.identifier('oakRenderFn')
)
);
} else {
assert(
false,
`${dir}文件夹中不存在web.tsx或者web.pc.tsx无法渲染`
);
}
return statements;
};
const statements = getStatements();
const statements = getStatements(dir);
node.arguments.forEach((node4) => {
if (t.isObjectExpression(node4)) {
const propertyRender = t.objectProperty(
@ -195,5 +200,6 @@ function injectGetRender(node, projectRoot, filename, env) {
}
module.exports = {
injectGetRender
injectGetRender,
getStatements
};

View File

@ -34,6 +34,7 @@ const oakRenderTsxPlugin = require('../babel-plugin/oakRender');
const oakI18nPlugin = require('../babel-plugin/oakI18n');
const oakStylePlugin = require('../babel-plugin/oakStyle');
const oakRpxToPxPlugin = require('../postcss-plugin/oakRpxToPx');
const reuseOakComponentPlugin = require('../babel-plugin/reuse-oak-component');
// Source maps are resource heavy and can cause out of memory issue for large source files.
const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== 'false';
@ -582,6 +583,7 @@ module.exports = function (webpackEnv) {
oakRenderTsxPlugin,
// oakRouterPlugin,
oakI18nPlugin,
reuseOakComponentPlugin,
// [
// 'import',
// {