transform.ts 3.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. // 修改自
  2. // https://github.com/luxueyan/vite-transform-globby-import/blob/master/src/index.ts
  3. // TODO 目前还不能监听文件新增及删除 内容已经改变,缓存问题?
  4. // 可以使用,先不打算集成
  5. import { join } from 'path';
  6. import { lstatSync } from 'fs';
  7. import glob from 'glob';
  8. import { createResolver, Resolver } from 'vite/dist/node/resolver.js';
  9. import { Transform } from 'vite/dist/node/transform.js';
  10. const modulesDir: string = join(process.cwd(), '/node_modules/');
  11. interface SharedConfig {
  12. root?: string;
  13. alias?: Record<string, string>;
  14. resolvers?: Resolver[];
  15. }
  16. function template(template: string) {
  17. return (data: { [x: string]: any }) => {
  18. return template.replace(/#([^#]+)#/g, (_, g1) => data[g1] || g1);
  19. };
  20. }
  21. const globbyTransform = function (config: SharedConfig): Transform {
  22. const resolver = createResolver(
  23. config.root || process.cwd(),
  24. config.resolvers || [],
  25. config.alias || {}
  26. );
  27. const cache = new Map();
  28. const urlMap = new Map();
  29. return {
  30. test({ path }) {
  31. const filePath = path.replace('\u0000', ''); // why some path startsWith '\u0000'?
  32. try {
  33. return (
  34. !filePath.startsWith(modulesDir) &&
  35. /\.(vue|js|jsx|ts|tsx)$/.test(filePath) &&
  36. lstatSync(filePath).isFile()
  37. );
  38. } catch {
  39. return false;
  40. }
  41. },
  42. transform({ code, path, isBuild }) {
  43. let result = cache.get(path);
  44. if (!result) {
  45. const reg = /import\s+([\w\s{}*]+)\s+from\s+(['"])globby(\?path)?!([^'"]+)\2/g;
  46. const match = code.match(reg);
  47. if (!match) return code;
  48. const lastImport = urlMap.get(path);
  49. if (lastImport && match) {
  50. code = code.replace(lastImport, match[0]);
  51. }
  52. result = code.replace(reg, (_, g1, g2, g3, g4) => {
  53. const filePath = path.replace('\u0000', ''); // why some path startsWith '\u0000'?
  54. // resolve path
  55. const resolvedFilePath = g4.startsWith('.')
  56. ? resolver.resolveRelativeRequest(filePath, g4)
  57. : { pathname: resolver.requestToFile(g4) };
  58. const files = glob.sync(resolvedFilePath.pathname, { dot: true });
  59. let templateStr = 'import #name# from #file#'; // import default
  60. let name = g1;
  61. const m = g1.match(/\{\s*(\w+)(\s+as\s+(\w+))?\s*\}/); // import module
  62. const m2 = g1.match(/\*\s+as\s+(\w+)/); // import * as all module
  63. if (m) {
  64. templateStr = `import { ${m[1]} as #name# } from #file#`;
  65. name = m[3] || m[1];
  66. } else if (m2) {
  67. templateStr = 'import * as #name# from #file#';
  68. name = m2[1];
  69. }
  70. const temRender = template(templateStr);
  71. const groups: Array<string>[] = [];
  72. const replaceFiles = files.map((f, i) => {
  73. const file = g2 + resolver.fileToRequest(f) + g2;
  74. groups.push([name + i, file]);
  75. return temRender({ name: name + i, file });
  76. });
  77. urlMap.set(path, replaceFiles.join('\n'));
  78. return (
  79. replaceFiles.join('\n') +
  80. (g3 ? '\n' + groups.map((v) => `${v[0]}._path = ${v[1]}`).join('\n') : '') +
  81. `\nconst ${name} = { ${groups.map((v) => v[0]).join(',')} }\n`
  82. );
  83. });
  84. if (isBuild) cache.set(path, result);
  85. }
  86. return result;
  87. },
  88. };
  89. };
  90. export default globbyTransform;