elm-pages 2.1.10 → 3.0.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Internal-RoutePattern.elmi +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Internal-RoutePattern.elmo +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-NoContractViolations.elmi +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-NoContractViolations.elmo +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-NoContractViolationsTest.elmi +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-NoContractViolationsTest.elmo +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Reporter.elmi +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Reporter.elmo +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Runner.elmi +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Runner.elmo +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/d.dat +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/i.dat +0 -0
- package/generator/{template/public/style.css → review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/lock} +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/o.dat +0 -0
- package/generator/review/elm-stuff/tests-0.19.1/elm.json +1 -0
- package/generator/review/elm-stuff/tests-0.19.1/js/Reporter.elm.js +6795 -0
- package/generator/review/elm-stuff/tests-0.19.1/js/Runner.elm.js +27617 -0
- package/generator/review/elm-stuff/tests-0.19.1/js/node_runner.js +110 -0
- package/generator/review/elm-stuff/tests-0.19.1/js/node_supervisor.js +187 -0
- package/generator/review/elm-stuff/tests-0.19.1/js/package.json +1 -0
- package/generator/review/elm-stuff/tests-0.19.1/src/Reporter.elm +26 -0
- package/generator/review/elm-stuff/tests-0.19.1/src/Runner.elm +62 -0
- package/generator/review/elm.json +13 -4
- package/{src → generator/review/src}/Pages/Review/NoContractViolations.elm +148 -148
- package/generator/review/tests/Pages/Review/NoContractViolationsTest.elm +331 -0
- package/generator/src/RouteBuilder.elm +420 -0
- package/generator/src/SharedTemplate.elm +4 -5
- package/generator/src/SiteConfig.elm +3 -9
- package/generator/src/build.js +308 -95
- package/generator/src/cli.js +103 -8
- package/generator/src/codegen.js +192 -35
- package/generator/src/compile-elm.js +183 -31
- package/generator/src/dev-server.js +353 -96
- package/generator/src/elm-application.json +3 -1
- package/generator/src/elm-codegen.js +34 -0
- package/generator/src/elm-file-constants.js +2 -0
- package/generator/src/error-formatter.js +20 -1
- package/generator/src/generate-template-module-connector.js +120 -924
- package/generator/src/hello.ts +5 -0
- package/generator/src/pre-render-html.js +58 -104
- package/generator/src/render-worker.js +27 -13
- package/generator/src/render.js +252 -197
- package/generator/src/request-cache-fs.js +18 -0
- package/generator/src/request-cache.js +128 -56
- package/generator/src/rewrite-client-elm-json.js +49 -0
- package/generator/src/route-codegen-helpers.js +62 -1
- package/generator/static-code/dev-style.css +22 -0
- package/generator/static-code/elm-pages.js +43 -39
- package/generator/static-code/hmr.js +98 -88
- package/generator/template/app/Api.elm +25 -0
- package/generator/template/app/ErrorPage.elm +38 -0
- package/generator/template/app/Route/Index.elm +87 -0
- package/generator/template/{src → app}/Shared.elm +34 -13
- package/generator/template/app/Site.elm +19 -0
- package/generator/template/{src → app}/View.elm +0 -0
- package/generator/template/elm-pages.config.mjs +5 -0
- package/generator/template/elm.json +14 -5
- package/generator/template/{public/index.js → index.ts} +7 -3
- package/generator/template/package.json +5 -5
- package/generator/template/public/favicon.ico +0 -0
- package/generator/template/public/images/icon-png.png +0 -0
- package/generator/template/src/.gitkeep +0 -0
- package/generator/template/style.css +4 -0
- package/package.json +30 -23
- package/src/ApiRoute.elm +176 -43
- package/src/BuildError.elm +10 -1
- package/src/CookieParser.elm +84 -0
- package/src/DataSource/Env.elm +38 -0
- package/src/DataSource/File.elm +27 -16
- package/src/DataSource/Glob.elm +126 -80
- package/src/DataSource/Http.elm +283 -304
- package/src/DataSource/Internal/Glob.elm +5 -21
- package/src/DataSource/Internal/Request.elm +25 -0
- package/src/DataSource/Port.elm +17 -14
- package/src/DataSource.elm +55 -318
- package/src/Form/Field.elm +717 -0
- package/src/Form/FieldStatus.elm +36 -0
- package/src/Form/FieldView.elm +417 -0
- package/src/Form/FormData.elm +22 -0
- package/src/Form/Validation.elm +391 -0
- package/src/Form/Value.elm +118 -0
- package/src/Form.elm +1683 -0
- package/src/FormData.elm +58 -0
- package/src/FormDecoder.elm +102 -0
- package/src/Head/Seo.elm +12 -4
- package/src/Head.elm +12 -2
- package/src/HtmlPrinter.elm +1 -1
- package/src/Internal/ApiRoute.elm +17 -4
- package/src/Internal/Request.elm +7 -0
- package/src/PageServerResponse.elm +68 -0
- package/src/Pages/ContentCache.elm +1 -229
- package/src/Pages/Fetcher.elm +58 -0
- package/src/Pages/FormState.elm +256 -0
- package/src/Pages/Generate.elm +800 -0
- package/src/Pages/Internal/Form.elm +17 -0
- package/src/Pages/Internal/NotFoundReason.elm +3 -55
- package/src/Pages/Internal/Platform/Cli.elm +777 -579
- package/src/Pages/Internal/Platform/Effect.elm +5 -5
- package/src/Pages/Internal/Platform/StaticResponses.elm +178 -394
- package/src/Pages/Internal/Platform/ToJsPayload.elm +24 -23
- package/src/Pages/Internal/Platform.elm +1244 -504
- package/src/Pages/Internal/ResponseSketch.elm +19 -0
- package/src/Pages/Internal/RoutePattern.elm +596 -45
- package/src/Pages/Manifest.elm +26 -0
- package/src/Pages/Msg.elm +79 -0
- package/src/Pages/ProgramConfig.elm +67 -14
- package/src/Pages/SiteConfig.elm +3 -6
- package/src/Pages/StaticHttp/Request.elm +4 -2
- package/src/Pages/StaticHttpRequest.elm +50 -215
- package/src/Pages/Transition.elm +70 -0
- package/src/Path.elm +1 -0
- package/src/Pattern.elm +98 -0
- package/src/RenderRequest.elm +2 -2
- package/src/RequestsAndPending.elm +111 -9
- package/src/Server/Request.elm +1253 -0
- package/src/Server/Response.elm +292 -0
- package/src/Server/Session.elm +316 -0
- package/src/Server/SetCookie.elm +169 -0
- package/src/TerminalText.elm +1 -1
- package/src/Test/Html/Internal/ElmHtml/Markdown.elm +0 -1
- package/src/Test/Html/Internal/ElmHtml/ToString.elm +1 -1
- package/generator/src/Page.elm +0 -359
- package/generator/src/codegen-template-module.js +0 -183
- package/generator/src/elm-pages-js-minified.js +0 -1
- package/generator/template/src/Api.elm +0 -14
- package/generator/template/src/Page/Index.elm +0 -69
- package/generator/template/src/Site.elm +0 -41
- package/src/DataSource/ServerRequest.elm +0 -60
- package/src/Internal/OptimizedDecoder.elm +0 -18
- package/src/KeepOrDiscard.elm +0 -6
- package/src/OptimizedDecoder/Pipeline.elm +0 -335
- package/src/OptimizedDecoder.elm +0 -818
- package/src/Pages/Internal/ApplicationType.elm +0 -6
- package/src/Pages/Secrets.elm +0 -83
- package/src/Secrets.elm +0 -111
- package/src/SecretsDict.elm +0 -45
|
@@ -2,10 +2,11 @@ const path = require("path");
|
|
|
2
2
|
const fs = require("fs");
|
|
3
3
|
const which = require("which");
|
|
4
4
|
const chokidar = require("chokidar");
|
|
5
|
+
const { URL } = require("url");
|
|
5
6
|
const {
|
|
6
|
-
spawnElmMake,
|
|
7
7
|
compileElmForBrowser,
|
|
8
8
|
runElmReview,
|
|
9
|
+
compileCliApp,
|
|
9
10
|
} = require("./compile-elm.js");
|
|
10
11
|
const http = require("http");
|
|
11
12
|
const https = require("https");
|
|
@@ -13,15 +14,19 @@ const codegen = require("./codegen.js");
|
|
|
13
14
|
const kleur = require("kleur");
|
|
14
15
|
const serveStatic = require("serve-static");
|
|
15
16
|
const connect = require("connect");
|
|
16
|
-
const {
|
|
17
|
+
const { restoreColorSafe } = require("./error-formatter");
|
|
17
18
|
const { Worker, SHARE_ENV } = require("worker_threads");
|
|
18
19
|
const os = require("os");
|
|
19
20
|
const { ensureDirSync } = require("./file-helpers.js");
|
|
20
21
|
const baseMiddleware = require("./basepath-middleware.js");
|
|
21
22
|
const devcert = require("devcert");
|
|
23
|
+
const busboy = require("busboy");
|
|
24
|
+
const { createServer: createViteServer } = require("vite");
|
|
25
|
+
const cliVersion = require("../../package.json").version;
|
|
26
|
+
const esbuild = require("esbuild");
|
|
22
27
|
|
|
23
28
|
/**
|
|
24
|
-
* @param {{ port: string; base: string; https: boolean; }} options
|
|
29
|
+
* @param {{ port: string; base: string; https: boolean; debug: boolean; }} options
|
|
25
30
|
*/
|
|
26
31
|
async function start(options) {
|
|
27
32
|
let threadReadyQueue = [];
|
|
@@ -33,7 +38,6 @@ async function start(options) {
|
|
|
33
38
|
const useHttps = options.https;
|
|
34
39
|
let elmMakeRunning = true;
|
|
35
40
|
|
|
36
|
-
const serve = serveStatic("public/", { index: false });
|
|
37
41
|
fs.mkdirSync(".elm-pages/cache", { recursive: true });
|
|
38
42
|
const serveCachedFiles = serveStatic(".elm-pages/cache", { index: false });
|
|
39
43
|
const generatedFilesDirectory = "elm-stuff/elm-pages/generated-files";
|
|
@@ -59,8 +63,18 @@ async function start(options) {
|
|
|
59
63
|
console.error(error);
|
|
60
64
|
process.exit(1);
|
|
61
65
|
}
|
|
62
|
-
let clientElmMakeProcess = compileElmForBrowser();
|
|
63
|
-
let pendingCliCompile = compileCliApp(
|
|
66
|
+
let clientElmMakeProcess = compileElmForBrowser(options);
|
|
67
|
+
let pendingCliCompile = compileCliApp(
|
|
68
|
+
options,
|
|
69
|
+
".elm-pages/Main.elm",
|
|
70
|
+
|
|
71
|
+
path.join(process.cwd(), "elm-stuff/elm-pages/", "elm.js"),
|
|
72
|
+
|
|
73
|
+
// "elm.js",
|
|
74
|
+
"elm-stuff/elm-pages/",
|
|
75
|
+
path.join("elm-stuff/elm-pages/", "elm.js")
|
|
76
|
+
);
|
|
77
|
+
|
|
64
78
|
watchElmSourceDirs(true);
|
|
65
79
|
|
|
66
80
|
async function setup() {
|
|
@@ -101,26 +115,75 @@ async function start(options) {
|
|
|
101
115
|
);
|
|
102
116
|
|
|
103
117
|
watcher.add(sourceDirs);
|
|
104
|
-
watcher.add("./public/*.css");
|
|
105
|
-
watcher.add("./port-data-source.js");
|
|
106
118
|
}
|
|
107
119
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
)
|
|
114
|
-
|
|
120
|
+
const viteConfig = await import(
|
|
121
|
+
path.join(process.cwd(), "elm-pages.config.mjs")
|
|
122
|
+
)
|
|
123
|
+
.then(async (elmPagesConfig) => {
|
|
124
|
+
return elmPagesConfig.default.vite || {};
|
|
125
|
+
})
|
|
126
|
+
.catch((error) => {
|
|
127
|
+
console.warn(
|
|
128
|
+
kleur.yellow(
|
|
129
|
+
"No `elm-pages.config.mjs` file found. Using default config."
|
|
130
|
+
)
|
|
131
|
+
);
|
|
132
|
+
return {};
|
|
133
|
+
});
|
|
134
|
+
const vite = await createViteServer({
|
|
135
|
+
server: { middlewareMode: "ssr", base: options.base, port: options.port },
|
|
136
|
+
configFile: false,
|
|
137
|
+
root: process.cwd(),
|
|
138
|
+
base: options.base,
|
|
139
|
+
...viteConfig,
|
|
140
|
+
});
|
|
141
|
+
esbuild
|
|
142
|
+
.build({
|
|
143
|
+
entryPoints: ["./port-data-source"],
|
|
144
|
+
platform: "node",
|
|
145
|
+
assetNames: "[name]-[hash]",
|
|
146
|
+
chunkNames: "chunks/[name]-[hash]",
|
|
147
|
+
outExtension: { ".js": ".js" },
|
|
148
|
+
metafile: true,
|
|
149
|
+
bundle: true,
|
|
150
|
+
watch: true,
|
|
151
|
+
logLevel: "error",
|
|
152
|
+
|
|
153
|
+
outdir: ".elm-pages/compiled-ports",
|
|
154
|
+
entryNames: "[dir]/[name]-[hash]",
|
|
155
|
+
|
|
156
|
+
plugins: [
|
|
157
|
+
{
|
|
158
|
+
name: "example",
|
|
159
|
+
setup(build) {
|
|
160
|
+
build.onEnd((result) => {
|
|
161
|
+
global.portsFilePath = Object.keys(result.metafile.outputs)[0];
|
|
162
|
+
|
|
163
|
+
clients.forEach((client) => {
|
|
164
|
+
client.response.write(`data: content.dat\n\n`);
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
],
|
|
170
|
+
})
|
|
171
|
+
.then((result) => {
|
|
172
|
+
console.log("Watching port-data-source...");
|
|
173
|
+
})
|
|
174
|
+
.catch((error) => {
|
|
175
|
+
console.error("Failed to start port-data-source watcher", error);
|
|
176
|
+
});
|
|
115
177
|
|
|
116
178
|
const app = connect()
|
|
117
179
|
.use(timeMiddleware())
|
|
118
|
-
.use(
|
|
180
|
+
.use(serveStaticCode)
|
|
119
181
|
.use(awaitElmMiddleware)
|
|
182
|
+
.use(baseMiddleware(options.base))
|
|
120
183
|
.use(serveCachedFiles)
|
|
121
|
-
.use(
|
|
122
|
-
.use(serve)
|
|
184
|
+
.use(vite.middlewares)
|
|
123
185
|
.use(processRequest);
|
|
186
|
+
|
|
124
187
|
if (useHttps) {
|
|
125
188
|
const ssl = await devcert.certificateFor("localhost");
|
|
126
189
|
https.createServer(ssl, app).listen(port);
|
|
@@ -143,10 +206,6 @@ async function start(options) {
|
|
|
143
206
|
watcher.on("all", async function (eventName, pathThatChanged) {
|
|
144
207
|
if (pathThatChanged === "elm.json") {
|
|
145
208
|
watchElmSourceDirs(false);
|
|
146
|
-
} else if (pathThatChanged.endsWith(".css")) {
|
|
147
|
-
clients.forEach((client) => {
|
|
148
|
-
client.response.write(`data: style.css\n\n`);
|
|
149
|
-
});
|
|
150
209
|
} else if (pathThatChanged.endsWith(".elm")) {
|
|
151
210
|
if (elmMakeRunning) {
|
|
152
211
|
} else {
|
|
@@ -154,8 +213,15 @@ async function start(options) {
|
|
|
154
213
|
if (needToRerunCodegen(eventName, pathThatChanged)) {
|
|
155
214
|
try {
|
|
156
215
|
await codegen.generate(options.base);
|
|
157
|
-
clientElmMakeProcess = compileElmForBrowser();
|
|
158
|
-
pendingCliCompile = compileCliApp(
|
|
216
|
+
clientElmMakeProcess = compileElmForBrowser(options);
|
|
217
|
+
pendingCliCompile = compileCliApp(
|
|
218
|
+
options,
|
|
219
|
+
".elm-pages/Main.elm",
|
|
220
|
+
path.join(process.cwd(), "elm-stuff/elm-pages/", "elm.js"),
|
|
221
|
+
// "elm.js",
|
|
222
|
+
"elm-stuff/elm-pages/",
|
|
223
|
+
path.join("elm-stuff/elm-pages/", "elm.js")
|
|
224
|
+
);
|
|
159
225
|
|
|
160
226
|
Promise.all([clientElmMakeProcess, pendingCliCompile])
|
|
161
227
|
.then(() => {
|
|
@@ -180,8 +246,17 @@ async function start(options) {
|
|
|
180
246
|
clientElmMakeProcess = Promise.reject(errorJson);
|
|
181
247
|
pendingCliCompile = Promise.reject(errorJson);
|
|
182
248
|
} else {
|
|
183
|
-
clientElmMakeProcess = compileElmForBrowser();
|
|
184
|
-
pendingCliCompile = compileCliApp(
|
|
249
|
+
clientElmMakeProcess = compileElmForBrowser(options);
|
|
250
|
+
pendingCliCompile = compileCliApp(
|
|
251
|
+
options,
|
|
252
|
+
".elm-pages/Main.elm",
|
|
253
|
+
|
|
254
|
+
path.join(process.cwd(), "elm-stuff/elm-pages/", "elm.js"),
|
|
255
|
+
|
|
256
|
+
// "elm.js",
|
|
257
|
+
"elm-stuff/elm-pages/",
|
|
258
|
+
path.join("elm-stuff/elm-pages/", "elm.js")
|
|
259
|
+
);
|
|
185
260
|
}
|
|
186
261
|
|
|
187
262
|
Promise.all([clientElmMakeProcess, pendingCliCompile])
|
|
@@ -192,7 +267,7 @@ async function start(options) {
|
|
|
192
267
|
elmMakeRunning = false;
|
|
193
268
|
});
|
|
194
269
|
clients.forEach((client) => {
|
|
195
|
-
client.response.write(`data: content.
|
|
270
|
+
client.response.write(`data: content.dat\n\n`);
|
|
196
271
|
});
|
|
197
272
|
}
|
|
198
273
|
} else {
|
|
@@ -214,7 +289,7 @@ async function start(options) {
|
|
|
214
289
|
// }
|
|
215
290
|
// });
|
|
216
291
|
clients.forEach((client) => {
|
|
217
|
-
client.response.write(`data: content.
|
|
292
|
+
client.response.write(`data: content.dat\n\n`);
|
|
218
293
|
});
|
|
219
294
|
}
|
|
220
295
|
});
|
|
@@ -242,7 +317,7 @@ async function start(options) {
|
|
|
242
317
|
function needToRerunCodegen(eventName, pathThatChanged) {
|
|
243
318
|
return (
|
|
244
319
|
(eventName === "add" || eventName === "unlink") &&
|
|
245
|
-
pathThatChanged.match(/
|
|
320
|
+
pathThatChanged.match(/app\/Route\/.*\.elm/)
|
|
246
321
|
);
|
|
247
322
|
}
|
|
248
323
|
|
|
@@ -250,12 +325,12 @@ async function start(options) {
|
|
|
250
325
|
* @param {string} pathname
|
|
251
326
|
* @param {((value: any) => any) | null | undefined} onOk
|
|
252
327
|
* @param {((reason: any) => PromiseLike<never>) | null | undefined} onErr
|
|
328
|
+
* @param {{ method: string; hostname: string; query: string; headers: Object; host: string; pathname: string; port: string; protocol: string; rawUrl: string; }} serverRequest
|
|
253
329
|
*/
|
|
254
|
-
function runRenderThread(pathname, onOk, onErr) {
|
|
330
|
+
function runRenderThread(serverRequest, pathname, onOk, onErr) {
|
|
255
331
|
let cleanUpThread = () => {};
|
|
256
332
|
return new Promise(async (resolve, reject) => {
|
|
257
333
|
const readyThread = await waitForThread();
|
|
258
|
-
console.log(`Rendering ${pathname}`, readyThread.worker.threadId);
|
|
259
334
|
cleanUpThread = () => {
|
|
260
335
|
cleanUp(readyThread);
|
|
261
336
|
};
|
|
@@ -264,6 +339,8 @@ async function start(options) {
|
|
|
264
339
|
readyThread.worker.postMessage({
|
|
265
340
|
mode: "dev-server",
|
|
266
341
|
pathname,
|
|
342
|
+
serverRequest,
|
|
343
|
+
portsFilePath: global.portsFilePath,
|
|
267
344
|
});
|
|
268
345
|
readyThread.worker.on("message", (message) => {
|
|
269
346
|
if (message.tag === "done") {
|
|
@@ -308,26 +385,31 @@ async function start(options) {
|
|
|
308
385
|
} catch (error) {
|
|
309
386
|
let isImplicitContractError = false;
|
|
310
387
|
try {
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
388
|
+
let jsonParsed = JSON.parse(error);
|
|
389
|
+
isImplicitContractError =
|
|
390
|
+
jsonParsed.errors &&
|
|
391
|
+
jsonParsed.errors.some((errorItem) => errorItem.name === "Main");
|
|
314
392
|
} catch (unexpectedError) {
|
|
315
393
|
console.log("Unexpected error", unexpectedError);
|
|
316
394
|
}
|
|
317
395
|
if (isImplicitContractError) {
|
|
318
396
|
const reviewOutput = await runElmReview();
|
|
319
|
-
console.log(
|
|
397
|
+
console.log(restoreColorSafe(reviewOutput));
|
|
320
398
|
|
|
321
|
-
if (req.url.includes("content.
|
|
399
|
+
if (req.url.includes("content.dat")) {
|
|
322
400
|
res.writeHead(500, { "Content-Type": "application/json" });
|
|
323
|
-
|
|
401
|
+
if (emptyReviewError(reviewOutput)) {
|
|
402
|
+
res.end(error);
|
|
403
|
+
} else {
|
|
404
|
+
res.end(reviewOutput);
|
|
405
|
+
}
|
|
324
406
|
} else {
|
|
325
407
|
res.writeHead(500, { "Content-Type": "text/html" });
|
|
326
408
|
res.end(errorHtml());
|
|
327
409
|
}
|
|
328
410
|
} else {
|
|
329
|
-
console.log(
|
|
330
|
-
if (req.url.includes("content.
|
|
411
|
+
console.log(restoreColorSafe(error));
|
|
412
|
+
if (req.url.includes("content.dat")) {
|
|
331
413
|
res.writeHead(500, { "Content-Type": "application/json" });
|
|
332
414
|
res.end(error);
|
|
333
415
|
} else {
|
|
@@ -338,51 +420,161 @@ async function start(options) {
|
|
|
338
420
|
return;
|
|
339
421
|
}
|
|
340
422
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
423
|
+
const requestTime = new Date();
|
|
424
|
+
/** @type {string | null} */
|
|
425
|
+
let body = null;
|
|
426
|
+
|
|
427
|
+
req.on("data", function (data) {
|
|
428
|
+
if (!body) {
|
|
429
|
+
body = "";
|
|
430
|
+
}
|
|
431
|
+
body += data;
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
req.on("end", async function () {
|
|
435
|
+
// TODO run render directly instead of in worker thread
|
|
436
|
+
await runRenderThread(
|
|
437
|
+
await reqToJson(req, body, requestTime),
|
|
438
|
+
pathname,
|
|
439
|
+
async function (renderResult) {
|
|
440
|
+
const is404 = renderResult.is404;
|
|
441
|
+
switch (renderResult.kind) {
|
|
442
|
+
case "bytes": {
|
|
443
|
+
res.writeHead(is404 ? 404 : renderResult.statusCode, {
|
|
444
|
+
"Content-Type": "application/octet-stream",
|
|
445
|
+
...renderResult.headers,
|
|
446
|
+
});
|
|
447
|
+
res.end(Buffer.from(renderResult.contentDatPayload.buffer));
|
|
448
|
+
break;
|
|
449
|
+
}
|
|
450
|
+
case "json": {
|
|
451
|
+
// TODO is this used anymore? I Think it's a dead code path and can be deleted
|
|
452
|
+
res.writeHead(is404 ? 404 : renderResult.statusCode, {
|
|
453
|
+
"Content-Type": "application/json",
|
|
454
|
+
...renderResult.headers,
|
|
455
|
+
});
|
|
456
|
+
// is contentJson used any more? I think it can safely be deleted
|
|
457
|
+
res.end(renderResult.contentJson);
|
|
458
|
+
break;
|
|
459
|
+
}
|
|
460
|
+
case "html": {
|
|
461
|
+
try {
|
|
462
|
+
const template =
|
|
463
|
+
/*html*/
|
|
464
|
+
`<!DOCTYPE html>
|
|
465
|
+
<!-- ROOT --><html lang="en">
|
|
466
|
+
<head>
|
|
467
|
+
<script src="/hmr.js" type="text/javascript"></script>
|
|
468
|
+
<script src="/elm.js" type="text/javascript"></script>
|
|
469
|
+
<link rel="stylesheet" href="/style.css">
|
|
470
|
+
<link rel="stylesheet" href="/dev-style.css">
|
|
471
|
+
<script src="/elm-pages.js" type="module"></script>
|
|
472
|
+
<meta charset="UTF-8" />
|
|
473
|
+
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
|
474
|
+
<title><!-- PLACEHOLDER_TITLE --></title>
|
|
475
|
+
<meta name="generator" content="elm-pages v${cliVersion}" />
|
|
476
|
+
<meta name="mobile-web-app-capable" content="yes" />
|
|
477
|
+
<meta name="theme-color" content="#ffffff" />
|
|
478
|
+
<meta name="apple-mobile-web-app-capable" content="yes" />
|
|
479
|
+
<meta
|
|
480
|
+
name="apple-mobile-web-app-status-bar-style"
|
|
481
|
+
content="black-translucent"
|
|
482
|
+
/>
|
|
483
|
+
<!-- PLACEHOLDER_HEAD_AND_DATA -->
|
|
484
|
+
</head>
|
|
485
|
+
<body>
|
|
486
|
+
<div data-url="" display="none"></div>
|
|
487
|
+
<!-- PLACEHOLDER_HTML -->
|
|
488
|
+
</body>
|
|
489
|
+
</html>
|
|
490
|
+
`;
|
|
491
|
+
const processedTemplate = await vite.transformIndexHtml(
|
|
492
|
+
req.originalUrl,
|
|
493
|
+
template
|
|
494
|
+
);
|
|
495
|
+
const info = renderResult.htmlString;
|
|
496
|
+
const renderedHtml = processedTemplate
|
|
497
|
+
.replace(
|
|
498
|
+
/<!--\s*PLACEHOLDER_HEAD_AND_DATA\s*-->/,
|
|
499
|
+
`${info.headTags}
|
|
500
|
+
<script id="__ELM_PAGES_BYTES_DATA__" type="application/octet-stream">${info.bytesData}</script>`
|
|
501
|
+
)
|
|
502
|
+
.replace(/<!--\s*PLACEHOLDER_TITLE\s*-->/, info.title)
|
|
503
|
+
.replace(/<!--\s*PLACEHOLDER_HTML\s* -->/, info.html)
|
|
504
|
+
.replace(
|
|
505
|
+
/<!-- ROOT -->\S*<html lang="en">/m,
|
|
506
|
+
info.rootElement
|
|
507
|
+
);
|
|
508
|
+
res.writeHead(renderResult.statusCode, {
|
|
509
|
+
"Content-Type": "text/html",
|
|
510
|
+
...renderResult.headers,
|
|
511
|
+
});
|
|
512
|
+
res.end(renderedHtml);
|
|
513
|
+
} catch (e) {
|
|
514
|
+
vite.ssrFixStacktrace(e);
|
|
515
|
+
next(e);
|
|
516
|
+
}
|
|
517
|
+
break;
|
|
518
|
+
}
|
|
519
|
+
case "api-response": {
|
|
520
|
+
if (renderResult.body.kind === "server-response") {
|
|
521
|
+
const serverResponse = renderResult.body;
|
|
522
|
+
res.writeHead(
|
|
523
|
+
serverResponse.statusCode,
|
|
524
|
+
serverResponse.headers
|
|
525
|
+
);
|
|
526
|
+
res.end(serverResponse.body);
|
|
527
|
+
} else if (renderResult.body.kind === "static-file") {
|
|
528
|
+
let mimeType = serveStatic.mime.lookup(pathname || "text/html");
|
|
529
|
+
mimeType =
|
|
530
|
+
mimeType === "application/octet-stream"
|
|
531
|
+
? "text/html"
|
|
532
|
+
: mimeType;
|
|
533
|
+
res.writeHead(renderResult.statusCode, {
|
|
534
|
+
"Content-Type": mimeType,
|
|
535
|
+
});
|
|
536
|
+
res.end(renderResult.body.body);
|
|
537
|
+
// TODO - if route is static, write file to api-route-cache/ directory
|
|
538
|
+
// TODO - get 404 or other status code from elm-pages renderer
|
|
539
|
+
} else {
|
|
540
|
+
throw (
|
|
541
|
+
"Unexpected api-response renderResult: " +
|
|
542
|
+
JSON.stringify(renderResult, null, 2)
|
|
543
|
+
);
|
|
544
|
+
}
|
|
545
|
+
break;
|
|
546
|
+
}
|
|
547
|
+
default: {
|
|
548
|
+
console.dir(renderResult);
|
|
549
|
+
throw "Unexpected renderResult kind: " + renderResult.kind;
|
|
550
|
+
}
|
|
359
551
|
}
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
break;
|
|
552
|
+
},
|
|
553
|
+
|
|
554
|
+
function (error) {
|
|
555
|
+
console.log(restoreColorSafe(error));
|
|
556
|
+
if (req.url.includes("content.dat")) {
|
|
557
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
558
|
+
res.end(JSON.stringify(error));
|
|
559
|
+
} else {
|
|
560
|
+
res.writeHead(500, { "Content-Type": "text/html" });
|
|
561
|
+
res.end(errorHtml());
|
|
371
562
|
}
|
|
372
563
|
}
|
|
373
|
-
|
|
564
|
+
);
|
|
565
|
+
});
|
|
566
|
+
}
|
|
374
567
|
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
);
|
|
568
|
+
/**
|
|
569
|
+
* @param {string} reviewReportJsonString
|
|
570
|
+
*/
|
|
571
|
+
function emptyReviewError(reviewReportJsonString) {
|
|
572
|
+
try {
|
|
573
|
+
return JSON.parse(reviewReportJsonString).errors.length === 0;
|
|
574
|
+
} catch (e) {
|
|
575
|
+
console.trace("problem with format in reviewReportJsonString", e);
|
|
576
|
+
return true;
|
|
577
|
+
}
|
|
386
578
|
}
|
|
387
579
|
|
|
388
580
|
async function awaitElmMiddleware(req, res, next) {
|
|
@@ -495,23 +687,12 @@ function errorHtml() {
|
|
|
495
687
|
return `<!DOCTYPE html>
|
|
496
688
|
<html lang="en">
|
|
497
689
|
<head>
|
|
498
|
-
<link rel="stylesheet" href="/style.css"
|
|
499
|
-
<style>
|
|
500
|
-
@keyframes lds-default {
|
|
501
|
-
0%, 20%, 80%, 100% {
|
|
502
|
-
transform: scale(1);
|
|
503
|
-
}
|
|
504
|
-
50% {
|
|
505
|
-
transform: scale(1.5);
|
|
506
|
-
}
|
|
507
|
-
}
|
|
508
|
-
</style>
|
|
509
|
-
<!--<link rel="preload" href="/elm-pages.js" as="script"> -->
|
|
690
|
+
<link rel="stylesheet" href="/style.css">
|
|
691
|
+
<link rel="stylesheet" href="/dev-style.css">
|
|
510
692
|
<link rel="preload" href="/index.js" as="script">
|
|
511
693
|
<!--<link rel="preload" href="/elm.js" as="script">-->
|
|
512
694
|
<script src="/hmr.js" type="text/javascript"></script>
|
|
513
|
-
|
|
514
|
-
<!--<script defer="defer" src="/elm-pages.js" type="module"></script>-->
|
|
695
|
+
<script src="/elm.js" type="text/javascript"></script>
|
|
515
696
|
<meta charset="UTF-8">
|
|
516
697
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
517
698
|
<script>
|
|
@@ -536,9 +717,9 @@ function errorHtml() {
|
|
|
536
717
|
|
|
537
718
|
async function ensureRequiredExecutables() {
|
|
538
719
|
try {
|
|
539
|
-
await which("
|
|
720
|
+
await which("lamdera");
|
|
540
721
|
} catch (error) {
|
|
541
|
-
throw "I couldn't find
|
|
722
|
+
throw "I couldn't find lamdera on the PATH. Please ensure it's installed, either globally, or locally. If it's installed locally, ensure you're running through an NPM script or with npx so the PATH is configured to include it.";
|
|
542
723
|
}
|
|
543
724
|
try {
|
|
544
725
|
await which("elm-review");
|
|
@@ -547,4 +728,80 @@ async function ensureRequiredExecutables() {
|
|
|
547
728
|
}
|
|
548
729
|
}
|
|
549
730
|
|
|
731
|
+
/**
|
|
732
|
+
* @param {http.IncomingMessage} req
|
|
733
|
+
* @param {string | null} body
|
|
734
|
+
* @param {Date} requestTime
|
|
735
|
+
*/
|
|
736
|
+
function reqToJson(req, body, requestTime) {
|
|
737
|
+
return new Promise((resolve, reject) => {
|
|
738
|
+
if (
|
|
739
|
+
req.method === "POST" &&
|
|
740
|
+
req.headers["content-type"] &&
|
|
741
|
+
req.headers["content-type"].includes("multipart/form-data") &&
|
|
742
|
+
body
|
|
743
|
+
) {
|
|
744
|
+
try {
|
|
745
|
+
const bb = busboy({
|
|
746
|
+
headers: req.headers,
|
|
747
|
+
});
|
|
748
|
+
let fields = {};
|
|
749
|
+
|
|
750
|
+
bb.on("file", (fieldname, file, info) => {
|
|
751
|
+
const { filename, encoding, mimeType } = info;
|
|
752
|
+
|
|
753
|
+
file.on("data", (data) => {
|
|
754
|
+
fields[fieldname] = {
|
|
755
|
+
filename,
|
|
756
|
+
mimeType,
|
|
757
|
+
body: data.toString(),
|
|
758
|
+
};
|
|
759
|
+
});
|
|
760
|
+
});
|
|
761
|
+
|
|
762
|
+
bb.on("field", (fieldName, value) => {
|
|
763
|
+
fields[fieldName] = value;
|
|
764
|
+
});
|
|
765
|
+
|
|
766
|
+
// TODO skip parsing JSON and form data body if busboy doesn't run
|
|
767
|
+
bb.on("close", () => {
|
|
768
|
+
resolve(toJsonHelper(req, body, requestTime, fields));
|
|
769
|
+
});
|
|
770
|
+
bb.write(body);
|
|
771
|
+
} catch (error) {
|
|
772
|
+
resolve(toJsonHelper(req, body, requestTime, null));
|
|
773
|
+
}
|
|
774
|
+
} else {
|
|
775
|
+
resolve(toJsonHelper(req, body, requestTime, null));
|
|
776
|
+
}
|
|
777
|
+
});
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
/**
|
|
781
|
+
* @param {http.IncomingMessage} req
|
|
782
|
+
* @param {string | null} body
|
|
783
|
+
* @param {Date} requestTime
|
|
784
|
+
* @param {Object | null} multiPartFormData
|
|
785
|
+
* @returns {{method: string; rawUrl: string; body: string?; }}
|
|
786
|
+
*/
|
|
787
|
+
function toJsonHelper(req, body, requestTime, multiPartFormData) {
|
|
788
|
+
const url = new URL(req.url, `http://${req.headers.host}`);
|
|
789
|
+
return {
|
|
790
|
+
method: req.method,
|
|
791
|
+
headers: req.headers || {},
|
|
792
|
+
rawUrl: url.toString(),
|
|
793
|
+
body: body,
|
|
794
|
+
requestTime: Math.round(requestTime.getTime()),
|
|
795
|
+
multiPartFormData: multiPartFormData,
|
|
796
|
+
};
|
|
797
|
+
}
|
|
798
|
+
// TODO capture repeat entries into a list of values
|
|
799
|
+
// TODO have expect functions in Elm to handle expecting exactly one value, or getting first value only without failing if more
|
|
800
|
+
function paramsToObject(entries) {
|
|
801
|
+
const result = {};
|
|
802
|
+
for (const [key, value] of entries) {
|
|
803
|
+
result[key] = value;
|
|
804
|
+
}
|
|
805
|
+
return result;
|
|
806
|
+
}
|
|
550
807
|
module.exports = { start };
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
const spawnCallback = require("cross-spawn").spawn;
|
|
2
|
+
|
|
3
|
+
function runElmCodegenInstall() {
|
|
4
|
+
return new Promise(async (resolve, reject) => {
|
|
5
|
+
const subprocess = spawnCallback(`elm-codegen`, ["install"], {
|
|
6
|
+
// ignore stdout
|
|
7
|
+
// stdio: ["inherit", "ignore", "inherit"],
|
|
8
|
+
// cwd: cwd,
|
|
9
|
+
});
|
|
10
|
+
// if (await fsHelpers.fileExists(outputPath)) {
|
|
11
|
+
// await fsPromises.unlink(outputPath, {
|
|
12
|
+
// force: true /* ignore errors if file doesn't exist */,
|
|
13
|
+
// });
|
|
14
|
+
// }
|
|
15
|
+
let commandOutput = "";
|
|
16
|
+
|
|
17
|
+
subprocess.stderr.on("data", function (data) {
|
|
18
|
+
commandOutput += data;
|
|
19
|
+
});
|
|
20
|
+
subprocess.on("error", function () {
|
|
21
|
+
reject(commandOutput);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
subprocess.on("close", async (code) => {
|
|
25
|
+
if (code == 0) {
|
|
26
|
+
resolve();
|
|
27
|
+
} else {
|
|
28
|
+
reject(commandOutput);
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
module.exports = { runElmCodegenInstall };
|