elm-pages 3.0.0-beta.8 → 3.0.0-beta.9
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 +1 -1
- 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/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 +1 -1
- package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/Runner.elm.js +1 -1
- 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 +4 -4
- 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/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 +1 -1
- package/generator/review/elm-stuff/tests-0.19.1/js/Runner.elm.js +1 -1
- 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 +4 -4
- package/generator/src/build.js +11 -11
- package/generator/src/dev-server.js +15 -6
- package/generator/src/render.js +2 -0
- package/generator/src/seo-renderer.js +11 -4
- package/package.json +1 -1
- package/src/ApiRoute.elm +0 -3
- package/src/DataSource.elm +11 -3
- package/src/Head.elm +126 -0
- package/src/Pages/Generate.elm +101 -10
- package/src/Pages/Internal/Platform/Cli.elm +50 -6
- package/src/Pages/Internal/Platform/Cli.elm.bak +1276 -0
- package/src/Pages/Internal/Platform/CompatibilityKey.elm +6 -0
package/README.md
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
# `elm-pages` [](https://app.netlify.com/sites/elm-pages/deploys) [](https://github.com/dillonkearns/elm-pages/actions?query=branch%3Amaster) [](https://npmjs.com/package/elm-pages) [](https://package.elm-lang.org/packages/dillonkearns/elm-pages/latest/)
|
|
2
2
|
|
|
3
3
|
<!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section -->
|
|
4
|
+
|
|
4
5
|
[](#contributors-)
|
|
6
|
+
|
|
5
7
|
<!-- ALL-CONTRIBUTORS-BADGE:END -->
|
|
6
8
|
|
|
7
9
|
[](https://app.netlify.com/start/deploy?repository=https://github.com/dillonkearns/elm-pages-starter)
|
|
@@ -68,13 +70,19 @@ Try out `elm-pages`, open up Lighthouse, and
|
|
|
68
70
|
see for yourself! Or check out https://elm-pages.com
|
|
69
71
|
(find the source code in the [`examples/docs/`](https://github.com/dillonkearns/elm-pages/tree/master/examples/docs) folder).
|
|
70
72
|
|
|
71
|
-
|
|
72
73
|
## What's next?
|
|
73
74
|
|
|
74
75
|
Take a look at the current projects to see the current priorities!
|
|
75
76
|
|
|
76
77
|
https://github.com/dillonkearns/elm-pages/projects
|
|
77
78
|
|
|
79
|
+
## Compatibility Key
|
|
80
|
+
|
|
81
|
+
You will see an error if the NPM and Elm package do not have a matching Compatibility Key. Usually it's best to upgrade to the latest version of both the Elm and NPM
|
|
82
|
+
packages when you upgrade. However, in case you want to install versions that are behind the latest, the Compatibility Key is included here for reference.
|
|
83
|
+
|
|
84
|
+
Current Compatibility Key: 1.
|
|
85
|
+
|
|
78
86
|
## Contributors ✨
|
|
79
87
|
|
|
80
88
|
Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
|
|
@@ -94,6 +102,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
|
|
|
94
102
|
|
|
95
103
|
<!-- markdownlint-enable -->
|
|
96
104
|
<!-- prettier-ignore-end -->
|
|
105
|
+
|
|
97
106
|
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
|
98
107
|
|
|
99
108
|
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
|
|
@@ -38923,7 +38923,7 @@ _Platform_export({'Generate':{'init':$author$project$Generate$main(
|
|
|
38923
38923
|
$elm$json$Json$Decode$field,
|
|
38924
38924
|
'templates',
|
|
38925
38925
|
$elm$json$Json$Decode$list(
|
|
38926
|
-
$elm$json$Json$Decode$list($elm$json$Json$Decode$string)))))(0)}});var isBackend = false && typeof isLamdera !== 'undefined'
|
|
38926
|
+
$elm$json$Json$Decode$list($elm$json$Json$Decode$string)))))(0)}});var isBackend = false && typeof isLamdera !== 'undefined';
|
|
38927
38927
|
|
|
38928
38928
|
function _Platform_initialize(flagDecoder, args, init, update, subscriptions, stepperBuilder)
|
|
38929
38929
|
{
|
|
Binary file
|
|
Binary file
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"type":"application","source-directories":["../../src","../../tests","../../../../src","src"],"elm-version":"0.19.1","dependencies":{"direct":{"elm/core":"1.0.5","elm/json":"1.1.3","elm-community/result-extra":"2.4.0","elm-explorations/test":"1.2.2","jfmengels/elm-review":"2.4.2","mpizenberg/elm-test-runner":"5.0.0","stil4m/elm-syntax":"7.2.5"},"indirect":{"elm/html":"1.0.0","elm/parser":"1.1.0","elm/project-metadata-utils":"1.0.2","elm/random":"1.0.0","elm/time":"1.0.0","elm/virtual-dom":"1.0.3","elm-community/list-extra":"8.
|
|
1
|
+
{"type":"application","source-directories":["../../src","../../tests","../../../../src","src"],"elm-version":"0.19.1","dependencies":{"direct":{"elm/core":"1.0.5","elm/json":"1.1.3","elm-community/result-extra":"2.4.0","elm-explorations/test":"1.2.2","jfmengels/elm-review":"2.4.2","mpizenberg/elm-test-runner":"5.0.0","stil4m/elm-syntax":"7.2.5"},"indirect":{"elm/html":"1.0.0","elm/parser":"1.1.0","elm/project-metadata-utils":"1.0.2","elm/random":"1.0.0","elm/time":"1.0.0","elm/virtual-dom":"1.0.3","elm-community/list-extra":"8.7.0","miniBill/elm-unicode":"1.0.2","rtfeldman/elm-hex":"1.0.0","stil4m/structured-writer":"1.0.3"}},"test-dependencies":{"direct":{},"indirect":{}}}
|
|
@@ -6692,7 +6692,7 @@ _Platform_export({'Reporter':{'init':$author$project$Reporter$main(
|
|
|
6692
6692
|
'paths',
|
|
6693
6693
|
$elm$json$Json$Decode$list($elm$json$Json$Decode$string)));
|
|
6694
6694
|
},
|
|
6695
|
-
A2($elm$json$Json$Decode$field, 'verbosity', $elm$json$Json$Decode$int)))(0)}});var isBackend = false && typeof isLamdera !== 'undefined'
|
|
6695
|
+
A2($elm$json$Json$Decode$field, 'verbosity', $elm$json$Json$Decode$int)))(0)}});var isBackend = false && typeof isLamdera !== 'undefined';
|
|
6696
6696
|
|
|
6697
6697
|
function _Platform_initialize(flagDecoder, args, init, update, subscriptions, stepperBuilder)
|
|
6698
6698
|
{
|
|
@@ -25732,7 +25732,7 @@ _Platform_export({'Runner':{'init':$author$project$Runner$main(
|
|
|
25732
25732
|
},
|
|
25733
25733
|
A2($elm$json$Json$Decode$field, 'fuzzRuns', $elm$json$Json$Decode$int));
|
|
25734
25734
|
},
|
|
25735
|
-
A2($elm$json$Json$Decode$field, 'initialSeed', $elm$json$Json$Decode$int)))(0)}});var isBackend = false && typeof isLamdera !== 'undefined'
|
|
25735
|
+
A2($elm$json$Json$Decode$field, 'initialSeed', $elm$json$Json$Decode$int)))(0)}});var isBackend = false && typeof isLamdera !== 'undefined';
|
|
25736
25736
|
|
|
25737
25737
|
function _Platform_initialize(flagDecoder, args, init, update, subscriptions, stepperBuilder)
|
|
25738
25738
|
{
|
|
@@ -75,7 +75,7 @@ console.elmlog = (str) => logs.push(str + "\n");
|
|
|
75
75
|
const { Elm } = require("./Runner.elm.js");
|
|
76
76
|
|
|
77
77
|
// Start the Elm app
|
|
78
|
-
const flags = { initialSeed:
|
|
78
|
+
const flags = { initialSeed: 3518984952, fuzzRuns: 100, filter: null };
|
|
79
79
|
const app = Elm.Runner.init({ flags: flags });
|
|
80
80
|
|
|
81
81
|
// Record the timing at which we received the last "runTest" message
|
|
@@ -75,19 +75,19 @@ let testsCount, todoTests;
|
|
|
75
75
|
let reporter;
|
|
76
76
|
let runners = [];
|
|
77
77
|
let working = false;
|
|
78
|
-
let workersCount =
|
|
78
|
+
let workersCount = 10;
|
|
79
79
|
let startWorkCallback = function(){};
|
|
80
80
|
const verbosity = 0;
|
|
81
81
|
|
|
82
82
|
// Create a long lived reporter worker
|
|
83
83
|
const { Elm } = require("./Reporter.elm.js");
|
|
84
84
|
const flags = {
|
|
85
|
-
initialSeed:
|
|
85
|
+
initialSeed: 3518984952,
|
|
86
86
|
fuzzRuns: 100,
|
|
87
|
-
mode: "
|
|
87
|
+
mode: "consoleColor",
|
|
88
88
|
verbosity: verbosity,
|
|
89
89
|
globs: [],
|
|
90
|
-
paths: ["/
|
|
90
|
+
paths: ["/Users/dillonkearns/src/github.com/dillonkearns/elm-pages-v3-beta/generator/dead-code-review/tests/Pages/Review/DeadCodeEliminateDataTest.elm"],
|
|
91
91
|
};
|
|
92
92
|
reporter = Elm.Reporter.init({ flags: flags });
|
|
93
93
|
|
|
Binary file
|
|
Binary file
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"type":"application","source-directories":["../../src","../../tests","../../../../src","src"],"elm-version":"0.19.1","dependencies":{"direct":{"elm/core":"1.0.5","elm/html":"1.0.0","elm/json":"1.1.3","elm/regex":"1.0.0","elm-community/result-extra":"2.4.0","elm-explorations/test":"1.2.2","jfmengels/elm-review":"2.4.2","mdgriffith/elm-codegen":"2.0.0","mpizenberg/elm-test-runner":"5.0.0","stil4m/elm-syntax":"7.2.5","the-sett/elm-syntax-dsl":"6.0.2"},"indirect":{"Chadtech/elm-bool-extra":"2.4.2","elm/parser":"1.1.0","elm/project-metadata-utils":"1.0.2","elm/random":"1.0.0","elm/time":"1.0.0","elm/virtual-dom":"1.0.3","elm-community/basics-extra":"4.1.0","elm-community/list-extra":"8.
|
|
1
|
+
{"type":"application","source-directories":["../../src","../../tests","../../../../src","src"],"elm-version":"0.19.1","dependencies":{"direct":{"elm/core":"1.0.5","elm/html":"1.0.0","elm/json":"1.1.3","elm/regex":"1.0.0","elm-community/result-extra":"2.4.0","elm-explorations/test":"1.2.2","jfmengels/elm-review":"2.4.2","mdgriffith/elm-codegen":"2.0.0","mpizenberg/elm-test-runner":"5.0.0","stil4m/elm-syntax":"7.2.5","the-sett/elm-syntax-dsl":"6.0.2"},"indirect":{"Chadtech/elm-bool-extra":"2.4.2","elm/parser":"1.1.0","elm/project-metadata-utils":"1.0.2","elm/random":"1.0.0","elm/time":"1.0.0","elm/virtual-dom":"1.0.3","elm-community/basics-extra":"4.1.0","elm-community/list-extra":"8.7.0","elm-community/maybe-extra":"5.3.0","miniBill/elm-unicode":"1.0.2","rtfeldman/elm-hex":"1.0.0","stil4m/structured-writer":"1.0.3","the-sett/elm-pretty-printer":"3.0.0"}},"test-dependencies":{"direct":{},"indirect":{}}}
|
|
@@ -6692,7 +6692,7 @@ _Platform_export({'Reporter':{'init':$author$project$Reporter$main(
|
|
|
6692
6692
|
'paths',
|
|
6693
6693
|
$elm$json$Json$Decode$list($elm$json$Json$Decode$string)));
|
|
6694
6694
|
},
|
|
6695
|
-
A2($elm$json$Json$Decode$field, 'verbosity', $elm$json$Json$Decode$int)))(0)}});var isBackend = false && typeof isLamdera !== 'undefined'
|
|
6695
|
+
A2($elm$json$Json$Decode$field, 'verbosity', $elm$json$Json$Decode$int)))(0)}});var isBackend = false && typeof isLamdera !== 'undefined';
|
|
6696
6696
|
|
|
6697
6697
|
function _Platform_initialize(flagDecoder, args, init, update, subscriptions, stepperBuilder)
|
|
6698
6698
|
{
|
|
@@ -27514,7 +27514,7 @@ _Platform_export({'Runner':{'init':$author$project$Runner$main(
|
|
|
27514
27514
|
},
|
|
27515
27515
|
A2($elm$json$Json$Decode$field, 'fuzzRuns', $elm$json$Json$Decode$int));
|
|
27516
27516
|
},
|
|
27517
|
-
A2($elm$json$Json$Decode$field, 'initialSeed', $elm$json$Json$Decode$int)))(0)}});var isBackend = false && typeof isLamdera !== 'undefined'
|
|
27517
|
+
A2($elm$json$Json$Decode$field, 'initialSeed', $elm$json$Json$Decode$int)))(0)}});var isBackend = false && typeof isLamdera !== 'undefined';
|
|
27518
27518
|
|
|
27519
27519
|
function _Platform_initialize(flagDecoder, args, init, update, subscriptions, stepperBuilder)
|
|
27520
27520
|
{
|
|
@@ -75,7 +75,7 @@ console.elmlog = (str) => logs.push(str + "\n");
|
|
|
75
75
|
const { Elm } = require("./Runner.elm.js");
|
|
76
76
|
|
|
77
77
|
// Start the Elm app
|
|
78
|
-
const flags = { initialSeed:
|
|
78
|
+
const flags = { initialSeed: 188222656, fuzzRuns: 100, filter: null };
|
|
79
79
|
const app = Elm.Runner.init({ flags: flags });
|
|
80
80
|
|
|
81
81
|
// Record the timing at which we received the last "runTest" message
|
|
@@ -75,19 +75,19 @@ let testsCount, todoTests;
|
|
|
75
75
|
let reporter;
|
|
76
76
|
let runners = [];
|
|
77
77
|
let working = false;
|
|
78
|
-
let workersCount =
|
|
78
|
+
let workersCount = 10;
|
|
79
79
|
let startWorkCallback = function(){};
|
|
80
80
|
const verbosity = 0;
|
|
81
81
|
|
|
82
82
|
// Create a long lived reporter worker
|
|
83
83
|
const { Elm } = require("./Reporter.elm.js");
|
|
84
84
|
const flags = {
|
|
85
|
-
initialSeed:
|
|
85
|
+
initialSeed: 188222656,
|
|
86
86
|
fuzzRuns: 100,
|
|
87
|
-
mode: "
|
|
87
|
+
mode: "consoleColor",
|
|
88
88
|
verbosity: verbosity,
|
|
89
89
|
globs: [],
|
|
90
|
-
paths: ["/
|
|
90
|
+
paths: ["/Users/dillonkearns/src/github.com/dillonkearns/elm-pages-v3-beta/generator/review/tests/Pages/Review/NoContractViolationsTest.elm"],
|
|
91
91
|
};
|
|
92
92
|
reporter = Elm.Reporter.init({ flags: flags });
|
|
93
93
|
|
package/generator/src/build.js
CHANGED
|
@@ -18,6 +18,7 @@ const esbuild = require("esbuild");
|
|
|
18
18
|
const { createHash } = require("crypto");
|
|
19
19
|
const { merge_vite_configs } = require("./vite-utils.js");
|
|
20
20
|
const { resolveConfig } = require("./config.js");
|
|
21
|
+
const globby = require("globby");
|
|
21
22
|
|
|
22
23
|
let pool = [];
|
|
23
24
|
let pagesReady;
|
|
@@ -154,21 +155,20 @@ async function run(options) {
|
|
|
154
155
|
metafile: true,
|
|
155
156
|
bundle: true,
|
|
156
157
|
watch: false,
|
|
157
|
-
logLevel: "
|
|
158
|
+
logLevel: "silent",
|
|
158
159
|
})
|
|
159
160
|
.then((result) => {
|
|
160
|
-
|
|
161
|
+
try {
|
|
162
|
+
global.portsFilePath = Object.keys(result.metafile.outputs)[0];
|
|
163
|
+
} catch (e) {}
|
|
161
164
|
})
|
|
162
165
|
.catch((error) => {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
console.warn("No port-data-source file found.");
|
|
170
|
-
} else {
|
|
171
|
-
console.error("Failed to load port-data-source file", error);
|
|
166
|
+
const portDataSourceFileFound =
|
|
167
|
+
globby.sync("./port-data-source.*").length > 0;
|
|
168
|
+
if (portDataSourceFileFound) {
|
|
169
|
+
// don't present error if there are no files matching port-data-source
|
|
170
|
+
// if there are files matching port-data-source, warn the user in case something went wrong loading it
|
|
171
|
+
console.error("Failed to start port-data-source watcher", error);
|
|
172
172
|
}
|
|
173
173
|
});
|
|
174
174
|
// TODO extract common code for compiling ports file?
|
|
@@ -27,6 +27,7 @@ const esbuild = require("esbuild");
|
|
|
27
27
|
const { merge_vite_configs } = require("./vite-utils.js");
|
|
28
28
|
const { templateHtml } = require("./pre-render-html.js");
|
|
29
29
|
const { resolveConfig } = require("./config.js");
|
|
30
|
+
const globby = require("globby");
|
|
30
31
|
|
|
31
32
|
/**
|
|
32
33
|
* @param {{ port: string; base: string; https: boolean; debug: boolean; }} options
|
|
@@ -147,7 +148,7 @@ async function start(options) {
|
|
|
147
148
|
metafile: true,
|
|
148
149
|
bundle: true,
|
|
149
150
|
watch: true,
|
|
150
|
-
logLevel: "
|
|
151
|
+
logLevel: "silent",
|
|
151
152
|
|
|
152
153
|
outdir: ".elm-pages/compiled-ports",
|
|
153
154
|
entryNames: "[dir]/[name]-[hash]",
|
|
@@ -157,11 +158,13 @@ async function start(options) {
|
|
|
157
158
|
name: "example",
|
|
158
159
|
setup(build) {
|
|
159
160
|
build.onEnd((result) => {
|
|
160
|
-
|
|
161
|
+
try {
|
|
162
|
+
global.portsFilePath = Object.keys(result.metafile.outputs)[0];
|
|
161
163
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
164
|
+
clients.forEach((client) => {
|
|
165
|
+
client.response.write(`data: content.dat\n\n`);
|
|
166
|
+
});
|
|
167
|
+
} catch (e) {}
|
|
165
168
|
});
|
|
166
169
|
},
|
|
167
170
|
},
|
|
@@ -171,7 +174,13 @@ async function start(options) {
|
|
|
171
174
|
console.log("Watching port-data-source...");
|
|
172
175
|
})
|
|
173
176
|
.catch((error) => {
|
|
174
|
-
|
|
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
|
+
}
|
|
175
184
|
});
|
|
176
185
|
|
|
177
186
|
const app = connect()
|
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) => {
|
|
@@ -98,6 +99,7 @@ function runElmApp(
|
|
|
98
99
|
app = elmModule.Elm.Main.init({
|
|
99
100
|
flags: {
|
|
100
101
|
mode,
|
|
102
|
+
compatibilityKey,
|
|
101
103
|
request: {
|
|
102
104
|
payload: modifiedRequest,
|
|
103
105
|
kind: "single-page",
|
|
@@ -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)}
|
package/package.json
CHANGED
package/src/ApiRoute.elm
CHANGED
|
@@ -11,9 +11,6 @@ module ApiRoute exposing
|
|
|
11
11
|
to a DataSource so you can pull in HTTP data, etc. Because ApiRoutes don't hydrate into Elm apps (like pages in elm-pages do), you can pull in as much data as you want in
|
|
12
12
|
the DataSource for your ApiRoutes, and it won't effect the payload size. Instead, the size of an ApiRoute is just the content you output for that route.
|
|
13
13
|
|
|
14
|
-
In a future release, ApiRoutes may be able to run at request-time in a serverless function, allowing you to use pure Elm code to create dynamic APIs, and even pulling in data from
|
|
15
|
-
DataSources dynamically.
|
|
16
|
-
|
|
17
14
|
@docs ApiRoute, ApiRouteBuilder, Response
|
|
18
15
|
|
|
19
16
|
@docs capture, literal, slash, succeed
|
package/src/DataSource.elm
CHANGED
|
@@ -7,7 +7,7 @@ module DataSource exposing
|
|
|
7
7
|
, map2, map3, map4, map5, map6, map7, map8, map9
|
|
8
8
|
)
|
|
9
9
|
|
|
10
|
-
{-| In an `elm-pages` app, each
|
|
10
|
+
{-| In an `elm-pages` app, each Route Module can define a value `data` which is a `DataSource` that will be resolved **before** `init` is called. That means it is also available
|
|
11
11
|
when the page's HTML is pre-rendered during the build step. You can also access the resolved data in `head` to use it for the page's SEO meta tags.
|
|
12
12
|
|
|
13
13
|
A `DataSource` lets you pull in data from:
|
|
@@ -20,9 +20,17 @@ A `DataSource` lets you pull in data from:
|
|
|
20
20
|
- Or any combination of the above, using `DataSource.map2`, `DataSource.andThen`, or other combining/continuing helpers from this module
|
|
21
21
|
|
|
22
22
|
|
|
23
|
-
##
|
|
23
|
+
## DataSource's vs. Effect's/Cmd's
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
DataSource's are always resolved before the page is rendered and sent to the browser. A DataSource is never executed
|
|
26
|
+
in the Browser. Instead, the resolved data from the DataSource is passed down to the Browser - it has been resolved
|
|
27
|
+
before any client-side JavaScript ever executes. In the case of a pre-rendered route, this is during the CLI build phase,
|
|
28
|
+
and for server-rendered routes its DataSource is resolved on the server.
|
|
29
|
+
|
|
30
|
+
Effect's/Cmd's are never executed on the CLI or server, they are only executed in the Browser. The data from a Route Module's
|
|
31
|
+
`init` function is used to render the initial HTML on the server or build step, but the Effect isn't executed and `update` is never called
|
|
32
|
+
before the page is hydrated in the Browser. This gives a deterministic mental model of what the first render will look like,
|
|
33
|
+
and a nicely typed way to define the initial `Data` you have to render your initial view.
|
|
26
34
|
|
|
27
35
|
Because `elm-pages` hydrates into a full Elm single-page app, it does need the data in order to initialize the Elm app.
|
|
28
36
|
So why not just get the data the old-fashioned way, with `elm/http`, for example?
|
package/src/Head.elm
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
module Head exposing
|
|
2
2
|
( Tag, metaName, metaProperty, metaRedirect
|
|
3
3
|
, rssLink, sitemapLink, rootLanguage, manifestLink
|
|
4
|
+
, nonLoadingNode
|
|
4
5
|
, structuredData
|
|
5
6
|
, AttributeValue
|
|
6
7
|
, currentPageFullUrl, urlAttribute, raw
|
|
@@ -20,6 +21,8 @@ writing a plugin package to extend `elm-pages`.
|
|
|
20
21
|
@docs Tag, metaName, metaProperty, metaRedirect
|
|
21
22
|
@docs rssLink, sitemapLink, rootLanguage, manifestLink
|
|
22
23
|
|
|
24
|
+
@docs nonLoadingNode
|
|
25
|
+
|
|
23
26
|
|
|
24
27
|
## Structured Data
|
|
25
28
|
|
|
@@ -45,9 +48,11 @@ writing a plugin package to extend `elm-pages`.
|
|
|
45
48
|
|
|
46
49
|
import Json.Encode
|
|
47
50
|
import LanguageTag exposing (LanguageTag)
|
|
51
|
+
import List.Extra
|
|
48
52
|
import MimeType
|
|
49
53
|
import Pages.Internal.String as String
|
|
50
54
|
import Pages.Url
|
|
55
|
+
import Regex
|
|
51
56
|
|
|
52
57
|
|
|
53
58
|
{-| Values that can be passed to the generated `Pages.application` config
|
|
@@ -57,6 +62,7 @@ type Tag
|
|
|
57
62
|
= Tag Details
|
|
58
63
|
| StructuredData Json.Encode.Value
|
|
59
64
|
| RootModifier String String
|
|
65
|
+
| Stripped String
|
|
60
66
|
|
|
61
67
|
|
|
62
68
|
type alias Details =
|
|
@@ -211,6 +217,120 @@ canonicalLink maybePath =
|
|
|
211
217
|
]
|
|
212
218
|
|
|
213
219
|
|
|
220
|
+
{-| Escape hatch for any head tags that don't have high-level helpers. This lets you build arbitrary head nodes as long as they
|
|
221
|
+
are not loading or preloading directives.
|
|
222
|
+
|
|
223
|
+
Tags that do loading/pre-loading will not work from this function. `elm-pages` uses ViteJS for loading assets like
|
|
224
|
+
script tags, stylesheets, fonts, etc., and allows you to customize which assets to preload and how through the elm-pages.config.mjs file.
|
|
225
|
+
See the full discussion of the design in [#339](https://github.com/dillonkearns/elm-pages/discussions/339).
|
|
226
|
+
|
|
227
|
+
So for example the following tags would _not_ load if defined through `nonLoadingNode`, and would instead need to be registered through Vite:
|
|
228
|
+
|
|
229
|
+
- `<script src="...">`
|
|
230
|
+
- `<link href="/style.css">`
|
|
231
|
+
- `<link rel="preload">`
|
|
232
|
+
|
|
233
|
+
The following tag would successfully render as it is a non-loading tag:
|
|
234
|
+
|
|
235
|
+
Head.nonLoadingNode "link"
|
|
236
|
+
[ ( "rel", Head.raw "alternate" )
|
|
237
|
+
, ( "type", Head.raw "application/atom+xml" )
|
|
238
|
+
, ( "title", Head.raw "News" )
|
|
239
|
+
, ( "href", Head.raw "/news/atom" )
|
|
240
|
+
]
|
|
241
|
+
|
|
242
|
+
Renders the head tag:
|
|
243
|
+
|
|
244
|
+
`<link rel="alternate" type="application/atom+xml" title="News" href="/news/atom">`
|
|
245
|
+
|
|
246
|
+
-}
|
|
247
|
+
nonLoadingNode : String -> List ( String, AttributeValue ) -> Tag
|
|
248
|
+
nonLoadingNode nodeName attributes =
|
|
249
|
+
let
|
|
250
|
+
relTag : Maybe AttributeValue
|
|
251
|
+
relTag =
|
|
252
|
+
attributes
|
|
253
|
+
|> List.Extra.find (\( key, _ ) -> key == "rel")
|
|
254
|
+
|> Maybe.map Tuple.second
|
|
255
|
+
|
|
256
|
+
isPreloadDirective : Bool
|
|
257
|
+
isPreloadDirective =
|
|
258
|
+
case relTag of
|
|
259
|
+
Just (Raw rel) ->
|
|
260
|
+
let
|
|
261
|
+
isLinkTag : Bool
|
|
262
|
+
isLinkTag =
|
|
263
|
+
nodeName |> matchesKeyword "link"
|
|
264
|
+
in
|
|
265
|
+
isLinkTag
|
|
266
|
+
&& (rel
|
|
267
|
+
|> matchesOneKeyword
|
|
268
|
+
[ "preload"
|
|
269
|
+
, "modulepreload"
|
|
270
|
+
, "preconnect"
|
|
271
|
+
, "dns-prefetch"
|
|
272
|
+
, "stylesheet"
|
|
273
|
+
]
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
_ ->
|
|
277
|
+
False
|
|
278
|
+
in
|
|
279
|
+
if
|
|
280
|
+
(nodeName |> matchesKeyword "script")
|
|
281
|
+
|| isPreloadDirective
|
|
282
|
+
then
|
|
283
|
+
Stripped
|
|
284
|
+
("<"
|
|
285
|
+
++ nodeName
|
|
286
|
+
++ " "
|
|
287
|
+
++ (attributes
|
|
288
|
+
|> List.map
|
|
289
|
+
(\( name, value ) ->
|
|
290
|
+
name
|
|
291
|
+
++ "=\""
|
|
292
|
+
++ ((case value of
|
|
293
|
+
Raw rawValue ->
|
|
294
|
+
rawValue
|
|
295
|
+
|
|
296
|
+
_ ->
|
|
297
|
+
"<internals>"
|
|
298
|
+
)
|
|
299
|
+
++ "\""
|
|
300
|
+
)
|
|
301
|
+
)
|
|
302
|
+
|> String.join " "
|
|
303
|
+
)
|
|
304
|
+
++ " />"
|
|
305
|
+
)
|
|
306
|
+
|
|
307
|
+
else
|
|
308
|
+
node nodeName attributes
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
matchesOneKeyword : List String -> String -> Bool
|
|
312
|
+
matchesOneKeyword keywords string =
|
|
313
|
+
List.any
|
|
314
|
+
(\keyword -> string |> matchesKeyword keyword)
|
|
315
|
+
keywords
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
matchesKeyword : String -> String -> Bool
|
|
319
|
+
matchesKeyword regex string =
|
|
320
|
+
string |> matchesRegex ("^\\s*" ++ regex ++ "\\s*$")
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
matchesRegex : String -> String -> Bool
|
|
324
|
+
matchesRegex regex string =
|
|
325
|
+
string
|
|
326
|
+
|> Regex.contains
|
|
327
|
+
(Regex.fromStringWith
|
|
328
|
+
{ caseInsensitive = True, multiline = True }
|
|
329
|
+
regex
|
|
330
|
+
|> Maybe.withDefault Regex.never
|
|
331
|
+
)
|
|
332
|
+
|
|
333
|
+
|
|
214
334
|
{-| Let's you link to your manifest.json file, see <https://developer.mozilla.org/en-US/docs/Web/Manifest#deploying_a_manifest>.
|
|
215
335
|
-}
|
|
216
336
|
manifestLink : String -> Tag
|
|
@@ -443,6 +563,12 @@ toJson canonicalSiteUrl currentPagePath tag =
|
|
|
443
563
|
, ( "keyValuePair", Json.Encode.list Json.Encode.string [ key, value ] )
|
|
444
564
|
]
|
|
445
565
|
|
|
566
|
+
Stripped message ->
|
|
567
|
+
Json.Encode.object
|
|
568
|
+
[ ( "type", Json.Encode.string "stripped" )
|
|
569
|
+
, ( "message", Json.Encode.string message )
|
|
570
|
+
]
|
|
571
|
+
|
|
446
572
|
|
|
447
573
|
encodeProperty : String -> String -> ( String, AttributeValue ) -> Json.Encode.Value
|
|
448
574
|
encodeProperty canonicalSiteUrl currentPagePath ( name, value ) =
|