-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathplugin-mdx.ts
143 lines (130 loc) · 4.53 KB
/
plugin-mdx.ts
1
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
53
54
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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
import { compileMdx as compileMdx_, dirname, ensureDir, esbuild, extname, join, normalize, resolve } from './deps.ts';
export const buildMdx = async (options: {
inFile?: string; // input file (e.g. src/app.tsx)
outFile?: string; // output file (e.g. public/app.js)
outDir?: string; // output directory (e.g. public)
watch?: boolean | string; // watch for changes
}) => {
const {
inFile = Deno.cwd(),
outFile,
outDir: outDir_,
// outFile = DEFAULT_OUT_FILE,
} = options;
const doBuild = async () => {
if (inFile.endsWith(".mdx")) {
const output = await compileMdx(inFile);
if (outFile) {
await Deno.writeTextFile(outFile, output);
return;
} else {
// file.mdx --> file.jsx (TODO: optional suffix)
const filename = inFile.substring(0, inFile.lastIndexOf("."));
const compiledFile = filename + ".jsx";
const outDir = outDir_ ?? dirname(compiledFile);
await ensureDir(outDir);
await Deno.writeTextFile(compiledFile, output);
}
} else {
// if directory, then build all mdx files in directory
const maybeFolder = await Deno.stat(inFile);
if (!maybeFolder.isDirectory) {
throw new Error(
`Input file must be a .mdx file or a directory containing .mdx files. (got ${inFile})`
);
}
const files = Deno.readDirSync(inFile);
for (const file of files) {
if (file.isFile && file.name.endsWith(".mdx")) {
// file.mdx --> file.jsx (TODO: optional suffix)
const startTime = performance.now();
const inPath = join(inFile, file.name);
let output = "";
try {
output = await compileMdx(inPath);
} catch (e) {
console.error("Error compiling file: ", inPath, e);
continue;
}
let targetOutFile = outFile;
if (!targetOutFile) {
// use same directory
targetOutFile = inFile;
}
if (extname(targetOutFile) !== ".jsx") {
targetOutFile = join(
targetOutFile,
file.name.substring(0, file.name.lastIndexOf(".")) + ".jsx"
);
}
const filename = file.name.substring(0, file.name.lastIndexOf("."));
const fullfilename = filename + ".jsx";
// create directory if it doesn't exist
const outDir = outDir_ ?? dirname(targetOutFile);
const finalOutFile = join(outDir, fullfilename);
await ensureDir(outDir);
await Deno.writeTextFile(finalOutFile, output);
const endTime = performance.now();
const diff = (endTime - startTime).toFixed(2);
console.log(`✅ Built MDX file ${fullfilename} in ${diff}ms`);
}
}
}
};
await doBuild();
if (!options.watch) {
return;
}
const inDir = dirname(inFile);
const watchDirs = typeof options.watch === "string"
? options.watch.split(",").map(normalize)
: [inDir];
const arePathsEqual = (path1: string, path2: string) => {
return normalize(resolve(path1)) === normalize(resolve(path2));
};
const outDir = outFile ? dirname(outFile) : outDir_ ? normalize(outDir_) : undefined;
if (outDir && watchDirs.some((dir) => arePathsEqual(dir, outDir))) {
throw new Error(
"Input watch directory and output directories cannot be the same when using --watch, will cause infinite loop.",
);
}
const watcher = Deno.watchFs(watchDirs, { recursive: true });
for await (const event of watcher) {
// if any paths end with .mdx, then rebuild
let rebuild = false;
for (const path of event.paths) {
if (path.endsWith(".mdx")) {
rebuild = true;
break;
}
}
if (rebuild) {
await doBuild();
}
}
};
export const compileMdxText = (text: string) => compileMdx_(text).then((result: any) => result.value) as Promise<string>;
export const compileMdx = async (path: string, withCache = true /* todo */): Promise<string> => {
const compiled = await compileMdxText(await Deno.readTextFile(path))
return compiled
}
export const mdxPlugin: esbuild.Plugin = {
"name": "mdx-preprocessor",
"setup": (build) => {
build.onResolve({ filter: /.*/ }, (args) => {
if (args.path.endsWith(".mdx")) {
return {
path: args.path,
namespace: "mdx",
};
}
})
build.onLoad({ filter: /.*/, namespace: "mdx" }, async (args) => {
const result = await compileMdx(args.path);
return {
contents: result,
loader: "jsx",
};
})
}
}