@tarojs/plugin-generator
Version:
Taro 生成器插件
357 lines (356 loc) • 17.6 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.processViteConfig = exports.updateConfig = void 0;
/* eslint-disable no-console */
const generator_1 = __importDefault(require("@babel/generator"));
const parser = __importStar(require("@babel/parser"));
const traverse_1 = __importDefault(require("@babel/traverse"));
const t = __importStar(require("@babel/types"));
const dedent_1 = __importDefault(require("dedent"));
const error_1 = require("../../utils/error");
async function updateConfig(options) {
const { ctx, compilerType } = options;
const { fs } = ctx.helper;
const sourceCode = await fs.readFile(ctx.paths.configPath, { encoding: 'utf-8' });
const ast = parser.parse(sourceCode, {
sourceType: 'module',
plugins: ['typescript'],
});
if (compilerType === 'webpack5') {
processWebpack5Config(ast);
}
else if (compilerType === 'vite') {
processViteConfig(ast);
}
const { code: latestConfig } = (0, generator_1.default)(ast);
await fs.writeFile(ctx.paths.configPath, latestConfig, { encoding: 'utf-8' });
console.log('✅ 更新配置文件成功\n');
}
exports.updateConfig = updateConfig;
function processImportDecl(ast, pkgMap) {
const alias = new Map();
const importedModule = new Map();
(0, traverse_1.default)(ast, {
ImportDeclaration(path) {
const importFrom = path.node.source.value;
if (pkgMap.has(importFrom)) {
importedModule.set(importFrom, path.node);
const specifiers = path.node.specifiers;
const importNames = pkgMap.get(importFrom);
if (!importNames)
return;
for (const specifier of specifiers) {
if (t.isImportDefaultSpecifier(specifier)) {
if (importNames.defaultImport) {
alias.set(specifier.local.name, importNames.defaultImport);
Reflect.deleteProperty(importNames, 'defaultImport');
}
}
if (importNames.namedImport) {
if (importNames.namedImport.size === 0) {
Reflect.deleteProperty(importNames, 'namedImport');
continue;
}
if (t.isImportSpecifier(specifier) && t.isIdentifier(specifier.imported)) {
const importName = specifier.imported.name;
const localName = specifier.local?.name ?? importName;
alias.set(importName, localName);
if (importNames.namedImport.has(importName)) {
importNames.namedImport.delete(importName);
}
}
}
}
}
},
Program: {
exit(path) {
for (const [moduleName, { namedImport, defaultImport }] of pkgMap) {
if (defaultImport) {
if (importedModule.get(moduleName)) {
const importDecl = importedModule.get(moduleName);
importDecl?.specifiers.unshift(t.importDefaultSpecifier(t.identifier(defaultImport)));
}
else {
path.node.body.unshift(t.importDeclaration([t.importDefaultSpecifier(t.identifier(defaultImport))], t.stringLiteral(moduleName)));
}
}
if (namedImport && namedImport.size > 0) {
// 需要从已有的导入语句追加
if (importedModule.get(moduleName)) {
const importDecl = importedModule.get(moduleName);
for (const importName of namedImport) {
importDecl?.specifiers.push(t.importSpecifier(t.identifier(importName), t.identifier(importName)));
}
}
else {
path.node.body.unshift(t.importDeclaration(Array.from(namedImport).map((importName) => t.importSpecifier(t.identifier(importName), t.identifier(importName))), t.stringLiteral(moduleName)));
}
}
}
},
},
});
return alias;
}
function processWebpack5Config(ast) {
const fromModule = 'weapp-tailwindcss/webpack';
const importName = 'UnifiedWebpackPluginV5';
const alias = processImportDecl(ast, new Map([[fromModule, { namedImport: new Set([importName]) }]]));
let updated = false;
(0, traverse_1.default)(ast, {
VariableDeclarator(path) {
const { node } = path;
if (t.isIdentifier(node.id, { name: 'baseConfig' }) && t.isObjectExpression(node.init)) {
(0, traverse_1.default)(node.init, {
ObjectProperty: (prop) => {
if (t.isIdentifier(prop.node.key, { name: 'mini' }) && t.isObjectExpression(prop.node.value)) {
const props = prop.node.value.properties;
const webpackChainMethod = props.find((p) => t.isObjectMethod(p) && t.isIdentifier(p.key, { name: 'webpackChain' }));
const installPluginCode = (0, dedent_1.default)(`
chain.merge({
plugin: {
install: {
plugin: UnifiedWebpackPluginV5,
args: [{
// 这里可以传参数
rem2rpx: true,
}]
}
}
})
`);
const installPluginStmt = parser.parseExpression(installPluginCode);
let pluginAlreadyExists = false;
// 存在 webpackChain 方法
if (webpackChainMethod) {
for (const stmt of webpackChainMethod.body.body) {
if (t.isExpressionStatement(stmt) &&
t.isCallExpression(stmt.expression) &&
t.isMemberExpression(stmt.expression.callee) &&
t.isIdentifier(stmt.expression.callee.object, { name: 'chain' }) &&
t.isIdentifier(stmt.expression.callee.property, { name: 'merge' })) {
const [arg] = stmt.expression.arguments;
if (t.isObjectExpression(arg)) {
for (const prop of arg.properties) {
if (t.isObjectProperty(prop) &&
t.isIdentifier(prop.key, { name: 'plugin' }) &&
t.isObjectExpression(prop.value)) {
const installProp = prop.value.properties.find((p) => t.isObjectProperty(p) &&
t.isIdentifier(p.key, { name: 'install' }) &&
t.isObjectExpression(p.value) &&
p.value.properties.some((ip) => t.isObjectProperty(ip) &&
t.isIdentifier(ip.key, { name: 'plugin' }) &&
t.isIdentifier(ip.value, { name: alias.get(importName) ?? importName })));
if (installProp) {
pluginAlreadyExists = true;
}
}
}
}
}
}
if (!pluginAlreadyExists) {
webpackChainMethod.body.body.push(t.expressionStatement(installPluginStmt));
}
}
else {
// 没有 webpackChain 方法则添加
prop.node.value.properties.push(t.objectMethod('method', t.identifier('webpackChain'), [t.identifier('chain'), t.identifier('webpack')], t.blockStatement([t.expressionStatement(installPluginStmt)]), false, false));
}
updated = true;
prop.stop();
}
},
}, path.scope);
path.stop();
}
},
});
if (!updated) {
throw new error_1.GeneratorError({
type: error_1.GeneratorErrorType.modifyConfig,
message: (0, dedent_1.default)(`
import { UnifiedWebpackPluginV5 } from 'weapp-tailwindcss/webpack'
{
// 找到 mini 这个配置
mini: {
// postcss: { /*...*/ },
// 中的 webpackChain, 通常紧挨着 postcss
webpackChain(chain, webpack) {
// 复制这块区域到你的配置代码中
chain.merge({
plugin: {
install: {
plugin: UnifiedWebpackPluginV5,
args: [{
// 这里可以传参数
rem2rpx: true,
}]
}
}
})
}
}
}
`),
});
}
}
function processViteConfig(ast) {
const weappTailwindCSS = 'weapp-tailwindcss/vite';
const tailwindcss = '@tailwindcss/postcss';
const importPluginName = 'UnifiedViteWeappTailwindcssPlugin';
const importTailwindcss = 'tailwindcss';
const alias = processImportDecl(ast, new Map([
[weappTailwindCSS, { namedImport: new Set([importPluginName]) }],
[tailwindcss, { defaultImport: importTailwindcss }],
]));
function createUnifiedVitePluginNode() {
const code = `
${alias.get(importPluginName) ?? importPluginName}({
// rem转rpx
rem2rpx: true,
// 除了小程序这些,其他平台都 disable
disabled: process.env.TARO_ENV === 'h5' || process.env.TARO_ENV === 'harmony' || process.env.TARO_ENV === 'rn',
// 由于 taro vite 默认会移除所有的 tailwindcss css 变量,所以一定要开启这个配置,进行css 变量的重新注入
injectAdditionalCssVarScope: true,
})
`;
return parser.parseExpression(code);
}
function createPostcssPluginNode() {
const code = `
{
name: 'postcss-config-loader-plugin',
config(config) {
// 加载 tailwindcss
if (typeof config.css?.postcss === 'object') {
config.css?.postcss.plugins?.unshift(tailwindcss())
}
},
}
`;
return parser.parseExpression(code);
}
let updated = false;
(0, traverse_1.default)(ast, {
VariableDeclarator(path) {
const { node } = path;
if (t.isIdentifier(node.id, { name: 'baseConfig' }) && t.isObjectExpression(node.init)) {
(0, traverse_1.default)(node.init, {
ObjectProperty: (prop) => {
if (!t.isIdentifier(prop.node.key, { name: 'compiler' }))
return;
// compiler: 'vite' => 替换为对象 compiler: { type: 'vite', ... }
if (t.isStringLiteral(prop.node.value, { value: 'vite' })) {
prop.node.value = t.objectExpression([
t.objectProperty(t.identifier('type'), t.stringLiteral('vite')),
t.objectProperty(t.identifier('vitePlugins'), t.arrayExpression([createPostcssPluginNode(), createUnifiedVitePluginNode()])),
]);
updated = true;
prop.stop();
return;
}
// compiler: { type: 'vite', ... }
if (t.isObjectExpression(prop.node.value)) {
const compilerProps = prop.node.value.properties;
let vitePluginsProp;
for (const p of compilerProps) {
if (t.isObjectProperty(p) &&
t.isIdentifier(p.key, { name: 'vitePlugins' }) &&
t.isArrayExpression(p.value)) {
vitePluginsProp = p;
break;
}
}
if (!vitePluginsProp) {
compilerProps.push(t.objectProperty(t.identifier('vitePlugins'), t.arrayExpression([createPostcssPluginNode(), createUnifiedVitePluginNode()])));
updated = true;
prop.stop();
return;
}
if (!t.isArrayExpression(vitePluginsProp.value))
return;
const elements = vitePluginsProp.value.elements;
const hasPostcssPlugin = elements.some((el) => t.isObjectExpression(el) &&
el.properties.some((prop) => t.isObjectProperty(prop) &&
t.isIdentifier(prop.key, { name: 'name' }) &&
t.isStringLiteral(prop.value, { value: 'postcss-config-loader-plugin' })));
const hasUnifiedPlugin = elements.some((el) => t.isCallExpression(el) &&
t.isIdentifier(el.callee, { name: alias.get(importPluginName) ?? importPluginName }));
if (!hasPostcssPlugin) {
elements.unshift(createPostcssPluginNode());
}
if (!hasUnifiedPlugin) {
elements.push(createUnifiedVitePluginNode());
}
updated = true;
prop.stop();
}
},
}, path.scope);
path.stop();
}
},
});
if (!updated) {
throw new error_1.GeneratorError({
type: error_1.GeneratorErrorType.modifyConfig,
message: (0, dedent_1.default)(`
import tailwindcss from 'tailwindcss';
import { UnifiedViteWeappTailwindcssPlugin } from 'weapp-tailwindcss/vite'
{
// ... 其他配置
compiler: {
type: 'vite',
vitePlugins: [
{
name: 'postcss-config-loader-plugin',
config(config) {
if (typeof config.css?.postcss === 'object') {
config.css?.postcss.plugins?.unshift(tailwindcss())
}
},
},
UnifiedViteWeappTailwindcssPlugin({
rem2rpx: true,
disabled: process.env.TARO_ENV === 'h5' || process.env.TARO_ENV === 'harmony' || process.env.TARO_ENV === 'rn',
injectAdditionalCssVarScope: true,
})
]
// ... 其他配置
}
}
`),
});
}
}
exports.processViteConfig = processViteConfig;
//# sourceMappingURL=config.js.map