@bleedingdev/modern-js-app-tools 3.5.0-ultramodern.19 → 3.5.0-ultramodern.20

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.
@@ -648,21 +648,40 @@ async function collectRenderedRemoteCssHrefs(html, request, env) {
648
648
  function escapeAttribute(value) {
649
649
  return String(value).replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
650
650
  }
651
+ function isAbsoluteUrl(value) {
652
+ return /^[a-z][a-z\d+.-]*:/iu.test(value);
653
+ }
654
+ function toRouteCssHtmlHref(asset) {
655
+ if (isAbsoluteUrl(asset) || asset.startsWith('/')) return asset;
656
+ return `/${asset.replace(/^\/+/u, '')}`;
657
+ }
651
658
  async function withRouteCssLinks(response, route, routeManifest, request, env) {
652
659
  const contentType = response.headers.get('content-type') || '';
653
660
  if (!contentType.includes('text/html')) return response;
654
661
  const html = await response.text();
655
- const cssHrefs = [
656
- ...collectRouteCssAssets(route, routeManifest).map((asset)=>new URL(asset, request.url).toString()),
657
- ...await collectRenderedRemoteCssHrefs(html, request, env)
658
- ];
659
- if (0 === cssHrefs.length) return response;
660
- const uniqueCssHrefs = [
661
- ...new Set(cssHrefs)
662
+ const cssEntries = [
663
+ ...collectRouteCssAssets(route, routeManifest).map((asset)=>{
664
+ const href = toRouteCssHtmlHref(asset);
665
+ return {
666
+ href,
667
+ preloadHref: new URL(href, request.url).toString()
668
+ };
669
+ }),
670
+ ...(await collectRenderedRemoteCssHrefs(html, request, env)).map((href)=>({
671
+ href,
672
+ preloadHref: new URL(href, request.url).toString()
673
+ }))
662
674
  ];
675
+ if (0 === cssEntries.length) return response;
676
+ const seenCssHrefs = new Set();
677
+ const uniqueCssEntries = cssEntries.filter((entry)=>{
678
+ if (seenCssHrefs.has(entry.preloadHref)) return false;
679
+ seenCssHrefs.add(entry.preloadHref);
680
+ return true;
681
+ });
663
682
  const headers = new Headers(response.headers);
664
- for (const href of uniqueCssHrefs)headers.append('link', `<${href}>; rel=preload; as=style`);
665
- const links = uniqueCssHrefs.filter((href)=>!html.includes(href)).map((href)=>`<link rel="stylesheet" href="${escapeAttribute(href)}">`);
683
+ for (const { preloadHref } of uniqueCssEntries)headers.append('link', `<${preloadHref}>; rel=preload; as=style`);
684
+ const links = uniqueCssEntries.filter(({ href, preloadHref })=>!html.includes(href) && !html.includes(preloadHref)).map(({ href })=>`<link rel="stylesheet" href="${escapeAttribute(href)}">`);
666
685
  if (0 === links.length || !html.includes('</head>')) return new Response(html, {
667
686
  headers,
668
687
  status: response.status,
@@ -648,21 +648,40 @@ async function collectRenderedRemoteCssHrefs(html, request, env) {
648
648
  function escapeAttribute(value) {
649
649
  return String(value).replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
650
650
  }
651
+ function isAbsoluteUrl(value) {
652
+ return /^[a-z][a-z\d+.-]*:/iu.test(value);
653
+ }
654
+ function toRouteCssHtmlHref(asset) {
655
+ if (isAbsoluteUrl(asset) || asset.startsWith('/')) return asset;
656
+ return `/${asset.replace(/^\/+/u, '')}`;
657
+ }
651
658
  async function withRouteCssLinks(response, route, routeManifest, request, env) {
652
659
  const contentType = response.headers.get('content-type') || '';
653
660
  if (!contentType.includes('text/html')) return response;
654
661
  const html = await response.text();
655
- const cssHrefs = [
656
- ...collectRouteCssAssets(route, routeManifest).map((asset)=>new URL(asset, request.url).toString()),
657
- ...await collectRenderedRemoteCssHrefs(html, request, env)
658
- ];
659
- if (0 === cssHrefs.length) return response;
660
- const uniqueCssHrefs = [
661
- ...new Set(cssHrefs)
662
+ const cssEntries = [
663
+ ...collectRouteCssAssets(route, routeManifest).map((asset)=>{
664
+ const href = toRouteCssHtmlHref(asset);
665
+ return {
666
+ href,
667
+ preloadHref: new URL(href, request.url).toString()
668
+ };
669
+ }),
670
+ ...(await collectRenderedRemoteCssHrefs(html, request, env)).map((href)=>({
671
+ href,
672
+ preloadHref: new URL(href, request.url).toString()
673
+ }))
662
674
  ];
675
+ if (0 === cssEntries.length) return response;
676
+ const seenCssHrefs = new Set();
677
+ const uniqueCssEntries = cssEntries.filter((entry)=>{
678
+ if (seenCssHrefs.has(entry.preloadHref)) return false;
679
+ seenCssHrefs.add(entry.preloadHref);
680
+ return true;
681
+ });
663
682
  const headers = new Headers(response.headers);
664
- for (const href of uniqueCssHrefs)headers.append('link', `<${href}>; rel=preload; as=style`);
665
- const links = uniqueCssHrefs.filter((href)=>!html.includes(href)).map((href)=>`<link rel="stylesheet" href="${escapeAttribute(href)}">`);
683
+ for (const { preloadHref } of uniqueCssEntries)headers.append('link', `<${preloadHref}>; rel=preload; as=style`);
684
+ const links = uniqueCssEntries.filter(({ href, preloadHref })=>!html.includes(href) && !html.includes(preloadHref)).map(({ href })=>`<link rel="stylesheet" href="${escapeAttribute(href)}">`);
666
685
  if (0 === links.length || !html.includes('</head>')) return new Response(html, {
667
686
  headers,
668
687
  status: response.status,
@@ -648,21 +648,40 @@ async function collectRenderedRemoteCssHrefs(html, request, env) {
648
648
  function escapeAttribute(value) {
649
649
  return String(value).replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
650
650
  }
651
+ function isAbsoluteUrl(value) {
652
+ return /^[a-z][a-z\d+.-]*:/iu.test(value);
653
+ }
654
+ function toRouteCssHtmlHref(asset) {
655
+ if (isAbsoluteUrl(asset) || asset.startsWith('/')) return asset;
656
+ return `/${asset.replace(/^\/+/u, '')}`;
657
+ }
651
658
  async function withRouteCssLinks(response, route, routeManifest, request, env) {
652
659
  const contentType = response.headers.get('content-type') || '';
653
660
  if (!contentType.includes('text/html')) return response;
654
661
  const html = await response.text();
655
- const cssHrefs = [
656
- ...collectRouteCssAssets(route, routeManifest).map((asset)=>new URL(asset, request.url).toString()),
657
- ...await collectRenderedRemoteCssHrefs(html, request, env)
658
- ];
659
- if (0 === cssHrefs.length) return response;
660
- const uniqueCssHrefs = [
661
- ...new Set(cssHrefs)
662
+ const cssEntries = [
663
+ ...collectRouteCssAssets(route, routeManifest).map((asset)=>{
664
+ const href = toRouteCssHtmlHref(asset);
665
+ return {
666
+ href,
667
+ preloadHref: new URL(href, request.url).toString()
668
+ };
669
+ }),
670
+ ...(await collectRenderedRemoteCssHrefs(html, request, env)).map((href)=>({
671
+ href,
672
+ preloadHref: new URL(href, request.url).toString()
673
+ }))
662
674
  ];
675
+ if (0 === cssEntries.length) return response;
676
+ const seenCssHrefs = new Set();
677
+ const uniqueCssEntries = cssEntries.filter((entry)=>{
678
+ if (seenCssHrefs.has(entry.preloadHref)) return false;
679
+ seenCssHrefs.add(entry.preloadHref);
680
+ return true;
681
+ });
663
682
  const headers = new Headers(response.headers);
664
- for (const href of uniqueCssHrefs)headers.append('link', `<${href}>; rel=preload; as=style`);
665
- const links = uniqueCssHrefs.filter((href)=>!html.includes(href)).map((href)=>`<link rel="stylesheet" href="${escapeAttribute(href)}">`);
683
+ for (const { preloadHref } of uniqueCssEntries)headers.append('link', `<${preloadHref}>; rel=preload; as=style`);
684
+ const links = uniqueCssEntries.filter(({ href, preloadHref })=>!html.includes(href) && !html.includes(preloadHref)).map(({ href })=>`<link rel="stylesheet" href="${escapeAttribute(href)}">`);
666
685
  if (0 === links.length || !html.includes('</head>')) return new Response(html, {
667
686
  headers,
668
687
  status: response.status,
package/package.json CHANGED
@@ -17,7 +17,7 @@
17
17
  "modern",
18
18
  "modern.js"
19
19
  ],
20
- "version": "3.5.0-ultramodern.19",
20
+ "version": "3.5.0-ultramodern.20",
21
21
  "types": "./dist/types/index.d.ts",
22
22
  "main": "./dist/cjs/index.js",
23
23
  "exports": {
@@ -90,16 +90,16 @@
90
90
  "ndepe": "^0.1.13",
91
91
  "pkg-types": "^2.3.1",
92
92
  "std-env": "4.1.0",
93
- "@modern-js/builder": "npm:@bleedingdev/modern-js-builder@3.5.0-ultramodern.19",
94
- "@modern-js/plugin": "npm:@bleedingdev/modern-js-plugin@3.5.0-ultramodern.19",
95
- "@modern-js/plugin-data-loader": "npm:@bleedingdev/modern-js-plugin-data-loader@3.5.0-ultramodern.19",
96
- "@modern-js/prod-server": "npm:@bleedingdev/modern-js-prod-server@3.5.0-ultramodern.19",
97
- "@modern-js/server": "npm:@bleedingdev/modern-js-server@3.5.0-ultramodern.19",
98
- "@modern-js/i18n-utils": "npm:@bleedingdev/modern-js-i18n-utils@3.5.0-ultramodern.19",
99
- "@modern-js/server-utils": "npm:@bleedingdev/modern-js-server-utils@3.5.0-ultramodern.19",
100
- "@modern-js/server-core": "npm:@bleedingdev/modern-js-server-core@3.5.0-ultramodern.19",
101
- "@modern-js/types": "npm:@bleedingdev/modern-js-types@3.5.0-ultramodern.19",
102
- "@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.5.0-ultramodern.19"
93
+ "@modern-js/builder": "npm:@bleedingdev/modern-js-builder@3.5.0-ultramodern.20",
94
+ "@modern-js/i18n-utils": "npm:@bleedingdev/modern-js-i18n-utils@3.5.0-ultramodern.20",
95
+ "@modern-js/plugin": "npm:@bleedingdev/modern-js-plugin@3.5.0-ultramodern.20",
96
+ "@modern-js/plugin-data-loader": "npm:@bleedingdev/modern-js-plugin-data-loader@3.5.0-ultramodern.20",
97
+ "@modern-js/prod-server": "npm:@bleedingdev/modern-js-prod-server@3.5.0-ultramodern.20",
98
+ "@modern-js/server": "npm:@bleedingdev/modern-js-server@3.5.0-ultramodern.20",
99
+ "@modern-js/server-core": "npm:@bleedingdev/modern-js-server-core@3.5.0-ultramodern.20",
100
+ "@modern-js/server-utils": "npm:@bleedingdev/modern-js-server-utils@3.5.0-ultramodern.20",
101
+ "@modern-js/types": "npm:@bleedingdev/modern-js-types@3.5.0-ultramodern.20",
102
+ "@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.5.0-ultramodern.20"
103
103
  },
104
104
  "devDependencies": {
105
105
  "@rslib/core": "0.23.1",