easycom.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. "use strict";
  2. var __importDefault = (this && this.__importDefault) || function (mod) {
  3. return (mod && mod.__esModule) ? mod : { "default": mod };
  4. };
  5. Object.defineProperty(exports, "__esModule", { value: true });
  6. exports.genUTSComponentPublicInstanceImported = exports.genUTSComponentPublicInstanceIdent = exports.addUTSEasyComAutoImports = exports.getUTSEasyComAutoImports = exports.UNI_EASYCOM_EXCLUDE = exports.genResolveEasycomCode = exports.addImportDeclaration = exports.matchEasycom = exports.initEasycomsOnce = exports.initEasycoms = void 0;
  7. const fs_1 = __importDefault(require("fs"));
  8. const path_1 = __importDefault(require("path"));
  9. const debug_1 = __importDefault(require("debug"));
  10. const shared_1 = require("@vue/shared");
  11. const pluginutils_1 = require("@rollup/pluginutils");
  12. const uni_shared_1 = require("@dcloudio/uni-shared");
  13. const utils_1 = require("./utils");
  14. const pages_1 = require("./json/pages");
  15. const messages_1 = require("./messages");
  16. const uts_1 = require("./uts");
  17. const debugEasycom = (0, debug_1.default)('uni:easycom');
  18. const easycoms = [];
  19. const easycomsCache = new Map();
  20. const easycomsInvalidCache = new Set();
  21. let hasEasycom = false;
  22. function clearEasycom() {
  23. easycoms.length = 0;
  24. easycomsCache.clear();
  25. easycomsInvalidCache.clear();
  26. }
  27. function initEasycoms(inputDir, { dirs, platform, isX, }) {
  28. const componentsDir = path_1.default.resolve(inputDir, 'components');
  29. const uniModulesDir = path_1.default.resolve(inputDir, 'uni_modules');
  30. const initEasycomOptions = (pagesJson) => {
  31. // 初始化时,从once中读取缓存,refresh时,实时读取
  32. const { easycom } = pagesJson || (0, pages_1.parsePagesJson)(inputDir, platform, false);
  33. const easycomOptions = {
  34. isX,
  35. dirs: easycom && easycom.autoscan === false
  36. ? [...dirs] // 禁止自动扫描
  37. : [
  38. ...dirs,
  39. componentsDir,
  40. ...initUniModulesEasycomDirs(uniModulesDir),
  41. ],
  42. rootDir: inputDir,
  43. autoscan: !!(easycom && easycom.autoscan),
  44. custom: (easycom && easycom.custom) || {},
  45. extensions: [...(isX ? ['.uvue'] : []), ...['.vue', '.jsx', '.tsx']],
  46. };
  47. debugEasycom(easycomOptions);
  48. return easycomOptions;
  49. };
  50. const options = initEasycomOptions((0, pages_1.parsePagesJsonOnce)(inputDir, platform));
  51. const initUTSEasycom = () => {
  52. (0, uts_1.initUTSComponents)(inputDir, platform).forEach((item) => {
  53. const index = easycoms.findIndex((easycom) => item.name === easycom.name);
  54. if (index > -1) {
  55. easycoms.splice(index, 1, item);
  56. }
  57. else {
  58. easycoms.push(item);
  59. }
  60. });
  61. if (isX && globalThis.uts2jsSourceCodeMap) {
  62. ;
  63. globalThis.uts2jsSourceCodeMap.initUts2jsEasycom(easycoms);
  64. }
  65. };
  66. initEasycom(options);
  67. initUTSEasycom();
  68. const componentExtNames = isX ? 'uvue|vue' : 'vue';
  69. const res = {
  70. options,
  71. filter: (0, pluginutils_1.createFilter)([
  72. 'components/*/*.(' + componentExtNames + '|jsx|tsx)',
  73. 'uni_modules/*/components/*/*.(' + componentExtNames + '|jsx|tsx)',
  74. 'utssdk/*/**/*.(' + componentExtNames + ')',
  75. 'uni_modules/*/utssdk/*/*.(' + componentExtNames + ')',
  76. ], [], {
  77. resolve: inputDir,
  78. }),
  79. refresh() {
  80. res.options = initEasycomOptions();
  81. initEasycom(res.options);
  82. initUTSEasycom();
  83. },
  84. easycoms,
  85. };
  86. return res;
  87. }
  88. exports.initEasycoms = initEasycoms;
  89. exports.initEasycomsOnce = (0, uni_shared_1.once)(initEasycoms);
  90. function initUniModulesEasycomDirs(uniModulesDir) {
  91. if (!fs_1.default.existsSync(uniModulesDir)) {
  92. return [];
  93. }
  94. return fs_1.default
  95. .readdirSync(uniModulesDir)
  96. .map((uniModuleDir) => {
  97. const uniModuleComponentsDir = path_1.default.resolve(uniModulesDir, uniModuleDir, 'components');
  98. if (fs_1.default.existsSync(uniModuleComponentsDir)) {
  99. return uniModuleComponentsDir;
  100. }
  101. })
  102. .filter(Boolean);
  103. }
  104. function initEasycom({ isX, dirs, rootDir, custom, extensions, }) {
  105. clearEasycom();
  106. rootDir = (0, utils_1.normalizePath)(rootDir);
  107. const easycomsObj = Object.create(null);
  108. if (dirs && dirs.length && rootDir) {
  109. const autoEasyComObj = initAutoScanEasycoms(dirs, rootDir, extensions);
  110. if (isX) {
  111. Object.keys(autoEasyComObj).forEach((tagName) => {
  112. let source = autoEasyComObj[tagName];
  113. tagName = tagName.slice(1, -1);
  114. if (path_1.default.isAbsolute(source) && source.startsWith(rootDir)) {
  115. source = '@/' + (0, utils_1.normalizePath)(path_1.default.relative(rootDir, source));
  116. }
  117. addUTSEasyComAutoImports(source, [
  118. genUTSComponentPublicInstanceImported(rootDir, source),
  119. genUTSComponentPublicInstanceIdent(tagName),
  120. ]);
  121. });
  122. }
  123. (0, shared_1.extend)(easycomsObj, autoEasyComObj);
  124. }
  125. if (custom) {
  126. Object.keys(custom).forEach((name) => {
  127. const componentPath = custom[name];
  128. easycomsObj[name] = componentPath.startsWith('@/')
  129. ? (0, utils_1.normalizePath)(path_1.default.join(rootDir, componentPath.slice(2)))
  130. : componentPath;
  131. });
  132. }
  133. Object.keys(easycomsObj).forEach((name) => {
  134. easycoms.push({
  135. name: name.startsWith('^') && name.endsWith('$') ? name.slice(1, -1) : name,
  136. pattern: new RegExp(name),
  137. replacement: easycomsObj[name],
  138. });
  139. });
  140. debugEasycom(easycoms);
  141. hasEasycom = !!easycoms.length;
  142. return easycoms;
  143. }
  144. function matchEasycom(tag) {
  145. if (!hasEasycom) {
  146. return;
  147. }
  148. let source = easycomsCache.get(tag);
  149. if (source) {
  150. return source;
  151. }
  152. if (easycomsInvalidCache.has(tag)) {
  153. return false;
  154. }
  155. const matcher = easycoms.find((matcher) => matcher.pattern.test(tag));
  156. if (!matcher) {
  157. easycomsInvalidCache.add(tag);
  158. return false;
  159. }
  160. source = tag.replace(matcher.pattern, matcher.replacement);
  161. easycomsCache.set(tag, source);
  162. debugEasycom('matchEasycom', tag, source);
  163. return source;
  164. }
  165. exports.matchEasycom = matchEasycom;
  166. const isDir = (path) => fs_1.default.lstatSync(path).isDirectory();
  167. function initAutoScanEasycom(dir, rootDir, extensions) {
  168. if (!path_1.default.isAbsolute(dir)) {
  169. dir = path_1.default.resolve(rootDir, dir);
  170. }
  171. const easycoms = Object.create(null);
  172. if (!fs_1.default.existsSync(dir)) {
  173. return easycoms;
  174. }
  175. fs_1.default.readdirSync(dir).forEach((name) => {
  176. const folder = path_1.default.resolve(dir, name);
  177. if (!isDir(folder)) {
  178. return;
  179. }
  180. const importDir = (0, utils_1.normalizePath)(folder);
  181. const files = fs_1.default.readdirSync(folder);
  182. // 读取文件夹文件列表,比对文件名(fs.existsSync在大小写不敏感的系统会匹配不准确)
  183. for (let i = 0; i < extensions.length; i++) {
  184. const ext = extensions[i];
  185. if (files.includes(name + ext)) {
  186. easycoms[`^${name}$`] = `${importDir}/${name}${ext}`;
  187. break;
  188. }
  189. }
  190. });
  191. return easycoms;
  192. }
  193. function initAutoScanEasycoms(dirs, rootDir, extensions) {
  194. const conflict = {};
  195. const res = dirs.reduce((easycoms, dir) => {
  196. const curEasycoms = initAutoScanEasycom(dir, rootDir, extensions);
  197. Object.keys(curEasycoms).forEach((name) => {
  198. // Use the first component when name conflict
  199. const componentPath = easycoms[name];
  200. if (!componentPath) {
  201. easycoms[name] = curEasycoms[name];
  202. }
  203. else {
  204. ;
  205. (conflict[componentPath] || (conflict[componentPath] = [])).push(normalizeComponentPath(curEasycoms[name], rootDir));
  206. }
  207. });
  208. return easycoms;
  209. }, Object.create(null));
  210. const conflictComponents = Object.keys(conflict);
  211. if (conflictComponents.length) {
  212. console.warn(messages_1.M['easycom.conflict']);
  213. conflictComponents.forEach((com) => {
  214. console.warn([normalizeComponentPath(com, rootDir), conflict[com]].join(','));
  215. });
  216. }
  217. return res;
  218. }
  219. function normalizeComponentPath(componentPath, rootDir) {
  220. return (0, utils_1.normalizePath)(path_1.default.relative(rootDir, componentPath));
  221. }
  222. function addImportDeclaration(importDeclarations, local, source, imported) {
  223. importDeclarations.push(createImportDeclaration(local, source, imported));
  224. return local;
  225. }
  226. exports.addImportDeclaration = addImportDeclaration;
  227. function createImportDeclaration(local, source, imported) {
  228. if (imported) {
  229. return `import { ${imported} as ${local} } from '${source}';`;
  230. }
  231. return `import ${local} from '${source}';`;
  232. }
  233. const RESOLVE_EASYCOM_IMPORT_CODE = `import { resolveDynamicComponent as __resolveDynamicComponent } from 'vue';import { resolveEasycom } from '@dcloudio/uni-app';`;
  234. function genResolveEasycomCode(importDeclarations, code, name) {
  235. if (!importDeclarations.includes(RESOLVE_EASYCOM_IMPORT_CODE)) {
  236. importDeclarations.push(RESOLVE_EASYCOM_IMPORT_CODE);
  237. }
  238. return `resolveEasycom(${code.replace('_resolveComponent', '__resolveDynamicComponent')}, ${name})`;
  239. }
  240. exports.genResolveEasycomCode = genResolveEasycomCode;
  241. exports.UNI_EASYCOM_EXCLUDE = [/App.vue$/, /@dcloudio\/uni-h5/];
  242. const utsEasyComAutoImports = {};
  243. function getUTSEasyComAutoImports() {
  244. return utsEasyComAutoImports;
  245. }
  246. exports.getUTSEasyComAutoImports = getUTSEasyComAutoImports;
  247. function addUTSEasyComAutoImports(source, imports) {
  248. if (!utsEasyComAutoImports[source]) {
  249. utsEasyComAutoImports[source] = [imports];
  250. }
  251. else {
  252. if (!utsEasyComAutoImports[source].find((item) => item[0] === imports[0])) {
  253. utsEasyComAutoImports[source].push(imports);
  254. }
  255. }
  256. }
  257. exports.addUTSEasyComAutoImports = addUTSEasyComAutoImports;
  258. function genUTSComponentPublicInstanceIdent(tagName) {
  259. return (0, shared_1.capitalize)((0, shared_1.camelize)(tagName)) + 'ComponentPublicInstance';
  260. }
  261. exports.genUTSComponentPublicInstanceIdent = genUTSComponentPublicInstanceIdent;
  262. function genUTSComponentPublicInstanceImported(root, fileName) {
  263. root = (0, utils_1.normalizePath)(root);
  264. if (path_1.default.isAbsolute(fileName) && fileName.startsWith(root)) {
  265. fileName = (0, utils_1.normalizePath)(path_1.default.relative(root, fileName));
  266. }
  267. if (fileName.startsWith('@/')) {
  268. return ((0, uts_1.genUTSClassName)(fileName.replace('@/', '')) + 'ComponentPublicInstance');
  269. }
  270. return (0, uts_1.genUTSClassName)(fileName) + 'ComponentPublicInstance';
  271. }
  272. exports.genUTSComponentPublicInstanceImported = genUTSComponentPublicInstanceImported;