1
1
import path from 'node:path'
2
2
import { rmSync } from 'node:fs'
3
- import { build , createNitro } from 'nitropack'
3
+ import * as fsp from 'node:fs/promises'
4
+ import { build , copyPublicAssets , createNitro , prepare } from 'nitropack'
4
5
import { dirname , resolve } from 'pathe'
5
6
import { clientDistDir , ssrEntryFile } from '../plugin'
6
7
import { prerender } from '../prerender'
7
8
import { VITE_ENVIRONMENT_NAMES } from '../constants'
8
9
import { buildSitemap } from '../build-sitemap'
9
10
import { devServerPlugin } from './dev-server-plugin'
10
- import { buildNitroEnvironment } from './build-nitro'
11
- import type { EnvironmentOptions , PluginOption , Rollup } from 'vite'
12
- import type { NitroConfig } from 'nitropack'
11
+ import type {
12
+ EnvironmentOptions ,
13
+ PluginOption ,
14
+ Rollup ,
15
+ ViteBuilder ,
16
+ } from 'vite'
17
+ import type { Nitro , NitroConfig } from 'nitropack'
13
18
import type { TanStackStartOutputConfig } from '../plugin'
14
19
15
20
export function nitroPlugin (
@@ -88,59 +93,7 @@ export function nitroPlugin(
88
93
89
94
const nitro = await createNitro ( nitroConfig )
90
95
91
- await buildNitroEnvironment ( nitro , ( ) => build ( nitro ) )
92
-
93
- // If the user has not set a prerender option, we need to set it to true
94
- // if the pages array is not empty and has sub options requiring for prerendering
95
- if ( options . prerender ?. enabled !== false ) {
96
- options . prerender = {
97
- ...options . prerender ,
98
- enabled : options . pages . some ( ( d ) =>
99
- typeof d === 'string' ? false : ! ! d . prerender ?. enabled ,
100
- ) ,
101
- }
102
- }
103
-
104
- // Setup the options for prerendering the SPA shell (i.e `src/routes/__root.tsx`)
105
- if ( options . spa ?. enabled ) {
106
- options . prerender = {
107
- ...options . prerender ,
108
- enabled : true ,
109
- }
110
-
111
- const maskUrl = new URL (
112
- options . spa . maskPath ,
113
- 'http://localhost' ,
114
- )
115
-
116
- maskUrl . searchParams . set ( '__TSS_SHELL' , 'true' )
117
-
118
- options . pages . push ( {
119
- path : maskUrl . toString ( ) . replace ( 'http://localhost' , '' ) ,
120
- prerender : options . spa . prerender ,
121
- sitemap : {
122
- exclude : true ,
123
- } ,
124
- } )
125
- }
126
-
127
- // Start prerendering!!!
128
- if ( options . prerender . enabled ) {
129
- await prerender ( {
130
- options,
131
- nitro,
132
- builder,
133
- } )
134
- }
135
-
136
- if ( options . pages . length ) {
137
- await buildSitemap ( {
138
- options,
139
- publicDir : nitro . options . output . publicDir ,
140
- } )
141
- }
142
-
143
- console . log ( `\n✅ Client and server bundles successfully built.` )
96
+ await buildNitroApp ( builder , nitro , options )
144
97
} ,
145
98
} ,
146
99
}
@@ -149,6 +102,93 @@ export function nitroPlugin(
149
102
]
150
103
}
151
104
105
+ /**
106
+ * Correctly co-ordinates the nitro app build process to make sure that the
107
+ * app is built, while also correctly handling the prerendering and sitemap
108
+ * generation and including their outputs in the final build.
109
+ */
110
+ async function buildNitroApp (
111
+ builder : ViteBuilder ,
112
+ nitro : Nitro ,
113
+ options : TanStackStartOutputConfig ,
114
+ ) {
115
+ // Cleans the public and server directories for a fresh build
116
+ // i.e the `.output/public` and `.output/server` directories
117
+ await prepare ( nitro )
118
+
119
+ // Creates the `.output/public` directory and copies the public assets
120
+ await copyPublicAssets ( nitro )
121
+
122
+ // If the user has not set a prerender option, we need to set it to true
123
+ // if the pages array is not empty and has sub options requiring for prerendering
124
+ if ( options . prerender ?. enabled !== false ) {
125
+ options . prerender = {
126
+ ...options . prerender ,
127
+ enabled : options . pages . some ( ( d ) =>
128
+ typeof d === 'string' ? false : ! ! d . prerender ?. enabled ,
129
+ ) ,
130
+ }
131
+ }
132
+
133
+ // Setup the options for prerendering the SPA shell (i.e `src/routes/__root.tsx`)
134
+ if ( options . spa ?. enabled ) {
135
+ options . prerender = {
136
+ ...options . prerender ,
137
+ enabled : true ,
138
+ }
139
+
140
+ const maskUrl = new URL ( options . spa . maskPath , 'http://localhost' )
141
+
142
+ maskUrl . searchParams . set ( '__TSS_SHELL' , 'true' )
143
+
144
+ options . pages . push ( {
145
+ path : maskUrl . toString ( ) . replace ( 'http://localhost' , '' ) ,
146
+ prerender : options . spa . prerender ,
147
+ sitemap : {
148
+ exclude : true ,
149
+ } ,
150
+ } )
151
+ }
152
+
153
+ // Run the prerendering process
154
+ if ( options . prerender . enabled ) {
155
+ await prerender ( {
156
+ options,
157
+ nitro,
158
+ builder,
159
+ } )
160
+ }
161
+
162
+ // Run the sitemap build process
163
+ if ( options . pages . length ) {
164
+ buildSitemap ( {
165
+ options,
166
+ publicDir : nitro . options . output . publicDir ,
167
+ } )
168
+ }
169
+
170
+ // Build the nitro app
171
+ await build ( nitro )
172
+
173
+ // Cleanup the vite public directory
174
+ // As a part of the build process, a `.vite/` directory
175
+ // is copied over from `.tanstack-start/build/client-dist/`
176
+ // to the nitro `publicDir` (e.g. `.output/public/`).
177
+ // This directory (and its contents including the vite client manifest)
178
+ // should not be included in the final build, so we remove it.
179
+ const nitroPublicDir = nitro . options . output . publicDir
180
+ const viteDir = path . resolve ( nitroPublicDir , '.vite' )
181
+ if ( await fsp . stat ( viteDir ) . catch ( ( ) => false ) ) {
182
+ await fsp . rm ( viteDir , { recursive : true , force : true } )
183
+ }
184
+
185
+ // Close the nitro instance
186
+ await nitro . close ( )
187
+ nitro . logger . success (
188
+ 'Client and Server bundles for TanStack Start have been successfully built.' ,
189
+ )
190
+ }
191
+
152
192
function virtualBundlePlugin ( ssrBundle : Rollup . OutputBundle ) : Rollup . Plugin {
153
193
type VirtualModule = { code : string ; map : string | null }
154
194
const _modules = new Map < string , VirtualModule > ( )
0 commit comments