@tanstack/start-plugin-core 1.121.0-alpha.2 → 1.121.0-alpha.21
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/dist/cjs/constants.cjs +4 -0
- package/dist/cjs/constants.cjs.map +1 -1
- package/dist/cjs/constants.d.cts +2 -0
- package/dist/cjs/{extractHtmlScripts.cjs → dev-server-plugin/extract-html-scripts.cjs} +1 -1
- package/dist/cjs/dev-server-plugin/extract-html-scripts.cjs.map +1 -0
- package/dist/cjs/{nitro/dev-server-plugin.cjs → dev-server-plugin/plugin.cjs} +2 -2
- package/dist/cjs/dev-server-plugin/plugin.cjs.map +1 -0
- package/dist/cjs/index.cjs +2 -0
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +1 -0
- package/dist/cjs/load-env-plugin/plugin.cjs +34 -0
- package/dist/cjs/load-env-plugin/plugin.cjs.map +1 -0
- package/dist/cjs/load-env-plugin/plugin.d.cts +3 -0
- package/dist/cjs/nitro-plugin/build-sitemap.cjs +138 -0
- package/dist/cjs/nitro-plugin/build-sitemap.cjs.map +1 -0
- package/dist/cjs/nitro-plugin/build-sitemap.d.cts +31 -0
- package/dist/cjs/{nitro/nitro-plugin.cjs → nitro-plugin/plugin.cjs} +77 -54
- package/dist/cjs/nitro-plugin/plugin.cjs.map +1 -0
- package/dist/cjs/{prerender.cjs → nitro-plugin/prerender.cjs} +12 -17
- package/dist/cjs/nitro-plugin/prerender.cjs.map +1 -0
- package/dist/cjs/{prerender.d.cts → nitro-plugin/prerender.d.cts} +1 -1
- package/dist/cjs/nitro-plugin/queue.cjs.map +1 -0
- package/dist/cjs/plugin.cjs +38 -27
- package/dist/cjs/plugin.cjs.map +1 -1
- package/dist/cjs/plugin.d.cts +25 -3064
- package/dist/cjs/resolve-virtual-entries-plugin/plugin.cjs +66 -0
- package/dist/cjs/resolve-virtual-entries-plugin/plugin.cjs.map +1 -0
- package/dist/cjs/resolve-virtual-entries-plugin/plugin.d.cts +3 -0
- package/dist/cjs/schema.cjs +6 -4
- package/dist/cjs/schema.cjs.map +1 -1
- package/dist/cjs/schema.d.cts +530 -1656
- package/dist/cjs/start-compiler-plugin.cjs +2 -2
- package/dist/cjs/start-compiler-plugin.cjs.map +1 -1
- package/dist/cjs/start-compiler-plugin.d.cts +1 -1
- package/dist/cjs/{routesManifestPlugin.cjs → start-routes-manifest-plugin/plugin.cjs} +86 -44
- package/dist/cjs/start-routes-manifest-plugin/plugin.cjs.map +1 -0
- package/dist/cjs/start-routes-manifest-plugin/plugin.d.cts +3 -0
- package/dist/cjs/start-server-routes-plugin/plugin.cjs +4 -2
- package/dist/cjs/start-server-routes-plugin/plugin.cjs.map +1 -1
- package/dist/cjs/utils.cjs +18 -0
- package/dist/cjs/utils.cjs.map +1 -0
- package/dist/cjs/utils.d.cts +8 -0
- package/dist/esm/constants.d.ts +2 -0
- package/dist/esm/constants.js +4 -0
- package/dist/esm/constants.js.map +1 -1
- package/dist/esm/{extractHtmlScripts.js → dev-server-plugin/extract-html-scripts.js} +1 -1
- package/dist/esm/dev-server-plugin/extract-html-scripts.js.map +1 -0
- package/dist/esm/{nitro/dev-server-plugin.js → dev-server-plugin/plugin.js} +2 -2
- package/dist/esm/dev-server-plugin/plugin.js.map +1 -0
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +3 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/load-env-plugin/plugin.d.ts +3 -0
- package/dist/esm/load-env-plugin/plugin.js +17 -0
- package/dist/esm/load-env-plugin/plugin.js.map +1 -0
- package/dist/esm/nitro-plugin/build-sitemap.d.ts +31 -0
- package/dist/esm/nitro-plugin/build-sitemap.js +138 -0
- package/dist/esm/nitro-plugin/build-sitemap.js.map +1 -0
- package/dist/esm/nitro-plugin/plugin.js +181 -0
- package/dist/esm/nitro-plugin/plugin.js.map +1 -0
- package/dist/esm/{prerender.d.ts → nitro-plugin/prerender.d.ts} +1 -1
- package/dist/esm/{prerender.js → nitro-plugin/prerender.js} +12 -17
- package/dist/esm/nitro-plugin/prerender.js.map +1 -0
- package/dist/esm/nitro-plugin/queue.js.map +1 -0
- package/dist/esm/plugin.d.ts +25 -3064
- package/dist/esm/plugin.js +39 -28
- package/dist/esm/plugin.js.map +1 -1
- package/dist/esm/resolve-virtual-entries-plugin/plugin.d.ts +3 -0
- package/dist/esm/resolve-virtual-entries-plugin/plugin.js +49 -0
- package/dist/esm/resolve-virtual-entries-plugin/plugin.js.map +1 -0
- package/dist/esm/schema.d.ts +530 -1656
- package/dist/esm/schema.js +6 -4
- package/dist/esm/schema.js.map +1 -1
- package/dist/esm/start-compiler-plugin.d.ts +1 -1
- package/dist/esm/start-compiler-plugin.js +2 -2
- package/dist/esm/start-compiler-plugin.js.map +1 -1
- package/dist/esm/start-routes-manifest-plugin/plugin.d.ts +3 -0
- package/dist/esm/{routesManifestPlugin.js → start-routes-manifest-plugin/plugin.js} +87 -45
- package/dist/esm/start-routes-manifest-plugin/plugin.js.map +1 -0
- package/dist/esm/start-server-routes-plugin/plugin.js +4 -2
- package/dist/esm/start-server-routes-plugin/plugin.js.map +1 -1
- package/dist/esm/utils.d.ts +8 -0
- package/dist/esm/utils.js +18 -0
- package/dist/esm/utils.js.map +1 -0
- package/package.json +6 -6
- package/src/constants.ts +3 -0
- package/src/{nitro/dev-server-plugin.ts → dev-server-plugin/plugin.ts} +11 -1
- package/src/index.ts +1 -0
- package/src/load-env-plugin/plugin.ts +17 -0
- package/src/nitro-plugin/build-sitemap.ts +213 -0
- package/src/nitro-plugin/plugin.ts +244 -0
- package/src/{prerender.ts → nitro-plugin/prerender.ts} +14 -21
- package/src/plugin.ts +57 -29
- package/src/resolve-virtual-entries-plugin/plugin.ts +63 -0
- package/src/schema.ts +11 -9
- package/src/start-compiler-plugin.ts +1 -1
- package/src/{routesManifestPlugin.ts → start-routes-manifest-plugin/plugin.ts} +111 -45
- package/src/start-server-routes-plugin/plugin.ts +4 -2
- package/src/utils.ts +14 -0
- package/dist/cjs/extractHtmlScripts.cjs.map +0 -1
- package/dist/cjs/nitro/build-nitro.cjs +0 -18
- package/dist/cjs/nitro/build-nitro.cjs.map +0 -1
- package/dist/cjs/nitro/build-nitro.d.cts +0 -2
- package/dist/cjs/nitro/build-sitemap.d.cts +0 -9
- package/dist/cjs/nitro/dev-server-plugin.cjs.map +0 -1
- package/dist/cjs/nitro/nitro-plugin.cjs.map +0 -1
- package/dist/cjs/prerender.cjs.map +0 -1
- package/dist/cjs/queue.cjs.map +0 -1
- package/dist/cjs/routesManifestPlugin.cjs.map +0 -1
- package/dist/cjs/routesManifestPlugin.d.cts +0 -3
- package/dist/esm/extractHtmlScripts.js.map +0 -1
- package/dist/esm/nitro/build-nitro.d.ts +0 -2
- package/dist/esm/nitro/build-nitro.js +0 -18
- package/dist/esm/nitro/build-nitro.js.map +0 -1
- package/dist/esm/nitro/build-sitemap.d.ts +0 -9
- package/dist/esm/nitro/dev-server-plugin.js.map +0 -1
- package/dist/esm/nitro/nitro-plugin.js +0 -158
- package/dist/esm/nitro/nitro-plugin.js.map +0 -1
- package/dist/esm/prerender.js.map +0 -1
- package/dist/esm/queue.js.map +0 -1
- package/dist/esm/routesManifestPlugin.d.ts +0 -3
- package/dist/esm/routesManifestPlugin.js.map +0 -1
- package/src/nitro/build-nitro.ts +0 -27
- package/src/nitro/build-sitemap.ts +0 -79
- package/src/nitro/nitro-plugin.ts +0 -199
- /package/dist/cjs/{extractHtmlScripts.d.cts → dev-server-plugin/extract-html-scripts.d.cts} +0 -0
- /package/dist/cjs/{nitro/dev-server-plugin.d.cts → dev-server-plugin/plugin.d.cts} +0 -0
- /package/dist/cjs/{nitro/nitro-plugin.d.cts → nitro-plugin/plugin.d.cts} +0 -0
- /package/dist/cjs/{queue.cjs → nitro-plugin/queue.cjs} +0 -0
- /package/dist/cjs/{queue.d.cts → nitro-plugin/queue.d.cts} +0 -0
- /package/dist/esm/{extractHtmlScripts.d.ts → dev-server-plugin/extract-html-scripts.d.ts} +0 -0
- /package/dist/esm/{nitro/dev-server-plugin.d.ts → dev-server-plugin/plugin.d.ts} +0 -0
- /package/dist/esm/{nitro/nitro-plugin.d.ts → nitro-plugin/plugin.d.ts} +0 -0
- /package/dist/esm/{queue.d.ts → nitro-plugin/queue.d.ts} +0 -0
- /package/dist/esm/{queue.js → nitro-plugin/queue.js} +0 -0
- /package/src/{extractHtmlScripts.ts → dev-server-plugin/extract-html-scripts.ts} +0 -0
- /package/src/{queue.ts → nitro-plugin/queue.ts} +0 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
function resolveViteId(id) {
|
|
2
|
+
return `\0${id}`;
|
|
3
|
+
}
|
|
4
|
+
function createLogger(prefix) {
|
|
5
|
+
const label = `[${prefix}]`;
|
|
6
|
+
return {
|
|
7
|
+
log: (...args) => console.log(label, ...args),
|
|
8
|
+
debug: (...args) => console.debug(label, ...args),
|
|
9
|
+
info: (...args) => console.info(label, ...args),
|
|
10
|
+
warn: (...args) => console.warn(label, ...args),
|
|
11
|
+
error: (...args) => console.error(label, ...args)
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export {
|
|
15
|
+
createLogger,
|
|
16
|
+
resolveViteId
|
|
17
|
+
};
|
|
18
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sources":["../../src/utils.ts"],"sourcesContent":["export function resolveViteId(id: string) {\n return `\\0${id}`\n}\n\nexport function createLogger(prefix: string) {\n const label = `[${prefix}]`\n return {\n log: (...args: any) => console.log(label, ...args),\n debug: (...args: any) => console.debug(label, ...args),\n info: (...args: any) => console.info(label, ...args),\n warn: (...args: any) => console.warn(label, ...args),\n error: (...args: any) => console.error(label, ...args),\n }\n}\n"],"names":[],"mappings":"AAAO,SAAS,cAAc,IAAY;AACxC,SAAO,KAAK,EAAE;AAChB;AAEO,SAAS,aAAa,QAAgB;AACrC,QAAA,QAAQ,IAAI,MAAM;AACjB,SAAA;AAAA,IACL,KAAK,IAAI,SAAc,QAAQ,IAAI,OAAO,GAAG,IAAI;AAAA,IACjD,OAAO,IAAI,SAAc,QAAQ,MAAM,OAAO,GAAG,IAAI;AAAA,IACrD,MAAM,IAAI,SAAc,QAAQ,KAAK,OAAO,GAAG,IAAI;AAAA,IACnD,MAAM,IAAI,SAAc,QAAQ,KAAK,OAAO,GAAG,IAAI;AAAA,IACnD,OAAO,IAAI,SAAc,QAAQ,MAAM,OAAO,GAAG,IAAI;AAAA,EACvD;AACF;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tanstack/start-plugin-core",
|
|
3
|
-
"version": "1.121.0-alpha.
|
|
3
|
+
"version": "1.121.0-alpha.21",
|
|
4
4
|
"description": "Modern and scalable routing for React applications",
|
|
5
5
|
"author": "Tanner Linsley",
|
|
6
6
|
"license": "MIT",
|
|
@@ -58,16 +58,16 @@
|
|
|
58
58
|
"babel-dead-code-elimination": "^1.0.9",
|
|
59
59
|
"cheerio": "^1.0.0",
|
|
60
60
|
"h3": "1.13.0",
|
|
61
|
-
"nitropack": "^2.11.
|
|
61
|
+
"nitropack": "^2.11.12",
|
|
62
62
|
"pathe": "^2.0.3",
|
|
63
63
|
"ufo": "^1.5.4",
|
|
64
64
|
"xmlbuilder2": "^3.1.1",
|
|
65
65
|
"zod": "^3.24.2",
|
|
66
|
-
"@tanstack/router-core": "^1.121.0-alpha.
|
|
67
|
-
"@tanstack/router-generator": "^1.121.0-alpha.
|
|
68
|
-
"@tanstack/router-plugin": "^1.121.0-alpha.2",
|
|
66
|
+
"@tanstack/router-core": "^1.121.0-alpha.14",
|
|
67
|
+
"@tanstack/router-generator": "^1.121.0-alpha.14",
|
|
69
68
|
"@tanstack/router-utils": "^1.121.0-alpha.2",
|
|
70
|
-
"@tanstack/server-functions-plugin": "^1.121.0-alpha.
|
|
69
|
+
"@tanstack/server-functions-plugin": "^1.121.0-alpha.8",
|
|
70
|
+
"@tanstack/router-plugin": "^1.121.0-alpha.14"
|
|
71
71
|
},
|
|
72
72
|
"devDependencies": {
|
|
73
73
|
"vite": "^6.0.0"
|
package/src/constants.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createEvent, getHeader, sendWebResponse } from 'h3'
|
|
2
2
|
import { isRunnableDevEnvironment } from 'vite'
|
|
3
|
-
import { extractHtmlScripts } from '../extractHtmlScripts'
|
|
4
3
|
import { VITE_ENVIRONMENT_NAMES } from '../constants'
|
|
4
|
+
import { extractHtmlScripts } from './extract-html-scripts'
|
|
5
5
|
import type { Connect, DevEnvironment, Plugin, ViteDevServer } from 'vite'
|
|
6
6
|
|
|
7
7
|
declare global {
|
|
@@ -29,8 +29,12 @@ export function devServerPlugin(): Plugin {
|
|
|
29
29
|
return () => {
|
|
30
30
|
remove_html_middlewares(viteDevServer.middlewares)
|
|
31
31
|
let cachedScripts: string | undefined
|
|
32
|
+
|
|
32
33
|
viteDevServer.middlewares.use(async (req, res) => {
|
|
34
|
+
// Create an H3Event to have it passed into the server entry
|
|
35
|
+
// i.e: event => defineEventHandler(event)
|
|
33
36
|
const event = createEvent(req, res)
|
|
37
|
+
|
|
34
38
|
const serverEnv = viteDevServer.environments[
|
|
35
39
|
VITE_ENVIRONMENT_NAMES.server
|
|
36
40
|
] as DevEnvironment | undefined
|
|
@@ -41,11 +45,14 @@ export function devServerPlugin(): Plugin {
|
|
|
41
45
|
`Server environment ${VITE_ENVIRONMENT_NAMES.server} not found`,
|
|
42
46
|
)
|
|
43
47
|
}
|
|
48
|
+
|
|
44
49
|
if (!isRunnableDevEnvironment(serverEnv)) {
|
|
45
50
|
throw new Error(
|
|
46
51
|
`Expected server environment ${VITE_ENVIRONMENT_NAMES.server} to be a RunnableDevEnvironment. This can be caused by multiple vite versions being installed in the project.`,
|
|
47
52
|
)
|
|
48
53
|
}
|
|
54
|
+
|
|
55
|
+
// Extract the scripts that Vite plugins would inject into the initial HTML
|
|
49
56
|
if (cachedScripts === undefined) {
|
|
50
57
|
const templateHtml = `<html><head></head><body></body></html>`
|
|
51
58
|
const transformedHtml = await viteDevServer.transformIndexHtml(
|
|
@@ -57,6 +64,9 @@ export function devServerPlugin(): Plugin {
|
|
|
57
64
|
.map((script) => script.content ?? '')
|
|
58
65
|
.join(';')
|
|
59
66
|
}
|
|
67
|
+
|
|
68
|
+
// Import and resolve the request by running the server entry point
|
|
69
|
+
// i.e export default defineEventHandler((event) => { ... })
|
|
60
70
|
const serverEntry = await serverEnv.runner.import(
|
|
61
71
|
'/~start/server-entry',
|
|
62
72
|
)
|
package/src/index.ts
CHANGED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import * as vite from 'vite'
|
|
2
|
+
import type { TanStackStartOutputConfig } from '../plugin'
|
|
3
|
+
|
|
4
|
+
export function loadEnvPlugin(
|
|
5
|
+
startOpts: TanStackStartOutputConfig,
|
|
6
|
+
): vite.Plugin {
|
|
7
|
+
return {
|
|
8
|
+
name: 'tanstack-vite-plugin-nitro-load-env',
|
|
9
|
+
enforce: 'pre',
|
|
10
|
+
config(userConfig, envConfig) {
|
|
11
|
+
Object.assign(
|
|
12
|
+
process.env,
|
|
13
|
+
vite.loadEnv(envConfig.mode, userConfig.root ?? startOpts.root, ''),
|
|
14
|
+
)
|
|
15
|
+
},
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { writeFileSync } from 'node:fs'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
import { create } from 'xmlbuilder2'
|
|
4
|
+
import { createLogger } from '../utils'
|
|
5
|
+
import type { TanStackStartOutputConfig } from '../plugin'
|
|
6
|
+
import type { XMLBuilder } from 'xmlbuilder2/lib/interfaces'
|
|
7
|
+
|
|
8
|
+
export type SitemapUrl = {
|
|
9
|
+
loc: string
|
|
10
|
+
lastmod: string
|
|
11
|
+
priority?: number
|
|
12
|
+
changefreq?:
|
|
13
|
+
| 'always'
|
|
14
|
+
| 'hourly'
|
|
15
|
+
| 'daily'
|
|
16
|
+
| 'weekly'
|
|
17
|
+
| 'monthly'
|
|
18
|
+
| 'yearly'
|
|
19
|
+
| 'never'
|
|
20
|
+
alternateRefs?: Array<{
|
|
21
|
+
href: string
|
|
22
|
+
hreflang?: string
|
|
23
|
+
}>
|
|
24
|
+
images?: Array<{
|
|
25
|
+
loc: string
|
|
26
|
+
title?: string
|
|
27
|
+
caption?: string
|
|
28
|
+
}>
|
|
29
|
+
news?: {
|
|
30
|
+
publication: {
|
|
31
|
+
name: string
|
|
32
|
+
language: string
|
|
33
|
+
}
|
|
34
|
+
publicationDate: string | Date
|
|
35
|
+
title: string
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export type SitemapData = {
|
|
40
|
+
urls: Array<SitemapUrl>
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function buildSitemapJson(
|
|
44
|
+
pages: TanStackStartOutputConfig['pages'],
|
|
45
|
+
host: string,
|
|
46
|
+
): SitemapData {
|
|
47
|
+
const slash = checkSlash(host)
|
|
48
|
+
|
|
49
|
+
const urls: Array<SitemapUrl> = pages
|
|
50
|
+
.filter((page) => {
|
|
51
|
+
return page.sitemap?.exclude !== true
|
|
52
|
+
})
|
|
53
|
+
.map((page) => ({
|
|
54
|
+
loc: `${host}${slash}${page.path.replace(/^\/+/g, '')}`,
|
|
55
|
+
lastmod: page.sitemap?.lastmod
|
|
56
|
+
? new Date(page.sitemap.lastmod).toISOString().split('T')[0]!
|
|
57
|
+
: new Date().toISOString().split('T')[0]!,
|
|
58
|
+
priority: page.sitemap?.priority,
|
|
59
|
+
changefreq: page.sitemap?.changefreq,
|
|
60
|
+
alternateRefs: page.sitemap?.alternateRefs,
|
|
61
|
+
images: page.sitemap?.images,
|
|
62
|
+
news: page.sitemap?.news,
|
|
63
|
+
}))
|
|
64
|
+
|
|
65
|
+
return { urls }
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function jsonToXml(sitemapData: SitemapData): string {
|
|
69
|
+
const sitemap = createXml('urlset')
|
|
70
|
+
|
|
71
|
+
for (const item of sitemapData.urls) {
|
|
72
|
+
const page = sitemap.ele('url')
|
|
73
|
+
page.ele('loc').txt(item.loc)
|
|
74
|
+
page.ele('lastmod').txt(item.lastmod)
|
|
75
|
+
|
|
76
|
+
if (item.priority !== undefined) {
|
|
77
|
+
page.ele('priority').txt(item.priority.toString())
|
|
78
|
+
}
|
|
79
|
+
if (item.changefreq) {
|
|
80
|
+
page.ele('changefreq').txt(item.changefreq)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Add alternate references
|
|
84
|
+
if (item.alternateRefs?.length) {
|
|
85
|
+
for (const ref of item.alternateRefs) {
|
|
86
|
+
const alternateRef = page.ele('xhtml:link')
|
|
87
|
+
alternateRef.att('rel', 'alternate')
|
|
88
|
+
alternateRef.att('href', ref.href)
|
|
89
|
+
if (ref.hreflang) {
|
|
90
|
+
alternateRef.att('hreflang', ref.hreflang)
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Add images
|
|
96
|
+
if (item.images?.length) {
|
|
97
|
+
for (const image of item.images) {
|
|
98
|
+
const imageElement = page.ele('image:image')
|
|
99
|
+
imageElement.ele('image:loc').txt(image.loc)
|
|
100
|
+
if (image.title) {
|
|
101
|
+
imageElement.ele('image:title').txt(image.title)
|
|
102
|
+
}
|
|
103
|
+
if (image.caption) {
|
|
104
|
+
imageElement.ele('image:caption').txt(image.caption)
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Add news
|
|
110
|
+
if (item.news) {
|
|
111
|
+
const newsElement = page.ele('news:news')
|
|
112
|
+
const publication = newsElement.ele('news:publication')
|
|
113
|
+
publication.ele('news:name').txt(item.news.publication.name)
|
|
114
|
+
publication.ele('news:language').txt(item.news.publication.language)
|
|
115
|
+
newsElement
|
|
116
|
+
.ele('news:publication_date')
|
|
117
|
+
.txt(new Date(item.news.publicationDate).toISOString().split('T')[0]!)
|
|
118
|
+
newsElement.ele('news:title').txt(item.news.title)
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return sitemap.end({ prettyPrint: true })
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export function buildSitemap({
|
|
126
|
+
options,
|
|
127
|
+
publicDir,
|
|
128
|
+
}: {
|
|
129
|
+
options: TanStackStartOutputConfig
|
|
130
|
+
publicDir: string
|
|
131
|
+
}) {
|
|
132
|
+
const logger = createLogger('sitemap')
|
|
133
|
+
|
|
134
|
+
let sitemapOptions = options.sitemap
|
|
135
|
+
|
|
136
|
+
if (!sitemapOptions && options.pages.length) {
|
|
137
|
+
sitemapOptions = { enabled: true, outputPath: 'sitemap.xml' }
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (!sitemapOptions?.enabled) {
|
|
141
|
+
throw new Error('Sitemap is not enabled')
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const { host, outputPath } = sitemapOptions
|
|
145
|
+
|
|
146
|
+
if (!host) {
|
|
147
|
+
if (!options.sitemap) {
|
|
148
|
+
logger.info(
|
|
149
|
+
'Hint: Pages found, but no sitemap host has been set. To enable sitemap generation, set the `sitemap.host` option.',
|
|
150
|
+
)
|
|
151
|
+
return
|
|
152
|
+
}
|
|
153
|
+
throw new Error(
|
|
154
|
+
'Sitemap host is not set and required to build the sitemap.',
|
|
155
|
+
)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (!outputPath) {
|
|
159
|
+
throw new Error('Sitemap output path is not set')
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const { pages } = options
|
|
163
|
+
|
|
164
|
+
if (!pages.length) {
|
|
165
|
+
logger.info('No pages were found to build the sitemap. Skipping...')
|
|
166
|
+
return
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
logger.info('Building Sitemap...')
|
|
170
|
+
|
|
171
|
+
// Build the sitemap data
|
|
172
|
+
const sitemapData = buildSitemapJson(pages, host)
|
|
173
|
+
|
|
174
|
+
// Generate output paths
|
|
175
|
+
const xmlOutputPath = path.join(publicDir, outputPath)
|
|
176
|
+
const pagesOutputPath = path.join(publicDir, 'pages.json')
|
|
177
|
+
|
|
178
|
+
try {
|
|
179
|
+
// Write XML sitemap
|
|
180
|
+
logger.info(`Writing sitemap XML at ${xmlOutputPath}`)
|
|
181
|
+
writeFileSync(xmlOutputPath, jsonToXml(sitemapData))
|
|
182
|
+
|
|
183
|
+
// Write pages data for runtime use
|
|
184
|
+
logger.info(`Writing pages data at ${pagesOutputPath}`)
|
|
185
|
+
writeFileSync(
|
|
186
|
+
pagesOutputPath,
|
|
187
|
+
JSON.stringify(
|
|
188
|
+
{
|
|
189
|
+
pages,
|
|
190
|
+
host,
|
|
191
|
+
lastBuilt: new Date().toISOString(),
|
|
192
|
+
},
|
|
193
|
+
null,
|
|
194
|
+
2,
|
|
195
|
+
),
|
|
196
|
+
)
|
|
197
|
+
} catch (e) {
|
|
198
|
+
logger.error(`Unable to write sitemap files`, e)
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function createXml(elementName: 'urlset' | 'sitemapindex'): XMLBuilder {
|
|
203
|
+
return create({ version: '1.0', encoding: 'UTF-8' })
|
|
204
|
+
.ele(elementName, {
|
|
205
|
+
xmlns: 'https://www.sitemaps.org/schemas/sitemap/0.9',
|
|
206
|
+
})
|
|
207
|
+
.com(`This file was automatically generated by TanStack Start.`)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function checkSlash(host: string): string {
|
|
211
|
+
const finalChar = host.slice(-1)
|
|
212
|
+
return finalChar === '/' ? '' : '/'
|
|
213
|
+
}
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import path from 'node:path'
|
|
2
|
+
import { rmSync } from 'node:fs'
|
|
3
|
+
import { build, copyPublicAssets, createNitro, prepare } from 'nitropack'
|
|
4
|
+
import { dirname, resolve } from 'pathe'
|
|
5
|
+
import {
|
|
6
|
+
CLIENT_DIST_DIR,
|
|
7
|
+
SSR_ENTRY_FILE,
|
|
8
|
+
VITE_ENVIRONMENT_NAMES,
|
|
9
|
+
} from '../constants'
|
|
10
|
+
import { buildSitemap } from './build-sitemap'
|
|
11
|
+
import { prerender } from './prerender'
|
|
12
|
+
import type {
|
|
13
|
+
EnvironmentOptions,
|
|
14
|
+
PluginOption,
|
|
15
|
+
Rollup,
|
|
16
|
+
ViteBuilder,
|
|
17
|
+
} from 'vite'
|
|
18
|
+
import type { Nitro, NitroConfig } from 'nitropack'
|
|
19
|
+
import type { TanStackStartOutputConfig } from '../plugin'
|
|
20
|
+
|
|
21
|
+
export function nitroPlugin(
|
|
22
|
+
options: TanStackStartOutputConfig,
|
|
23
|
+
getSsrBundle: () => Rollup.OutputBundle,
|
|
24
|
+
): Array<PluginOption> {
|
|
25
|
+
const buildPreset =
|
|
26
|
+
process.env['START_TARGET'] ?? (options.target as string | undefined)
|
|
27
|
+
return [
|
|
28
|
+
{
|
|
29
|
+
name: 'tanstack-vite-plugin-nitro',
|
|
30
|
+
configEnvironment(name) {
|
|
31
|
+
if (name === VITE_ENVIRONMENT_NAMES.server) {
|
|
32
|
+
return {
|
|
33
|
+
build: {
|
|
34
|
+
commonjsOptions: {
|
|
35
|
+
include: [],
|
|
36
|
+
},
|
|
37
|
+
ssr: true,
|
|
38
|
+
sourcemap: true,
|
|
39
|
+
rollupOptions: {
|
|
40
|
+
input: '/~start/server-entry',
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
} satisfies EnvironmentOptions
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return null
|
|
47
|
+
},
|
|
48
|
+
config() {
|
|
49
|
+
return {
|
|
50
|
+
builder: {
|
|
51
|
+
sharedPlugins: true,
|
|
52
|
+
async buildApp(builder) {
|
|
53
|
+
const client = builder.environments[VITE_ENVIRONMENT_NAMES.client]
|
|
54
|
+
const server = builder.environments[VITE_ENVIRONMENT_NAMES.server]
|
|
55
|
+
|
|
56
|
+
if (!client) {
|
|
57
|
+
throw new Error('Client environment not found')
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (!server) {
|
|
61
|
+
throw new Error('SSR environment not found')
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Build the client bundle
|
|
65
|
+
// i.e client entry file with `hydrateRoot(...)`
|
|
66
|
+
const clientOutputDir = resolve(options.root, CLIENT_DIST_DIR)
|
|
67
|
+
rmSync(clientOutputDir, { recursive: true, force: true })
|
|
68
|
+
await builder.build(client)
|
|
69
|
+
|
|
70
|
+
// Build the SSR bundle
|
|
71
|
+
await builder.build(server)
|
|
72
|
+
|
|
73
|
+
const nitroConfig: NitroConfig = {
|
|
74
|
+
dev: false,
|
|
75
|
+
// TODO: do we need this? should this be made configurable?
|
|
76
|
+
compatibilityDate: '2024-11-19',
|
|
77
|
+
logLevel: 3,
|
|
78
|
+
preset: buildPreset,
|
|
79
|
+
baseURL: globalThis.TSS_APP_BASE,
|
|
80
|
+
publicAssets: [
|
|
81
|
+
{
|
|
82
|
+
dir: path.resolve(options.root, CLIENT_DIST_DIR),
|
|
83
|
+
baseURL: '/',
|
|
84
|
+
maxAge: 31536000, // 1 year
|
|
85
|
+
},
|
|
86
|
+
],
|
|
87
|
+
typescript: {
|
|
88
|
+
generateTsConfig: false,
|
|
89
|
+
},
|
|
90
|
+
prerender: undefined,
|
|
91
|
+
renderer: SSR_ENTRY_FILE,
|
|
92
|
+
plugins: [], // Nitro's plugins
|
|
93
|
+
appConfigFiles: [],
|
|
94
|
+
scanDirs: [],
|
|
95
|
+
imports: false, // unjs/unimport for global/magic imports
|
|
96
|
+
rollupConfig: {
|
|
97
|
+
plugins: [virtualBundlePlugin(getSsrBundle())],
|
|
98
|
+
},
|
|
99
|
+
virtual: {
|
|
100
|
+
// This is Nitro's way of defining virtual modules
|
|
101
|
+
// Should we define the ones for TanStack Start's here as well?
|
|
102
|
+
},
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const nitro = await createNitro(nitroConfig)
|
|
106
|
+
|
|
107
|
+
await buildNitroApp(builder, nitro, options)
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
]
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Correctly co-ordinates the nitro app build process to make sure that the
|
|
118
|
+
* app is built, while also correctly handling the prerendering and sitemap
|
|
119
|
+
* generation and including their outputs in the final build.
|
|
120
|
+
*/
|
|
121
|
+
async function buildNitroApp(
|
|
122
|
+
builder: ViteBuilder,
|
|
123
|
+
nitro: Nitro,
|
|
124
|
+
options: TanStackStartOutputConfig,
|
|
125
|
+
) {
|
|
126
|
+
// Cleans the public and server directories for a fresh build
|
|
127
|
+
// i.e the `.output/public` and `.output/server` directories
|
|
128
|
+
await prepare(nitro)
|
|
129
|
+
|
|
130
|
+
// Creates the `.output/public` directory and copies the public assets
|
|
131
|
+
await copyPublicAssets(nitro)
|
|
132
|
+
|
|
133
|
+
// If the user has not set a prerender option, we need to set it to true
|
|
134
|
+
// if the pages array is not empty and has sub options requiring for prerendering
|
|
135
|
+
if (options.prerender?.enabled !== false) {
|
|
136
|
+
options.prerender = {
|
|
137
|
+
...options.prerender,
|
|
138
|
+
enabled: options.pages.some((d) =>
|
|
139
|
+
typeof d === 'string' ? false : !!d.prerender?.enabled,
|
|
140
|
+
),
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Setup the options for prerendering the SPA shell (i.e `src/routes/__root.tsx`)
|
|
145
|
+
if (options.spa?.enabled) {
|
|
146
|
+
options.prerender = {
|
|
147
|
+
...options.prerender,
|
|
148
|
+
enabled: true,
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const maskUrl = new URL(options.spa.maskPath, 'http://localhost')
|
|
152
|
+
|
|
153
|
+
maskUrl.searchParams.set('__TSS_SHELL', 'true')
|
|
154
|
+
|
|
155
|
+
options.pages.push({
|
|
156
|
+
path: maskUrl.toString().replace('http://localhost', ''),
|
|
157
|
+
prerender: options.spa.prerender,
|
|
158
|
+
sitemap: {
|
|
159
|
+
exclude: true,
|
|
160
|
+
},
|
|
161
|
+
})
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Run the prerendering process
|
|
165
|
+
if (options.prerender.enabled) {
|
|
166
|
+
await prerender({
|
|
167
|
+
options,
|
|
168
|
+
nitro,
|
|
169
|
+
builder,
|
|
170
|
+
})
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Run the sitemap build process
|
|
174
|
+
if (options.pages.length) {
|
|
175
|
+
buildSitemap({
|
|
176
|
+
options,
|
|
177
|
+
publicDir: nitro.options.output.publicDir,
|
|
178
|
+
})
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Build the nitro app
|
|
182
|
+
// We only build the nitro app, once we've prepared the public assets,
|
|
183
|
+
// prerendered the pages and built the sitemap.
|
|
184
|
+
// If we try to do this earlier, then the public assets may not be available
|
|
185
|
+
// in the production build.
|
|
186
|
+
await build(nitro)
|
|
187
|
+
|
|
188
|
+
// Close the nitro instance
|
|
189
|
+
await nitro.close()
|
|
190
|
+
nitro.logger.success(
|
|
191
|
+
'Client and Server bundles for TanStack Start have been successfully built.',
|
|
192
|
+
)
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
type NitroRollupPluginOption = NonNullable<
|
|
196
|
+
NitroConfig['rollupConfig']
|
|
197
|
+
>['plugins']
|
|
198
|
+
|
|
199
|
+
function virtualBundlePlugin(
|
|
200
|
+
ssrBundle: Rollup.OutputBundle,
|
|
201
|
+
): NitroRollupPluginOption {
|
|
202
|
+
type VirtualModule = { code: string; map: string | null }
|
|
203
|
+
const _modules = new Map<string, VirtualModule>()
|
|
204
|
+
|
|
205
|
+
// group chunks and source maps
|
|
206
|
+
for (const [fileName, content] of Object.entries(ssrBundle)) {
|
|
207
|
+
if (content.type === 'chunk') {
|
|
208
|
+
const virtualModule: VirtualModule = {
|
|
209
|
+
code: content.code,
|
|
210
|
+
map: null,
|
|
211
|
+
}
|
|
212
|
+
const maybeMap = ssrBundle[`${fileName}.map`]
|
|
213
|
+
if (maybeMap && maybeMap.type === 'asset') {
|
|
214
|
+
virtualModule.map = maybeMap.source as string
|
|
215
|
+
}
|
|
216
|
+
_modules.set(fileName, virtualModule)
|
|
217
|
+
_modules.set(resolve(fileName), virtualModule)
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
return {
|
|
222
|
+
name: 'virtual-bundle',
|
|
223
|
+
resolveId(id, importer) {
|
|
224
|
+
if (_modules.has(id)) {
|
|
225
|
+
return resolve(id)
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if (importer) {
|
|
229
|
+
const resolved = resolve(dirname(importer), id)
|
|
230
|
+
if (_modules.has(resolved)) {
|
|
231
|
+
return resolved
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
return null
|
|
235
|
+
},
|
|
236
|
+
load(id) {
|
|
237
|
+
const m = _modules.get(id)
|
|
238
|
+
if (!m) {
|
|
239
|
+
return null
|
|
240
|
+
}
|
|
241
|
+
return m
|
|
242
|
+
},
|
|
243
|
+
}
|
|
244
|
+
}
|
|
@@ -4,13 +4,13 @@ import path from 'node:path'
|
|
|
4
4
|
import { getRollupConfig } from 'nitropack/rollup'
|
|
5
5
|
import { build as buildNitro, createNitro } from 'nitropack'
|
|
6
6
|
import { joinURL, withBase, withoutBase } from 'ufo'
|
|
7
|
+
import { VITE_ENVIRONMENT_NAMES } from '../constants'
|
|
8
|
+
import { createLogger } from '../utils'
|
|
7
9
|
import { Queue } from './queue'
|
|
8
|
-
import { buildNitroEnvironment } from './nitro/build-nitro'
|
|
9
|
-
import { VITE_ENVIRONMENT_NAMES } from './constants'
|
|
10
10
|
import type { ViteBuilder } from 'vite'
|
|
11
11
|
import type { $Fetch, Nitro } from 'nitropack'
|
|
12
|
-
import type { TanStackStartOutputConfig } from '
|
|
13
|
-
import type { Page } from '
|
|
12
|
+
import type { TanStackStartOutputConfig } from '../plugin'
|
|
13
|
+
import type { Page } from '../schema'
|
|
14
14
|
|
|
15
15
|
export async function prerender({
|
|
16
16
|
options,
|
|
@@ -21,7 +21,8 @@ export async function prerender({
|
|
|
21
21
|
nitro: Nitro
|
|
22
22
|
builder: ViteBuilder
|
|
23
23
|
}) {
|
|
24
|
-
|
|
24
|
+
const logger = createLogger('prerender')
|
|
25
|
+
logger.info('Prendering pages...')
|
|
25
26
|
|
|
26
27
|
// If prerender is enabled but no pages are provided, default to prerendering the root page
|
|
27
28
|
if (options.prerender?.enabled && !options.pages.length) {
|
|
@@ -72,7 +73,7 @@ export async function prerender({
|
|
|
72
73
|
},
|
|
73
74
|
}
|
|
74
75
|
|
|
75
|
-
await
|
|
76
|
+
await buildNitro(nodeNitro)
|
|
76
77
|
|
|
77
78
|
// Import renderer entry
|
|
78
79
|
const serverFilename =
|
|
@@ -93,14 +94,14 @@ export async function prerender({
|
|
|
93
94
|
// Crawl all pages
|
|
94
95
|
const pages = await prerenderPages()
|
|
95
96
|
|
|
96
|
-
|
|
97
|
+
logger.info(`Prerendered ${pages.length} pages:`)
|
|
97
98
|
pages.forEach((page) => {
|
|
98
|
-
|
|
99
|
+
logger.info(`- ${page}`)
|
|
99
100
|
})
|
|
100
101
|
|
|
101
102
|
// TODO: Write the prerendered pages to the output directory
|
|
102
103
|
} catch (error) {
|
|
103
|
-
|
|
104
|
+
logger.error(error)
|
|
104
105
|
} finally {
|
|
105
106
|
// Ensure server is always closed
|
|
106
107
|
// server.process.kill()
|
|
@@ -126,18 +127,10 @@ export async function prerender({
|
|
|
126
127
|
const seen = new Set<string>()
|
|
127
128
|
const retriesByPath = new Map<string, number>()
|
|
128
129
|
const concurrency = options.prerender?.concurrency ?? os.cpus().length
|
|
129
|
-
|
|
130
|
+
logger.info(`Concurrency: ${concurrency}`)
|
|
130
131
|
const queue = new Queue({ concurrency })
|
|
131
132
|
|
|
132
|
-
options.pages.forEach((
|
|
133
|
-
let page = _page as Page
|
|
134
|
-
|
|
135
|
-
if (typeof _page === 'string') {
|
|
136
|
-
page = { path: _page }
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
addCrawlPageTask(page)
|
|
140
|
-
})
|
|
133
|
+
options.pages.forEach((page) => addCrawlPageTask(page))
|
|
141
134
|
|
|
142
135
|
await queue.start()
|
|
143
136
|
|
|
@@ -168,7 +161,7 @@ export async function prerender({
|
|
|
168
161
|
|
|
169
162
|
// Add the task
|
|
170
163
|
queue.add(async () => {
|
|
171
|
-
|
|
164
|
+
logger.info(`Crawling: ${page.path}`)
|
|
172
165
|
const retries = retriesByPath.get(page.path) || 0
|
|
173
166
|
try {
|
|
174
167
|
// Fetch the route
|
|
@@ -236,7 +229,7 @@ export async function prerender({
|
|
|
236
229
|
}
|
|
237
230
|
} catch (error) {
|
|
238
231
|
if (retries < (prerenderOptions.retryCount ?? 0)) {
|
|
239
|
-
|
|
232
|
+
logger.warn(`Encountered error, retrying: ${page.path} in 500ms`)
|
|
240
233
|
await new Promise((resolve) =>
|
|
241
234
|
setTimeout(resolve, prerenderOptions.retryDelay),
|
|
242
235
|
)
|