Blame view

build/plugin/vite-plugin-context/transform.ts 3.37 KB
vben authored
1
// 修改自
vben authored
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
// https://github.com/luxueyan/vite-transform-globby-import/blob/master/src/index.ts

// TODO 目前还不能监听文件新增及删除 内容已经改变,缓存问题?
// 可以使用,先不打算集成
import { join } from 'path';
import { lstatSync } from 'fs';
import glob from 'glob';
import { createResolver, Resolver } from 'vite/dist/node/resolver.js';
import { Transform } from 'vite/dist/node/transform.js';

const modulesDir: string = join(process.cwd(), '/node_modules/');

interface SharedConfig {
  root?: string;
  alias?: Record<string, string>;
  resolvers?: Resolver[];
}

function template(template: string) {
  return (data: { [x: string]: any }) => {
    return template.replace(/#([^#]+)#/g, (_, g1) => data[g1] || g1);
  };
}

const globbyTransform = function (config: SharedConfig): Transform {
  const resolver = createResolver(
    config.root || process.cwd(),
    config.resolvers || [],
    config.alias || {}
  );
  const cache = new Map();

  const urlMap = new Map();
  return {
    test({ path }) {
      const filePath = path.replace('\u0000', ''); // why some path startsWith '\u0000'?
      try {
        return (
          !filePath.startsWith(modulesDir) &&
          /\.(vue|js|jsx|ts|tsx)$/.test(filePath) &&
          lstatSync(filePath).isFile()
        );
      } catch {
        return false;
      }
    },
    transform({ code, path, isBuild }) {
      let result = cache.get(path);
      if (!result) {
        const reg = /import\s+([\w\s{}*]+)\s+from\s+(['"])globby(\?path)?!([^'"]+)\2/g;
        const match = code.match(reg);
vben authored
53
54
        if (!match) return code;
        const lastImport = urlMap.get(path);
vben authored
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
        if (lastImport && match) {
          code = code.replace(lastImport, match[0]);
        }
        result = code.replace(reg, (_, g1, g2, g3, g4) => {
          const filePath = path.replace('\u0000', ''); // why some path startsWith '\u0000'?
          // resolve path
          const resolvedFilePath = g4.startsWith('.')
            ? resolver.resolveRelativeRequest(filePath, g4)
            : { pathname: resolver.requestToFile(g4) };
          const files = glob.sync(resolvedFilePath.pathname, { dot: true });
          let templateStr = 'import #name# from #file#'; // import default
          let name = g1;
          const m = g1.match(/\{\s*(\w+)(\s+as\s+(\w+))?\s*\}/); // import module
          const m2 = g1.match(/\*\s+as\s+(\w+)/); // import * as all module
          if (m) {
            templateStr = `import { ${m[1]} as #name# } from #file#`;
            name = m[3] || m[1];
          } else if (m2) {
            templateStr = 'import * as #name# from #file#';
            name = m2[1];
          }
          const temRender = template(templateStr);

          const groups: Array<string>[] = [];
          const replaceFiles = files.map((f, i) => {
            const file = g2 + resolver.fileToRequest(f) + g2;
            groups.push([name + i, file]);
            return temRender({ name: name + i, file });
          });
          urlMap.set(path, replaceFiles.join('\n'));
          return (
            replaceFiles.join('\n') +
            (g3 ? '\n' + groups.map((v) => `${v[0]}._path = ${v[1]}`).join('\n') : '') +
            `\nconst ${name} = { ${groups.map((v) => v[0]).join(',')} }\n`
          );
        });
        if (isBuild) cache.set(path, result);
      }
      return result;
    },
  };
};
export default globbyTransform;