forked from angusjf/astro-integration-elm
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.ts
97 lines (92 loc) · 2.83 KB
/
index.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
import { AstroIntegration } from "astro";
import type { ElmCompilerOptions } from "node-elm-compiler";
import nodeElm from "node-elm-compiler";
import { toESModule } from "elm-esm";
import { Connect, Plugin } from "vite";
const { compileToString } = nodeElm;
export default (
elmCompilerOptions: ElmCompilerOptions = {}
): AstroIntegration => ({
name: "astro-integration-elm",
hooks: {
"astro:server:setup": (options) => {
options.server.middlewares.use(devServerMiddleware(elmCompilerOptions));
},
"astro:config:setup": ({ command, addRenderer, updateConfig }) => {
if (
command !== "dev" &&
!elmCompilerOptions.debug &&
elmCompilerOptions.optimize === undefined
) {
elmCompilerOptions.optimize = true;
}
addRenderer({
name: "astro-integration-elm",
serverEntrypoint: "astro-integration-elm/elm-server.js",
clientEntrypoint: "astro-integration-elm/elm-client.js",
});
updateConfig({
vite: { plugins: [elmPlugin(elmCompilerOptions)] },
});
},
},
});
const elmPlugin = (elmCompilerOptions: ElmCompilerOptions): Plugin => ({
name: "vite-plugin-elm",
async transform(code, id, options) {
if (!id.endsWith(".elm")) return;
return compile(id, elmCompilerOptions);
},
});
const devServerMiddleware =
(elmCompilerOptions: ElmCompilerOptions): Connect.NextHandleFunction =>
async (req, res, next) => {
if (req.originalUrl?.endsWith(".elm")) {
const filename = req.originalUrl.replace("/@fs", "");
const compiled = await compile(filename, elmCompilerOptions);
res.statusCode = 200;
res.setHeader("Content-Type", "application/javascript");
res.end(compiled);
} else if (
req.originalUrl?.includes("astro-integration-elm_elm-client__js")
) {
res.statusCode = 200;
res.setHeader("Content-Type", "application/javascript");
let content = `
const elmClient = target => (Component, {unsafeSetup, ...props}) => {
if (!target.hasAttribute("ssr"))
return;
props.server = !1;
const app = Component.init({
node: target,
flags: props
});
unsafeSetup && eval(unsafeSetup)(app)
};
export { elmClient as default };
`;
res.end(content);
} else {
next();
}
};
const compile = async (
filename: string,
options: ElmCompilerOptions
): Promise<string> => {
const compiled = await compileToString(filename, options);
const esModule = toESModule(compiled);
return `
try {
global.document = {}
global.XMLHttpRequest = {}
global.requestAnimationFrame = () => undefined
global.setTimeout = () => undefined
} catch (e) {}
${esModule}
export default {
$$elm: true,
...Elm[Object.keys(Elm)[0]]
}
`;
};