elm-pages 3.0.0-beta.1 → 3.0.0-beta.12
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/README.md +10 -1
- package/codegen/elm-pages-codegen.js +803 -284
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-DeadCodeEliminateData.elmi +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-DeadCodeEliminateData.elmo +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/Pages-Review-DeadCodeEliminateDataTest.elmo +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/d.dat +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/i.dat +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/o.dat +0 -0
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm.json +1 -1
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/Reporter.elm.js +1326 -121
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/Runner.elm.js +15368 -13272
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/node_runner.js +1 -1
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/node_supervisor.js +1 -1
- package/generator/dead-code-review/elm.json +6 -5
- package/generator/dead-code-review/src/Pages/Review/DeadCodeEliminateData.elm +141 -17
- package/generator/dead-code-review/tests/Pages/Review/DeadCodeEliminateDataTest.elm +218 -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/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 -1
- package/generator/review/elm-stuff/tests-0.19.1/js/Reporter.elm.js +1326 -121
- package/generator/review/elm-stuff/tests-0.19.1/js/Runner.elm.js +14574 -12631
- package/generator/review/elm-stuff/tests-0.19.1/js/node_runner.js +1 -1
- package/generator/review/elm-stuff/tests-0.19.1/js/node_supervisor.js +1 -1
- package/generator/review/elm.json +6 -6
- package/generator/src/SharedTemplate.elm +1 -1
- package/generator/src/build.js +81 -51
- package/generator/src/cli.js +120 -42
- package/generator/src/codegen.js +11 -10
- package/generator/src/compatibility-key.js +1 -0
- package/generator/src/config.js +41 -0
- package/generator/src/dev-server.js +36 -56
- package/generator/src/elm-codegen.js +3 -0
- package/generator/src/generate-template-module-connector.js +0 -28
- package/generator/src/pre-render-html.js +31 -17
- package/generator/src/render-worker.js +1 -1
- package/generator/src/render.js +224 -37
- package/generator/src/request-cache.js +1 -0
- package/generator/src/rewrite-elm-json.js +3 -3
- package/generator/src/seo-renderer.js +11 -4
- package/generator/src/vite-utils.js +78 -0
- package/generator/template/app/Api.elm +1 -1
- package/generator/template/app/Site.elm +6 -1
- package/package.json +12 -13
- package/src/ApiRoute.elm +146 -11
- package/src/DataSource/Env.elm +27 -3
- package/src/DataSource/File.elm +1 -1
- package/src/DataSource/Internal/Request.elm +0 -5
- package/src/DataSource.elm +50 -53
- package/src/Form/Field.elm +1 -1
- package/src/Form.elm +33 -33
- package/src/Head/Seo.elm +16 -27
- package/src/Head.elm +237 -7
- package/src/HtmlPrinter.elm +7 -3
- package/src/MultiDict.elm +49 -0
- package/src/Pages/Generate.elm +548 -103
- package/src/Pages/GeneratorProgramConfig.elm +15 -0
- package/src/Pages/Internal/NotFoundReason.elm +3 -2
- package/src/Pages/Internal/Platform/Cli.elm +91 -27
- package/src/Pages/Internal/Platform/Cli.elm.bak +1276 -0
- package/src/Pages/Internal/Platform/CompatibilityKey.elm +6 -0
- package/src/Pages/Internal/Platform/GeneratorApplication.elm +455 -0
- package/src/Pages/Internal/Platform.elm +34 -27
- package/src/Pages/Manifest.elm +24 -0
- package/src/Pages/ProgramConfig.elm +6 -3
- package/src/Pages/Script.elm +100 -0
- package/src/PairingHeap.elm +137 -0
- package/src/Parser/Extra/String.elm +33 -0
- package/src/Parser/Extra.elm +69 -0
- package/src/ProgramTest/ComplexQuery.elm +360 -0
- package/src/ProgramTest/EffectSimulation.elm +122 -0
- package/src/ProgramTest/Failure.elm +367 -0
- package/src/ProgramTest/HtmlHighlighter.elm +116 -0
- package/src/ProgramTest/HtmlParserHacks.elm +58 -0
- package/src/ProgramTest/HtmlRenderer.elm +73 -0
- package/src/ProgramTest/Program.elm +30 -0
- package/src/ProgramTest/StringLines.elm +26 -0
- package/src/ProgramTest/TestHtmlHacks.elm +132 -0
- package/src/ProgramTest/TestHtmlParser.elm +201 -0
- package/src/ProgramTest.elm +2339 -0
- package/src/Query/Extra.elm +55 -0
- package/src/Result/Extra.elm +21 -0
- package/src/Server/Request.elm +2 -2
- package/src/Server/Session.elm +149 -83
- package/src/Server/SetCookie.elm +89 -31
- package/src/SimulatedEffect/Cmd.elm +69 -0
- package/src/SimulatedEffect/Http.elm +330 -0
- package/src/SimulatedEffect/Navigation.elm +69 -0
- package/src/SimulatedEffect/Ports.elm +62 -0
- package/src/SimulatedEffect/Process.elm +24 -0
- package/src/SimulatedEffect/Sub.elm +48 -0
- package/src/SimulatedEffect/Task.elm +252 -0
- package/src/SimulatedEffect/Time.elm +25 -0
- package/src/SimulatedEffect.elm +42 -0
- package/src/String/Extra.elm +6 -0
- package/src/Test/Http.elm +145 -0
- package/src/TestResult.elm +35 -0
- package/src/TestState.elm +305 -0
- package/src/Url/Extra.elm +100 -0
- package/src/Vendored/Diff.elm +321 -0
- package/src/Vendored/Failure.elm +217 -0
- package/src/Vendored/FormatMonochrome.elm +44 -0
- package/src/Vendored/Highlightable.elm +53 -0
|
@@ -24,6 +24,10 @@ const busboy = require("busboy");
|
|
|
24
24
|
const { createServer: createViteServer } = require("vite");
|
|
25
25
|
const cliVersion = require("../../package.json").version;
|
|
26
26
|
const esbuild = require("esbuild");
|
|
27
|
+
const { merge_vite_configs } = require("./vite-utils.js");
|
|
28
|
+
const { templateHtml } = require("./pre-render-html.js");
|
|
29
|
+
const { resolveConfig } = require("./config.js");
|
|
30
|
+
const globby = require("globby");
|
|
27
31
|
|
|
28
32
|
/**
|
|
29
33
|
* @param {{ port: string; base: string; https: boolean; debug: boolean; }} options
|
|
@@ -117,27 +121,23 @@ async function start(options) {
|
|
|
117
121
|
watcher.add(sourceDirs);
|
|
118
122
|
}
|
|
119
123
|
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
)
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
root: process.cwd(),
|
|
138
|
-
base: options.base,
|
|
139
|
-
...viteConfig,
|
|
140
|
-
});
|
|
124
|
+
const config = await resolveConfig();
|
|
125
|
+
const vite = await createViteServer(
|
|
126
|
+
merge_vite_configs(
|
|
127
|
+
{
|
|
128
|
+
server: {
|
|
129
|
+
middlewareMode: "ssr",
|
|
130
|
+
base: options.base,
|
|
131
|
+
port: options.port,
|
|
132
|
+
},
|
|
133
|
+
configFile: false,
|
|
134
|
+
root: process.cwd(),
|
|
135
|
+
base: options.base,
|
|
136
|
+
},
|
|
137
|
+
|
|
138
|
+
config.vite
|
|
139
|
+
)
|
|
140
|
+
);
|
|
141
141
|
esbuild
|
|
142
142
|
.build({
|
|
143
143
|
entryPoints: ["./port-data-source"],
|
|
@@ -148,7 +148,7 @@ async function start(options) {
|
|
|
148
148
|
metafile: true,
|
|
149
149
|
bundle: true,
|
|
150
150
|
watch: true,
|
|
151
|
-
logLevel: "
|
|
151
|
+
logLevel: "silent",
|
|
152
152
|
|
|
153
153
|
outdir: ".elm-pages/compiled-ports",
|
|
154
154
|
entryNames: "[dir]/[name]-[hash]",
|
|
@@ -158,11 +158,13 @@ async function start(options) {
|
|
|
158
158
|
name: "example",
|
|
159
159
|
setup(build) {
|
|
160
160
|
build.onEnd((result) => {
|
|
161
|
-
|
|
161
|
+
try {
|
|
162
|
+
global.portsFilePath = Object.keys(result.metafile.outputs)[0];
|
|
162
163
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
164
|
+
clients.forEach((client) => {
|
|
165
|
+
client.response.write(`data: content.dat\n\n`);
|
|
166
|
+
});
|
|
167
|
+
} catch (e) {}
|
|
166
168
|
});
|
|
167
169
|
},
|
|
168
170
|
},
|
|
@@ -172,7 +174,13 @@ async function start(options) {
|
|
|
172
174
|
console.log("Watching port-data-source...");
|
|
173
175
|
})
|
|
174
176
|
.catch((error) => {
|
|
175
|
-
|
|
177
|
+
const portDataSourceFileFound =
|
|
178
|
+
globby.sync("./port-data-source.*").length > 0;
|
|
179
|
+
if (portDataSourceFileFound) {
|
|
180
|
+
// don't present error if there are no files matching port-data-source
|
|
181
|
+
// if there are files matching port-data-source, warn the user in case something went wrong loading it
|
|
182
|
+
console.error("Failed to start port-data-source watcher", error);
|
|
183
|
+
}
|
|
176
184
|
});
|
|
177
185
|
|
|
178
186
|
const app = connect()
|
|
@@ -459,35 +467,7 @@ async function start(options) {
|
|
|
459
467
|
}
|
|
460
468
|
case "html": {
|
|
461
469
|
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
|
-
`;
|
|
470
|
+
const template = templateHtml(true, config.headTagsTemplate);
|
|
491
471
|
const processedTemplate = await vite.transformIndexHtml(
|
|
492
472
|
req.originalUrl,
|
|
493
473
|
template
|
|
@@ -17,6 +17,9 @@ function runElmCodegenInstall() {
|
|
|
17
17
|
subprocess.stderr.on("data", function (data) {
|
|
18
18
|
commandOutput += data;
|
|
19
19
|
});
|
|
20
|
+
subprocess.stdout.on("data", function (data) {
|
|
21
|
+
commandOutput += data;
|
|
22
|
+
});
|
|
20
23
|
subprocess.on("error", function () {
|
|
21
24
|
reject(commandOutput);
|
|
22
25
|
});
|
|
@@ -63,32 +63,10 @@ async function generateTemplateModuleConnector(basePath, phase) {
|
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
async function runElmCodegenCli(templates, basePath, phase) {
|
|
66
|
-
// await runElmCodegenInstall();
|
|
67
|
-
// try {
|
|
68
|
-
// await compileCliApp(
|
|
69
|
-
// // { debug: true },
|
|
70
|
-
// {},
|
|
71
|
-
// `Generate.elm`,
|
|
72
|
-
// path.join(process.cwd(), "elm-stuff/elm-pages-codegen.js"),
|
|
73
|
-
// path.join(__dirname, "../../codegen"),
|
|
74
|
-
|
|
75
|
-
// path.join(process.cwd(), "elm-stuff/elm-pages-codegen.js")
|
|
76
|
-
// );
|
|
77
|
-
// } catch (error) {
|
|
78
|
-
// console.log(restoreColorSafe(error));
|
|
79
|
-
// process.exit(1);
|
|
80
|
-
// // throw error;
|
|
81
|
-
// }
|
|
82
|
-
|
|
83
66
|
const filePath = path.join(__dirname, `../../codegen/elm-pages-codegen.js`);
|
|
84
67
|
|
|
85
|
-
// TODO use uncached require here to prevent stale code from running
|
|
86
|
-
|
|
87
68
|
const promise = new Promise((resolve, reject) => {
|
|
88
69
|
const elmPagesCodegen = require(filePath).Elm.Generate;
|
|
89
|
-
// path.join(
|
|
90
|
-
// process.cwd(),
|
|
91
|
-
// "./elm-stuff/elm-pages-codegen.js")
|
|
92
70
|
|
|
93
71
|
const app = elmPagesCodegen.init({
|
|
94
72
|
flags: { templates: templates, basePath, phase },
|
|
@@ -104,12 +82,10 @@ async function runElmCodegenCli(templates, basePath, phase) {
|
|
|
104
82
|
}
|
|
105
83
|
});
|
|
106
84
|
const filesToGenerate = await promise;
|
|
107
|
-
console.dir(filesToGenerate.map((file) => file.path));
|
|
108
85
|
|
|
109
86
|
return filesToGenerate;
|
|
110
87
|
}
|
|
111
88
|
|
|
112
|
-
|
|
113
89
|
/**
|
|
114
90
|
*
|
|
115
91
|
* @param {string[][]} templates
|
|
@@ -175,8 +151,6 @@ function sortScore(name) {
|
|
|
175
151
|
);
|
|
176
152
|
}
|
|
177
153
|
|
|
178
|
-
|
|
179
|
-
|
|
180
154
|
function fetcherModule(name) {
|
|
181
155
|
let moduleName = name.join(".");
|
|
182
156
|
// TODO need to account for splat routes/etc.
|
|
@@ -248,7 +222,6 @@ submit toMsg options =
|
|
|
248
222
|
`;
|
|
249
223
|
}
|
|
250
224
|
|
|
251
|
-
|
|
252
225
|
/**
|
|
253
226
|
* Convert Strings from camelCase to kebab-case
|
|
254
227
|
* @param {string} input
|
|
@@ -258,5 +231,4 @@ function camelToKebab(input) {
|
|
|
258
231
|
return input.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
|
|
259
232
|
}
|
|
260
233
|
|
|
261
|
-
|
|
262
234
|
module.exports = { generateTemplateModuleConnector, sortTemplates };
|
|
@@ -17,28 +17,32 @@ function wrapHtml(basePath, fromElm, contentDatPayload) {
|
|
|
17
17
|
};
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
/**
|
|
21
|
+
* @param {boolean} devMode
|
|
22
|
+
* @param {(context: {cliVersion: string;}) => string} userHeadTagsTemplate
|
|
23
|
+
*/
|
|
24
|
+
function templateHtml(devMode, userHeadTagsTemplate) {
|
|
21
25
|
return /* html */ `<!DOCTYPE html>
|
|
22
26
|
<!-- ROOT --><html lang="en">
|
|
23
27
|
<head>
|
|
24
|
-
<!-- PLACEHOLDER_PRELOADS -->
|
|
25
|
-
<script defer src="/elm.js" type="text/javascript"></script>
|
|
26
|
-
<script defer src="${path.join(
|
|
27
|
-
__dirname,
|
|
28
|
-
"../static-code/elm-pages.js"
|
|
29
|
-
)}" type="module"></script>
|
|
30
|
-
<link rel="stylesheet" href="/style.css" />
|
|
31
28
|
<meta charset="UTF-8" />
|
|
32
|
-
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
|
33
29
|
<title><!-- PLACEHOLDER_TITLE --></title>
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
<
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
30
|
+
${
|
|
31
|
+
devMode
|
|
32
|
+
? `<script src="/hmr.js" type="text/javascript"></script>
|
|
33
|
+
<link rel="stylesheet" href="/dev-style.css">`
|
|
34
|
+
: `<!-- PLACEHOLDER_PRELOADS -->`
|
|
35
|
+
}
|
|
36
|
+
<script defer src="/elm.js" type="text/javascript"></script>
|
|
37
|
+
${
|
|
38
|
+
devMode
|
|
39
|
+
? `<script src="/elm-pages.js" type="module"></script>`
|
|
40
|
+
: `<script defer src="${path.join(
|
|
41
|
+
__dirname,
|
|
42
|
+
"../static-code/elm-pages.js"
|
|
43
|
+
)}" type="module"></script>`
|
|
44
|
+
}
|
|
45
|
+
${indent(userHeadTagsTemplate({ cliVersion }))}
|
|
42
46
|
<!-- PLACEHOLDER_HEAD_AND_DATA -->
|
|
43
47
|
</head>
|
|
44
48
|
<body>
|
|
@@ -48,6 +52,16 @@ function templateHtml() {
|
|
|
48
52
|
</html>`;
|
|
49
53
|
}
|
|
50
54
|
|
|
55
|
+
/**
|
|
56
|
+
* @param {string} snippet
|
|
57
|
+
*/
|
|
58
|
+
function indent(snippet) {
|
|
59
|
+
return snippet
|
|
60
|
+
.split("\n")
|
|
61
|
+
.map((line) => ` ${line}`)
|
|
62
|
+
.join("\n");
|
|
63
|
+
}
|
|
64
|
+
|
|
51
65
|
/**
|
|
52
66
|
* @param {string} processedTemplate
|
|
53
67
|
*/
|
|
@@ -10,7 +10,7 @@ global.staticHttpCache = {};
|
|
|
10
10
|
async function run({ mode, pathname, serverRequest, portsFilePath }) {
|
|
11
11
|
console.time(`${threadId} ${pathname}`);
|
|
12
12
|
try {
|
|
13
|
-
const renderResult = await renderer(
|
|
13
|
+
const renderResult = await renderer.render(
|
|
14
14
|
portsFilePath,
|
|
15
15
|
workerData.basePath,
|
|
16
16
|
requireElm(mode),
|
package/generator/src/render.js
CHANGED
|
@@ -9,6 +9,7 @@ const preRenderHtml = require("./pre-render-html.js");
|
|
|
9
9
|
const { lookupOrPerform } = require("./request-cache.js");
|
|
10
10
|
const kleur = require("kleur");
|
|
11
11
|
const cookie = require("cookie-signature");
|
|
12
|
+
const { compatibilityKey } = require("./compatibility-key.js");
|
|
12
13
|
kleur.enabled = true;
|
|
13
14
|
|
|
14
15
|
process.on("unhandledRejection", (error) => {
|
|
@@ -18,18 +19,37 @@ let foundErrors;
|
|
|
18
19
|
let pendingDataSourceResponses;
|
|
19
20
|
let pendingDataSourceCount;
|
|
20
21
|
|
|
21
|
-
module.exports =
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
22
|
+
module.exports = { render, runGenerator };
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
*
|
|
26
|
+
* @param {string} basePath
|
|
27
|
+
* @param {Object} elmModule
|
|
28
|
+
* @param {string} path
|
|
29
|
+
* @param {{ method: string; hostname: string; query: Record<string, string | undefined>; headers: Record<string, string>; host: string; pathname: string; port: number | null; protocol: string; rawUrl: string; }} request
|
|
30
|
+
* @param {(pattern: string) => void} addDataSourceWatcher
|
|
31
|
+
* @param {boolean} hasFsAccess
|
|
32
|
+
* @returns
|
|
33
|
+
*/
|
|
34
|
+
async function render(
|
|
35
|
+
portsFile,
|
|
36
|
+
basePath,
|
|
37
|
+
elmModule,
|
|
38
|
+
mode,
|
|
39
|
+
path,
|
|
40
|
+
request,
|
|
41
|
+
addDataSourceWatcher,
|
|
42
|
+
hasFsAccess
|
|
43
|
+
) {
|
|
44
|
+
const { fs, resetInMemoryFs } = require("./request-cache-fs.js")(hasFsAccess);
|
|
45
|
+
resetInMemoryFs();
|
|
46
|
+
foundErrors = false;
|
|
47
|
+
pendingDataSourceResponses = [];
|
|
48
|
+
pendingDataSourceCount = 0;
|
|
49
|
+
// since init/update are never called in pre-renders, and DataSource.Http is called using pure NodeJS HTTP fetching
|
|
50
|
+
// we can provide a fake HTTP instead of xhr2 (which is otherwise needed for Elm HTTP requests from Node)
|
|
51
|
+
XMLHttpRequest = {};
|
|
52
|
+
const result = await runElmApp(
|
|
33
53
|
portsFile,
|
|
34
54
|
basePath,
|
|
35
55
|
elmModule,
|
|
@@ -37,31 +57,167 @@ module.exports =
|
|
|
37
57
|
path,
|
|
38
58
|
request,
|
|
39
59
|
addDataSourceWatcher,
|
|
60
|
+
fs,
|
|
40
61
|
hasFsAccess
|
|
41
|
-
)
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
62
|
+
);
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* @param {Object} elmModule
|
|
68
|
+
* @returns
|
|
69
|
+
* @param {string[]} cliOptions
|
|
70
|
+
* @param {any} portsFile
|
|
71
|
+
*/
|
|
72
|
+
async function runGenerator(cliOptions, portsFile, elmModule) {
|
|
73
|
+
global.isRunningGenerator = true;
|
|
74
|
+
const { fs, resetInMemoryFs } = require("./request-cache-fs.js")(true);
|
|
75
|
+
resetInMemoryFs();
|
|
76
|
+
foundErrors = false;
|
|
77
|
+
pendingDataSourceResponses = [];
|
|
78
|
+
pendingDataSourceCount = 0;
|
|
79
|
+
// since init/update are never called in pre-renders, and DataSource.Http is called using pure NodeJS HTTP fetching
|
|
80
|
+
// we can provide a fake HTTP instead of xhr2 (which is otherwise needed for Elm HTTP requests from Node)
|
|
81
|
+
XMLHttpRequest = {};
|
|
82
|
+
const result = await runGeneratorAppHelp(
|
|
83
|
+
cliOptions,
|
|
84
|
+
portsFile,
|
|
85
|
+
"",
|
|
86
|
+
elmModule,
|
|
87
|
+
"production",
|
|
88
|
+
"",
|
|
89
|
+
fs,
|
|
90
|
+
true
|
|
91
|
+
);
|
|
92
|
+
return result;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* @param {string} basePath
|
|
96
|
+
* @param {Object} elmModule
|
|
97
|
+
* @param {string} pagePath
|
|
98
|
+
* @param {string} mode
|
|
99
|
+
* @returns {Promise<({is404: boolean;} & ({kind: 'json';contentJson: string;} | {kind: 'html';htmlString: string;} | {kind: 'api-response';body: string;}))>}
|
|
100
|
+
* @param {string[]} cliOptions
|
|
101
|
+
* @param {any} portsFile
|
|
102
|
+
* @param {typeof import("fs") | import("memfs").IFs} fs
|
|
103
|
+
* @param {boolean} hasFsAccess
|
|
104
|
+
*/
|
|
105
|
+
function runGeneratorAppHelp(
|
|
106
|
+
cliOptions,
|
|
107
|
+
portsFile,
|
|
108
|
+
basePath,
|
|
109
|
+
elmModule,
|
|
110
|
+
mode,
|
|
111
|
+
pagePath,
|
|
112
|
+
fs,
|
|
113
|
+
hasFsAccess
|
|
114
|
+
) {
|
|
115
|
+
const isDevServer = mode !== "build";
|
|
116
|
+
let patternsToWatch = new Set();
|
|
117
|
+
let app = null;
|
|
118
|
+
let killApp;
|
|
119
|
+
return new Promise((resolve, reject) => {
|
|
120
|
+
const isBytes = pagePath.match(/content\.dat\/?$/);
|
|
121
|
+
|
|
122
|
+
app = elmModule.Elm.Main.init({
|
|
123
|
+
flags: {
|
|
124
|
+
compatibilityKey,
|
|
125
|
+
argv: ["", "", ...cliOptions],
|
|
126
|
+
versionMessage: "1.2.3",
|
|
127
|
+
},
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
killApp = () => {
|
|
131
|
+
app.ports.toJsPort.unsubscribe(portHandler);
|
|
132
|
+
app.ports.sendPageData.unsubscribe(portHandler);
|
|
133
|
+
app.die();
|
|
134
|
+
app = null;
|
|
135
|
+
// delete require.cache[require.resolve(compiledElmPath)];
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
async function portHandler(/** @type { FromElm } */ newThing) {
|
|
139
|
+
let fromElm;
|
|
140
|
+
let contentDatPayload;
|
|
141
|
+
|
|
142
|
+
fromElm = newThing;
|
|
143
|
+
if (fromElm.command === "log") {
|
|
144
|
+
console.log(fromElm.value);
|
|
145
|
+
} else if (fromElm.tag === "ApiResponse") {
|
|
146
|
+
const args = fromElm.args[0];
|
|
147
|
+
if (mode === "build") {
|
|
148
|
+
global.staticHttpCache = args.staticHttpCache;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
resolve({
|
|
152
|
+
kind: "api-response",
|
|
153
|
+
is404: args.is404,
|
|
154
|
+
statusCode: args.statusCode,
|
|
155
|
+
body: args.body,
|
|
156
|
+
});
|
|
157
|
+
} else if (fromElm.tag === "PageProgress") {
|
|
158
|
+
const args = fromElm.args[0];
|
|
159
|
+
if (mode === "build") {
|
|
160
|
+
global.staticHttpCache = args.staticHttpCache;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (isBytes) {
|
|
164
|
+
resolve({
|
|
165
|
+
kind: "bytes",
|
|
166
|
+
is404: false,
|
|
167
|
+
contentJson: JSON.stringify({
|
|
168
|
+
staticData: args.contentJson,
|
|
169
|
+
is404: false,
|
|
170
|
+
}),
|
|
171
|
+
statusCode: args.statusCode,
|
|
172
|
+
headers: args.headers,
|
|
173
|
+
contentDatPayload,
|
|
174
|
+
});
|
|
175
|
+
} else {
|
|
176
|
+
resolve(
|
|
177
|
+
outputString(basePath, fromElm, isDevServer, contentDatPayload)
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
} else if (fromElm.tag === "DoHttp") {
|
|
181
|
+
const requestToPerform = fromElm.args[0];
|
|
182
|
+
if (
|
|
183
|
+
requestToPerform.url !== "elm-pages-internal://port" &&
|
|
184
|
+
requestToPerform.url.startsWith("elm-pages-internal://")
|
|
185
|
+
) {
|
|
186
|
+
runInternalJob(
|
|
187
|
+
app,
|
|
188
|
+
mode,
|
|
189
|
+
requestToPerform,
|
|
190
|
+
fs,
|
|
191
|
+
hasFsAccess,
|
|
192
|
+
patternsToWatch
|
|
193
|
+
);
|
|
194
|
+
} else {
|
|
195
|
+
runHttpJob(
|
|
196
|
+
portsFile,
|
|
197
|
+
app,
|
|
198
|
+
mode,
|
|
199
|
+
requestToPerform,
|
|
200
|
+
fs,
|
|
201
|
+
hasFsAccess,
|
|
202
|
+
fromElm.args[1]
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
} else if (fromElm.tag === "Errors") {
|
|
206
|
+
foundErrors = true;
|
|
207
|
+
reject(fromElm.args[0].errorsJson);
|
|
208
|
+
} else {
|
|
209
|
+
console.log(fromElm);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
app.ports.toJsPort.subscribe(portHandler);
|
|
213
|
+
app.ports.sendPageData.subscribe(portHandler);
|
|
214
|
+
}).finally(() => {
|
|
215
|
+
try {
|
|
216
|
+
killApp();
|
|
217
|
+
killApp = null;
|
|
218
|
+
} catch (error) {}
|
|
219
|
+
});
|
|
220
|
+
}
|
|
65
221
|
|
|
66
222
|
/**
|
|
67
223
|
* @param {string} basePath
|
|
@@ -98,6 +254,7 @@ function runElmApp(
|
|
|
98
254
|
app = elmModule.Elm.Main.init({
|
|
99
255
|
flags: {
|
|
100
256
|
mode,
|
|
257
|
+
compatibilityKey,
|
|
101
258
|
request: {
|
|
102
259
|
payload: modifiedRequest,
|
|
103
260
|
kind: "single-page",
|
|
@@ -300,7 +457,9 @@ async function runInternalJob(
|
|
|
300
457
|
try {
|
|
301
458
|
pendingDataSourceCount += 1;
|
|
302
459
|
|
|
303
|
-
if (requestToPerform.url === "elm-pages-internal://
|
|
460
|
+
if (requestToPerform.url === "elm-pages-internal://log") {
|
|
461
|
+
pendingDataSourceResponses.push(await runLogJob(requestToPerform));
|
|
462
|
+
} else if (requestToPerform.url === "elm-pages-internal://read-file") {
|
|
304
463
|
pendingDataSourceResponses.push(
|
|
305
464
|
await readFileJobNew(requestToPerform, patternsToWatch)
|
|
306
465
|
);
|
|
@@ -320,6 +479,8 @@ async function runInternalJob(
|
|
|
320
479
|
pendingDataSourceResponses.push(
|
|
321
480
|
await runDecryptJob(requestToPerform, patternsToWatch)
|
|
322
481
|
);
|
|
482
|
+
} else if (requestToPerform.url === "elm-pages-internal://write-file") {
|
|
483
|
+
pendingDataSourceResponses.push(await runWriteFileJob(requestToPerform));
|
|
323
484
|
} else {
|
|
324
485
|
throw `Unexpected internal DataSource request format: ${kleur.yellow(
|
|
325
486
|
JSON.stringify(2, null, requestToPerform)
|
|
@@ -360,6 +521,23 @@ async function readFileJobNew(req, patternsToWatch) {
|
|
|
360
521
|
};
|
|
361
522
|
}
|
|
362
523
|
}
|
|
524
|
+
async function runWriteFileJob(req) {
|
|
525
|
+
const data = req.body.args[0];
|
|
526
|
+
try {
|
|
527
|
+
const fullPathToWrite = path.join(process.cwd(), data.path);
|
|
528
|
+
await fsPromises.mkdir(path.dirname(fullPathToWrite), { recursive: true });
|
|
529
|
+
await fsPromises.writeFile(fullPathToWrite, data.body);
|
|
530
|
+
return jsonResponse(req, null);
|
|
531
|
+
} catch (error) {
|
|
532
|
+
console.trace(error);
|
|
533
|
+
throw {
|
|
534
|
+
title: "DataSource Error",
|
|
535
|
+
message: `DataSource.Generator.writeFile failed for file path: ${kleur.yellow(
|
|
536
|
+
data.path
|
|
537
|
+
)}\n${kleur.red(error.toString())}`,
|
|
538
|
+
};
|
|
539
|
+
}
|
|
540
|
+
}
|
|
363
541
|
|
|
364
542
|
async function runGlobNew(req, patternsToWatch) {
|
|
365
543
|
try {
|
|
@@ -382,6 +560,15 @@ async function runGlobNew(req, patternsToWatch) {
|
|
|
382
560
|
}
|
|
383
561
|
}
|
|
384
562
|
|
|
563
|
+
async function runLogJob(req) {
|
|
564
|
+
try {
|
|
565
|
+
console.log(req.body.args[0].message);
|
|
566
|
+
return jsonResponse(req, null);
|
|
567
|
+
} catch (e) {
|
|
568
|
+
console.log(`Error performing env '${JSON.stringify(req.body)}'`);
|
|
569
|
+
throw e;
|
|
570
|
+
}
|
|
571
|
+
}
|
|
385
572
|
async function runEnvJob(req, patternsToWatch) {
|
|
386
573
|
try {
|
|
387
574
|
const expectedEnv = req.body.args[0];
|
|
@@ -24,6 +24,7 @@ function fullPath(portsHash, request, hasFsAccess) {
|
|
|
24
24
|
if (hasFsAccess) {
|
|
25
25
|
return path.join(
|
|
26
26
|
process.cwd(),
|
|
27
|
+
// TODO use parameter or something other than global for this `global.isRunningGenerator` condition
|
|
27
28
|
".elm-pages",
|
|
28
29
|
"http-response-cache",
|
|
29
30
|
requestToString(requestWithPortHash)
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
const fs = require("fs");
|
|
2
2
|
|
|
3
|
-
module.exports = async function () {
|
|
3
|
+
module.exports = async function (sourceElmJsonPath, targetElmJsonPath) {
|
|
4
4
|
var elmJson = JSON.parse(
|
|
5
|
-
(await fs.promises.readFile(
|
|
5
|
+
(await fs.promises.readFile(sourceElmJsonPath)).toString()
|
|
6
6
|
);
|
|
7
7
|
|
|
8
8
|
// write new elm.json
|
|
9
9
|
|
|
10
10
|
await writeFileIfChanged(
|
|
11
|
-
|
|
11
|
+
targetElmJsonPath,
|
|
12
12
|
JSON.stringify(rewriteElmJson(elmJson))
|
|
13
13
|
);
|
|
14
14
|
};
|
|
@@ -43,11 +43,16 @@ function headTag(rootModifiers) {
|
|
|
43
43
|
|
|
44
44
|
function toString(/** @type { SeoTag[] } */ tags) {
|
|
45
45
|
return tags
|
|
46
|
-
.
|
|
46
|
+
.flatMap((headTag) => {
|
|
47
47
|
if (headTag.type === "head") {
|
|
48
|
-
return appendTag(headTag);
|
|
48
|
+
return [appendTag(headTag)];
|
|
49
49
|
} else if (headTag.type === "json-ld") {
|
|
50
|
-
return appendJsonLdTag(headTag);
|
|
50
|
+
return [appendJsonLdTag(headTag)];
|
|
51
|
+
} else if (headTag.type === "stripped") {
|
|
52
|
+
console.warn(
|
|
53
|
+
`WARNING: Head.nonLoadingTag value ignored because it used a loading tag: ${headTag.message}`
|
|
54
|
+
);
|
|
55
|
+
return [];
|
|
51
56
|
} else {
|
|
52
57
|
throw new Error(`Unknown tag type ${JSON.stringify(headTag)}`);
|
|
53
58
|
}
|
|
@@ -55,7 +60,7 @@ function toString(/** @type { SeoTag[] } */ tags) {
|
|
|
55
60
|
.join("");
|
|
56
61
|
}
|
|
57
62
|
|
|
58
|
-
/** @typedef {HeadTag | JsonLdTag} SeoTag */
|
|
63
|
+
/** @typedef {HeadTag | JsonLdTag | StrippedTag} SeoTag */
|
|
59
64
|
|
|
60
65
|
/** @typedef {{ name: string; attributes: string[][]; type: 'head' }} HeadTag */
|
|
61
66
|
function appendTag(/** @type {HeadTag} */ tagDetails) {
|
|
@@ -66,6 +71,8 @@ function appendTag(/** @type {HeadTag} */ tagDetails) {
|
|
|
66
71
|
}
|
|
67
72
|
|
|
68
73
|
/** @typedef {{ contents: Object; type: 'json-ld' }} JsonLdTag */
|
|
74
|
+
/** @typedef {{ message: string; type: 'stripped' }} StrippedTag */
|
|
75
|
+
|
|
69
76
|
function appendJsonLdTag(/** @type {JsonLdTag} */ tagDetails) {
|
|
70
77
|
return `<script type="application/ld+json">
|
|
71
78
|
${JSON.stringify(tagDetails.contents)}
|