H5-contact/node_modules/@dcloudio/uni-cli-shared/dist/mp/usingComponents.js

452 lines
18 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.transformDynamicImports = exports.parseScriptDescriptor = exports.parseTemplateDescriptor = exports.updateMiniProgramComponentsByMainFilename = exports.updateMiniProgramGlobalComponents = exports.updateMiniProgramComponentsByTemplateFilename = exports.updateMiniProgramComponentsByScriptFilename = exports.parseMainDescriptor = exports.getGlobalComponentSource = void 0;
const types_1 = require("@babel/types");
const estree_walker_1 = require("estree-walker");
const magic_string_1 = __importDefault(require("magic-string"));
const shared_1 = require("@vue/shared");
const uni_shared_1 = require("@dcloudio/uni-shared");
const messages_1 = require("../messages");
const constants_1 = require("../constants");
const utils_1 = require("../utils");
const utils_2 = require("../vite/utils");
const jsonFile_1 = require("../json/mp/jsonFile");
const subpackage_1 = require("../json/mp/subpackage");
const mainDescriptors = new Map();
const scriptDescriptors = new Map();
const templateDescriptors = new Map();
const scriptDescriptorMainMap = new Map();
const templateDescriptorMainMap = new Map();
// 存储全局组件名到完整源文件路径的映射
const globalComponentSourceMap = new Map();
function getGlobalComponentSource(componentName) {
return globalComponentSourceMap.get(componentName);
}
exports.getGlobalComponentSource = getGlobalComponentSource;
function findImportTemplateSource(ast) {
const importDeclaration = ast.body.find((node) => (0, types_1.isImportDeclaration)(node) &&
node.source.value.includes('vue&type=template'));
if (importDeclaration) {
return importDeclaration.source.value;
}
}
function findImportScriptSource(ast) {
const importDeclaration = ast.body.find((node) => (0, types_1.isImportDeclaration)(node) && node.source.value.includes('vue&type=script'));
if (importDeclaration) {
return importDeclaration.source.value;
}
}
async function resolveSource(filename, source, resolve, root) {
if (!source) {
return;
}
const resolveId = await resolve(source, root ? (0, subpackage_1.withIndependentRoot)(filename, root) : filename);
if (resolveId) {
return resolveId.id;
}
}
async function parseMainDescriptor(filename, ast, resolve, root) {
const script = await resolveSource(filename, findImportScriptSource(ast), resolve, root);
const template = await resolveSource(filename, findImportTemplateSource(ast), resolve, root);
const imports = await parseVueComponentImports(root ? (0, subpackage_1.withIndependentRoot)(filename, root) : filename, ast.body.filter((node) => (0, types_1.isImportDeclaration)(node)), resolve);
if (!script) {
// inline script
await parseScriptDescriptor(filename, ast, {
resolve,
isExternal: false,
root,
});
}
if (!template) {
// inline template
await parseTemplateDescriptor(filename, ast, {
resolve,
isExternal: false,
root,
});
}
const descriptor = {
imports,
script: script
? createDescriptorKey((0, utils_2.parseVueRequest)(script).filename, (0, subpackage_1.parseIndependentRoot)(script) || root)
: createDescriptorKey(filename, root),
template: template
? createDescriptorKey((0, utils_2.parseVueRequest)(template).filename, (0, subpackage_1.parseIndependentRoot)(template) || root)
: createDescriptorKey(filename, root),
};
const mainDescriptorKey = createDescriptorKey(filename, root);
updateMainDescriptorIndex(mainDescriptorKey, descriptor);
return descriptor;
}
exports.parseMainDescriptor = parseMainDescriptor;
function updateMainDescriptorIndex(mainDescriptorKey, descriptor) {
const oldDescriptor = mainDescriptors.get(mainDescriptorKey);
if (oldDescriptor && oldDescriptor.script !== descriptor.script) {
scriptDescriptorMainMap.delete(oldDescriptor.script);
}
if (oldDescriptor && oldDescriptor.template !== descriptor.template) {
templateDescriptorMainMap.delete(oldDescriptor.template);
}
mainDescriptors.set(mainDescriptorKey, descriptor);
scriptDescriptorMainMap.set(descriptor.script, mainDescriptorKey);
templateDescriptorMainMap.set(descriptor.template, mainDescriptorKey);
}
function updateMiniProgramComponentsByScriptFilename(scriptFilename, inputDir, normalizeComponentName, root) {
const mainFilename = findMainFilenameByScriptFilename(createDescriptorKey(scriptFilename, root));
if (mainFilename) {
updateMiniProgramComponentsByMainFilename(mainFilename, inputDir, normalizeComponentName, root);
}
}
exports.updateMiniProgramComponentsByScriptFilename = updateMiniProgramComponentsByScriptFilename;
function updateMiniProgramComponentsByTemplateFilename(templateFilename, inputDir, normalizeComponentName, root) {
const mainFilename = findMainFilenameByTemplateFilename(createDescriptorKey(templateFilename, root));
if (mainFilename) {
updateMiniProgramComponentsByMainFilename(mainFilename, inputDir, normalizeComponentName, root);
}
}
exports.updateMiniProgramComponentsByTemplateFilename = updateMiniProgramComponentsByTemplateFilename;
function findMainFilenameByScriptFilename(scriptFilename) {
return scriptDescriptorMainMap.get(scriptFilename);
}
function findMainFilenameByTemplateFilename(templateFilename) {
return templateDescriptorMainMap.get(templateFilename);
}
async function updateMiniProgramGlobalComponents(filename, ast, { inputDir, resolve, normalizeComponentName, root, }) {
const { bindingComponents, imports } = await parseGlobalDescriptor(filename, ast, resolve, root);
// 存储全局组件名到完整源文件路径的映射
imports.forEach(({ source: { value }, specifiers: [specifier] }) => {
const { name } = specifier.local;
if (!bindingComponents[name]) {
return;
}
if (!globalComponentSourceMap.has(bindingComponents[name].tag)) {
globalComponentSourceMap.set(bindingComponents[name].tag, (0, subpackage_1.withoutIndependentRoot)(value));
}
});
(0, jsonFile_1.addMiniProgramUsingComponents)('app', createUsingComponents(bindingComponents, imports, inputDir, normalizeComponentName));
return {
imports,
};
}
exports.updateMiniProgramGlobalComponents = updateMiniProgramGlobalComponents;
function createUsingComponents(bindingComponents, imports, inputDir, normalizeComponentName) {
const usingComponents = {};
imports.forEach(({ source: { value }, specifiers: [specifier] }) => {
const { name } = specifier.local;
if (!bindingComponents[name]) {
return;
}
const componentName = normalizeComponentName((0, shared_1.hyphenate)(bindingComponents[name].tag));
if (!usingComponents[componentName]) {
usingComponents[componentName] = (0, uni_shared_1.addLeadingSlash)((0, utils_1.removeExt)((0, utils_1.normalizeMiniProgramFilename)((0, subpackage_1.withoutIndependentRoot)(value), inputDir)));
}
});
return usingComponents;
}
function updateMiniProgramComponentsByMainFilename(mainFilename, inputDir, normalizeComponentName, root) {
const mainDescriptor = mainDescriptors.get(createDescriptorKey(mainFilename, root));
if (!mainDescriptor) {
return;
}
const templateDescriptor = templateDescriptors.get(mainDescriptor.template);
if (!templateDescriptor) {
return;
}
const scriptDescriptor = scriptDescriptors.get(mainDescriptor.script);
if (!scriptDescriptor) {
return;
}
const bindingComponents = parseBindingComponents({
...templateDescriptor.bindingComponents,
...scriptDescriptor.setupBindingComponents,
}, scriptDescriptor.bindingComponents);
const imports = parseImports(mainDescriptor.imports, scriptDescriptor.imports, templateDescriptor.imports);
(0, jsonFile_1.addMiniProgramUsingComponents)((0, utils_1.removeExt)((0, utils_1.normalizeMiniProgramFilename)((0, subpackage_1.withoutIndependentRoot)(mainFilename), inputDir)), createUsingComponents(bindingComponents, imports, inputDir, normalizeComponentName));
}
exports.updateMiniProgramComponentsByMainFilename = updateMiniProgramComponentsByMainFilename;
function findBindingComponent(tag, bindingComponents) {
return Object.keys(bindingComponents).find((name) => {
const componentTag = bindingComponents[name].tag;
const camelName = (0, shared_1.camelize)(componentTag);
const PascalName = (0, shared_1.capitalize)(camelName);
return tag === componentTag || tag === camelName || tag === PascalName;
});
}
function normalizeComponentId(id) {
// _unref(test) => test
if (id.includes('_unref(')) {
return id.replace('_unref(', '').replace(')', '');
}
// $setup["test"] => test
if (id.includes('$setup[')) {
return id.replace('$setup["', '').replace('"', '');
}
return id;
}
function parseBindingComponents(templateBindingComponents, scriptBindingComponents) {
const bindingComponents = {};
Object.keys(templateBindingComponents).forEach((id) => {
bindingComponents[normalizeComponentId(id)] = templateBindingComponents[id];
});
Object.keys(scriptBindingComponents).forEach((id) => {
const { tag } = scriptBindingComponents[id];
const name = findBindingComponent(tag, templateBindingComponents);
if (name) {
bindingComponents[id] = bindingComponents[name];
}
});
return bindingComponents;
}
function parseImports(mainImports, scriptImports, templateImports) {
const imports = [...mainImports, ...templateImports, ...scriptImports];
return imports;
}
/**
* 解析 template
* @param filename
* @param code
* @param ast
* @param options
* @returns
*/
async function parseTemplateDescriptor(filename, ast, options) {
// 外置时查找所有 vue component import
const imports = options.isExternal
? await parseVueComponentImports(options.root ? (0, subpackage_1.withIndependentRoot)(filename, options.root) : filename, ast.body.filter((node) => (0, types_1.isImportDeclaration)(node)), options.resolve)
: [];
const descriptor = {
bindingComponents: findBindingComponents(ast.body),
imports,
};
templateDescriptors.set(createDescriptorKey(filename, options.root), descriptor);
return descriptor;
}
exports.parseTemplateDescriptor = parseTemplateDescriptor;
async function parseGlobalDescriptor(filename, ast, resolve, root) {
// 外置时查找所有 vue component import
const imports = (await parseVueComponentImports(root ? (0, subpackage_1.withIndependentRoot)(filename, root) : filename, ast.body.filter((node) => (0, types_1.isImportDeclaration)(node)), resolve)).filter((item) => !(0, utils_1.isAppVue)((0, utils_2.cleanUrl)(item.source.value)));
return {
bindingComponents: parseGlobalComponents(ast),
imports,
};
}
/**
* 解析 script
* @param filename
* @param code
* @param ast
* @param options
* @returns
*/
async function parseScriptDescriptor(filename, ast, options) {
// 外置时查找所有 vue component import
const imports = options.isExternal
? await parseVueComponentImports(options.root ? (0, subpackage_1.withIndependentRoot)(filename, options.root) : filename, ast.body.filter((node) => (0, types_1.isImportDeclaration)(node)), options.resolve)
: [];
const descriptor = {
bindingComponents: parseComponents(ast),
setupBindingComponents: findBindingComponents(ast.body),
imports,
};
scriptDescriptors.set(createDescriptorKey(filename, options.root), descriptor);
return descriptor;
}
exports.parseScriptDescriptor = parseScriptDescriptor;
/**
* 解析编译器生成的 bindingComponents
* @param ast
* @returns
*/
function findBindingComponents(ast) {
const mapping = findUnpluginComponents(ast);
for (const node of ast) {
if (!(0, types_1.isVariableDeclaration)(node)) {
continue;
}
const declarator = node.declarations[0];
if ((0, types_1.isIdentifier)(declarator.id) &&
declarator.id.name === constants_1.BINDING_COMPONENTS) {
const bindingComponents = JSON.parse(declarator.init.value);
return Object.keys(bindingComponents).reduce((bindings, tag) => {
const { name, type } = bindingComponents[tag];
bindings[mapping[name] || name] = {
tag,
type: type,
};
return bindings;
}, {});
}
}
return {};
}
/**
* 兼容unplugin_components
* https://github.com/dcloudio/uni-app/issues/3057
* @param ast
* @returns
*/
function findUnpluginComponents(ast) {
const res = Object.create(null);
// if(!Array){}
const ifStatement = ast.find((statement) => (0, types_1.isIfStatement)(statement) &&
(0, types_1.isUnaryExpression)(statement.test) &&
statement.test.operator === '!' &&
(0, types_1.isIdentifier)(statement.test.argument) &&
statement.test.argument.name === 'Array');
if (!ifStatement) {
return res;
}
if (!(0, types_1.isBlockStatement)(ifStatement.consequent)) {
return res;
}
for (const node of ifStatement.consequent.body) {
if (!(0, types_1.isVariableDeclaration)(node)) {
continue;
}
const { id, init } = node.declarations[0];
if ((0, types_1.isIdentifier)(id) &&
(0, types_1.isIdentifier)(init) &&
init.name.includes('unplugin_components')) {
res[id.name] = init.name;
}
}
return res;
}
/**
* 查找全局组件定义app.component('component-a',{})
* @param ast
* @returns
*/
function parseGlobalComponents(ast) {
const bindingComponents = {};
estree_walker_1.walk(ast, {
enter(child) {
if (!(0, types_1.isCallExpression)(child)) {
return;
}
const { callee } = child;
// .component
if (!(0, types_1.isMemberExpression)(callee) ||
!(0, types_1.isIdentifier)(callee.property) ||
callee.property.name !== 'component') {
return;
}
// .component('component-a',{})
const args = child.arguments;
if (args.length !== 2) {
return;
}
const [name, value] = args;
if (!(0, types_1.isStringLiteral)(name)) {
return console.warn(messages_1.M['mp.component.args[0]'].replace('{0}', 'app.component'));
}
if (!(0, types_1.isIdentifier)(value)) {
return console.warn(messages_1.M['mp.component.args[1]'].replace('{0}', 'app.component'));
}
bindingComponents[value.name] = {
tag: name.value,
type: 'unknown',
};
},
});
return bindingComponents;
}
/**
* 从 components 中查找定义的组件
* @param ast
* @param bindingComponents
*/
function parseComponents(ast) {
const bindingComponents = {};
estree_walker_1.walk(ast, {
enter(child) {
if (!(0, types_1.isObjectExpression)(child)) {
return;
}
const componentsProp = child.properties.find((prop) => (0, types_1.isObjectProperty)(prop) &&
(0, types_1.isIdentifier)(prop.key) &&
prop.key.name === 'components');
if (!componentsProp) {
return;
}
const componentsExpr = componentsProp.value;
if (!(0, types_1.isObjectExpression)(componentsExpr)) {
return;
}
componentsExpr.properties.forEach((prop) => {
if (!(0, types_1.isObjectProperty)(prop)) {
return;
}
if (!(0, types_1.isIdentifier)(prop.key) && !(0, types_1.isStringLiteral)(prop.key)) {
return;
}
if (!(0, types_1.isIdentifier)(prop.value)) {
return;
}
bindingComponents[prop.value.name] = {
tag: (0, types_1.isIdentifier)(prop.key) ? prop.key.name : prop.key.value,
type: 'unknown',
};
});
},
});
return bindingComponents;
}
/**
* vue component imports
* @param filename
* @param imports
* @param resolve
* @returns
*/
async function parseVueComponentImports(importer, imports, resolve) {
const vueComponentImports = [];
for (let i = 0; i < imports.length; i++) {
const { source } = imports[i];
if ((0, utils_2.parseVueRequest)(source.value).query.vue) {
continue;
}
const resolveId = await resolve(source.value, importer);
if (!resolveId) {
continue;
}
const { filename } = (0, utils_2.parseVueRequest)(resolveId.id);
if (constants_1.EXTNAME_VUE_RE.test(filename)) {
source.value = resolveId.id;
vueComponentImports.push(imports[i]);
}
}
return vueComponentImports;
}
function createDescriptorKey(filename, root) {
return root ? (0, subpackage_1.withIndependentRoot)(filename, root) : filename;
}
/**
* static import => dynamic import
* @param code
* @param imports
* @param dynamicImport
* @returns
*/
async function transformDynamicImports(code, imports, { id, sourceMap, dynamicImport, }) {
if (!imports.length) {
return {
code,
map: null,
};
}
const s = new magic_string_1.default(code);
for (let i = 0; i < imports.length; i++) {
const { start, end, specifiers: [specifier], source, } = imports[i];
s.overwrite(start, end, dynamicImport(specifier.local.name, source.value) + ';');
}
return {
code: s.toString(),
map: null,
};
}
exports.transformDynamicImports = transformDynamicImports;