an attempt to make a lightweight, easily self-hostable, scoped bluesky appview
1//https://gist.github.com/sikanhe/f9ac68dd4c78c914c29cc98e7b875466
2import { readFileSync } from "node:fs"
3import * as babel from "npm:@babel/core"
4//import BabelPluginReactCompiler from "npm:babel-plugin-react-compiler"
5import BabelPluginReactCompiler from "npm:babel-plugin-react-compiler"
6import * as esbuild from "npm:esbuild@0.20.2";
7import QuickLRU from "npm:quick-lru"
8
9export function ReactCompilerEsbuildPlugin({
10 filter,
11 sourceMaps,
12 runtimeModulePath,
13}: { filter: RegExp; sourceMaps: boolean; runtimeModulePath: string }): esbuild.Plugin {
14 return {
15 name: "esbuild-react-compiler-plugin",
16 setup(build) {
17 // Cache previous outputs for incremental rebuilds
18 const buildCache = new QuickLRU<string, string>({ maxSize: 1000 })
19
20 let timings: number[] = []
21
22 build.onEnd(() => {
23 if (timings.length < 1) return
24
25 const totalTime = timings.reduce((sum, x) => sum + x, 0).toFixed(0)
26 console.log(`[⚛️ React Compiler] ${timings.length} files changed`)
27 console.log(`[⚛️ React Compiler] Used ${totalTime} ms`)
28
29 timings = []
30 })
31
32 build.onLoad({ filter, namespace: "" }, (args) => {
33 const contents = readFileSync(args.path, "utf8")
34
35 const t0 = performance.now()
36
37 if (buildCache.has(contents)) {
38 return {
39 contents: buildCache.get(contents),
40 loader: "js",
41 }
42 }
43
44 const output = build.esbuild.transformSync(contents, {
45 loader: "tsx",
46 jsx: "automatic",
47 define: build.initialOptions.define,
48 target: build.initialOptions.target,
49 })
50
51 const transformResult = babel.transformSync(output.code, {
52 plugins: [
53 // Warning: using string config here (ie 'babel-plugin-react-compiler') instead of the directly
54 // imported object is much slower than directly passing the plugin object because
55 // Babel has to resolve the plugin file from node_modules
56 [
57 BabelPluginReactCompiler,
58 {
59 runtimeModule: runtimeModulePath,
60 },
61 ],
62 ],
63 filename: args.path,
64 caller: {
65 name: "esbuild-react-compiler-plugin",
66 supportsStaticESM: true,
67 },
68 // TODO: figure out sourcemap setting and chaining
69 sourceMaps,
70 })
71
72 timings.push(performance.now() - t0)
73
74 if (transformResult?.code) {
75 buildCache.set(contents, transformResult?.code)
76 }
77
78 return {
79 contents: transformResult?.code ?? undefined,
80 loader: "js",
81 }
82 })
83 },
84 }
85}