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.
Files changed (28) hide show
  1. package/README.md +10 -1
  2. package/codegen/elm-pages-codegen.js +1 -1
  3. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/d.dat +0 -0
  4. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/o.dat +0 -0
  5. package/generator/dead-code-review/elm-stuff/tests-0.19.1/elm.json +1 -1
  6. package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/Reporter.elm.js +1 -1
  7. package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/Runner.elm.js +1 -1
  8. package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/node_runner.js +1 -1
  9. package/generator/dead-code-review/elm-stuff/tests-0.19.1/js/node_supervisor.js +4 -4
  10. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/d.dat +0 -0
  11. package/generator/review/elm-stuff/tests-0.19.1/elm-stuff/0.19.1/o.dat +0 -0
  12. package/generator/review/elm-stuff/tests-0.19.1/elm.json +1 -1
  13. package/generator/review/elm-stuff/tests-0.19.1/js/Reporter.elm.js +1 -1
  14. package/generator/review/elm-stuff/tests-0.19.1/js/Runner.elm.js +1 -1
  15. package/generator/review/elm-stuff/tests-0.19.1/js/node_runner.js +1 -1
  16. package/generator/review/elm-stuff/tests-0.19.1/js/node_supervisor.js +4 -4
  17. package/generator/src/build.js +11 -11
  18. package/generator/src/dev-server.js +15 -6
  19. package/generator/src/render.js +2 -0
  20. package/generator/src/seo-renderer.js +11 -4
  21. package/package.json +1 -1
  22. package/src/ApiRoute.elm +0 -3
  23. package/src/DataSource.elm +11 -3
  24. package/src/Head.elm +126 -0
  25. package/src/Pages/Generate.elm +101 -10
  26. package/src/Pages/Internal/Platform/Cli.elm +50 -6
  27. package/src/Pages/Internal/Platform/Cli.elm.bak +1276 -0
  28. package/src/Pages/Internal/Platform/CompatibilityKey.elm +6 -0
package/README.md CHANGED
@@ -1,7 +1,9 @@
1
1
  # `elm-pages` [![Netlify Status](https://api.netlify.com/api/v1/badges/8ee4a674-4f37-4f16-b99e-607c0a02ee75/deploy-status)](https://app.netlify.com/sites/elm-pages/deploys) [![Build Status](https://github.com/dillonkearns/elm-pages/workflows/Elm%20CI/badge.svg)](https://github.com/dillonkearns/elm-pages/actions?query=branch%3Amaster) [![npm](https://img.shields.io/npm/v/elm-pages.svg)](https://npmjs.com/package/elm-pages) [![Elm package](https://img.shields.io/elm-package/v/dillonkearns/elm-pages.svg)](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
  [![All Contributors](https://img.shields.io/badge/all_contributors-5-orange.svg?style=flat-square)](#contributors-)
6
+
5
7
  <!-- ALL-CONTRIBUTORS-BADGE:END -->
6
8
 
7
9
  [![Deploy to Netlify](https://www.netlify.com/img/deploy/button.svg)](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
  {
@@ -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.6.0","miniBill/elm-unicode":"1.0.2","rtfeldman/elm-hex":"1.0.0","stil4m/structured-writer":"1.0.3"}},"test-dependencies":{"direct":{},"indirect":{}}}
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: 343221655, fuzzRuns: 100, filter: null };
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 = 2;
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: 343221655,
85
+ initialSeed: 3518984952,
86
86
  fuzzRuns: 100,
87
- mode: "consoleNoColor",
87
+ mode: "consoleColor",
88
88
  verbosity: verbosity,
89
89
  globs: [],
90
- paths: ["/home/runner/work/elm-pages-v3-beta/elm-pages-v3-beta/generator/dead-code-review/tests/Pages/Review/DeadCodeEliminateDataTest.elm"],
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
 
@@ -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.6.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":{}}}
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: 2255331163, fuzzRuns: 100, filter: null };
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 = 2;
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: 2255331163,
85
+ initialSeed: 188222656,
86
86
  fuzzRuns: 100,
87
- mode: "consoleNoColor",
87
+ mode: "consoleColor",
88
88
  verbosity: verbosity,
89
89
  globs: [],
90
- paths: ["/home/runner/work/elm-pages-v3-beta/elm-pages-v3-beta/generator/review/tests/Pages/Review/NoContractViolationsTest.elm"],
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
 
@@ -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: "error",
158
+ logLevel: "silent",
158
159
  })
159
160
  .then((result) => {
160
- global.portsFilePath = Object.keys(result.metafile.outputs)[0];
161
+ try {
162
+ global.portsFilePath = Object.keys(result.metafile.outputs)[0];
163
+ } catch (e) {}
161
164
  })
162
165
  .catch((error) => {
163
- if (
164
- error.errors.length === 1 &&
165
- error.errors[0].text.includes(
166
- `Could not resolve "./port-data-source"`
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: "error",
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
- global.portsFilePath = Object.keys(result.metafile.outputs)[0];
161
+ try {
162
+ global.portsFilePath = Object.keys(result.metafile.outputs)[0];
161
163
 
162
- clients.forEach((client) => {
163
- client.response.write(`data: content.dat\n\n`);
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
- console.error("Failed to start port-data-source watcher", error);
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()
@@ -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
- .map((headTag) => {
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "elm-pages",
3
- "version": "3.0.0-beta.8",
3
+ "version": "3.0.0-beta.9",
4
4
  "homepage": "https://elm-pages.com",
5
5
  "moduleResolution": "node",
6
6
  "description": "Type-safe static sites, written in pure elm with your own custom elm-markup syntax.",
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
@@ -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 page can define a value `data` which is a `DataSource` that will be resolved **before** `init` is called. That means it is also available
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
- ## Where Does DataSource Data Come From?
23
+ ## DataSource's vs. Effect's/Cmd's
24
24
 
25
- Data from a `DataSource` is resolved when you load a page in the `elm-pages` dev server, or when you run `elm-pages build`.
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 ) =