-
Notifications
You must be signed in to change notification settings - Fork 1k
/
Copy pathbuildHandler.js
168 lines (151 loc) · 5.44 KB
/
buildHandler.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
import path from 'path'
import execa from 'execa'
import fs from 'fs-extra'
import { Listr } from 'listr2'
import terminalLink from 'terminal-link'
import { recordTelemetryAttributes } from '@redwoodjs/cli-helpers'
import { buildApi, cleanApiBuild } from '@redwoodjs/internal/dist/build/api'
import { generate } from '@redwoodjs/internal/dist/generate/generate'
import { loadAndValidateSdls } from '@redwoodjs/internal/dist/validateSchema'
import { detectPrerenderRoutes } from '@redwoodjs/prerender/detection'
import { timedTelemetry } from '@redwoodjs/telemetry'
import { generatePrismaCommand } from '../lib/generatePrismaClient.js'
import { getPaths, getConfig } from '../lib/index.js'
export const handler = async ({
side = ['api', 'web'],
verbose = false,
prisma = true,
prerender,
}) => {
recordTelemetryAttributes({
command: 'build',
side: JSON.stringify(side),
verbose,
prisma,
prerender,
})
const rwjsPaths = getPaths()
const rwjsConfig = getConfig()
const useFragments = rwjsConfig.graphql?.fragments
const useTrustedDocuments = rwjsConfig.graphql?.trustedDocuments
const prismaSchemaExists = fs.existsSync(rwjsPaths.api.dbSchema)
const prerenderRoutes =
prerender && side.includes('web') ? detectPrerenderRoutes() : []
const shouldGeneratePrismaClient =
prisma &&
prismaSchemaExists &&
(side.includes('api') || prerenderRoutes.length > 0)
const tasks = [
shouldGeneratePrismaClient && {
title: 'Generating Prisma Client...',
task: () => {
const { cmd, args } = generatePrismaCommand(rwjsPaths.api.dbSchema)
return execa(cmd, args, {
stdio: verbose ? 'inherit' : 'pipe',
shell: true,
cwd: rwjsPaths.api.base,
})
},
},
// If using GraphQL Fragments or Trusted Documents, then we need to use
// codegen to generate the types needed for possible types and the
// trusted document store hashes
(useFragments || useTrustedDocuments) && {
title: `Generating types needed for ${[
useFragments && 'GraphQL Fragments',
useTrustedDocuments && 'Trusted Documents',
]
.filter(Boolean)
.join(' and ')} support...`,
task: async () => {
await generate()
},
},
side.includes('api') && {
title: 'Verifying graphql schema...',
task: loadAndValidateSdls,
},
side.includes('api') && {
title: 'Building API...',
task: async () => {
await cleanApiBuild()
const { errors, warnings } = await buildApi()
if (errors.length) {
console.error(errors)
}
if (warnings.length) {
console.warn(warnings)
}
},
},
side.includes('web') && {
title: 'Building Web...',
task: async () => {
// @NOTE: we're using the vite build command here, instead of the
// buildWeb function directly because we want the process.cwd to be
// the web directory, not the root of the project.
// This is important for postcss/tailwind to work correctly
// Having a separate binary lets us contain the change of cwd to that
// process only. If we changed cwd here, or in the buildWeb function,
// it could affect other things that run in parallel while building.
// We don't have any parallel tasks right now, but someone might add
// one in the future as a performance optimization.
//
// Disable the new warning in Vite v5 about the CJS build being deprecated
// so that users don't have to see it when this command is called with --verbose
process.env.VITE_CJS_IGNORE_WARNING = 'true'
await execa(
`node ${require.resolve(
'@redwoodjs/vite/bins/rw-vite-build.mjs',
)} --webDir="${rwjsPaths.web.base}" --verbose=${verbose}`,
{
stdio: verbose ? 'inherit' : 'pipe',
shell: true,
// `cwd` is needed for yarn to find the rw-vite-build binary
// It won't change process.cwd for anything else here, in this
// process
cwd: rwjsPaths.web.base,
},
)
// Streaming SSR does not use the index.html file.
if (!getConfig().experimental?.streamingSsr?.enabled) {
console.log('Creating 200.html...')
const indexHtmlPath = path.join(getPaths().web.dist, 'index.html')
fs.copyFileSync(
indexHtmlPath,
path.join(getPaths().web.dist, '200.html'),
)
}
},
},
].filter(Boolean)
const triggerPrerender = async () => {
console.log('Starting prerendering...')
if (prerenderRoutes.length === 0) {
console.log(
`You have not marked any routes to "prerender" in your ${terminalLink(
'Routes',
'file://' + rwjsPaths.web.routes,
)}.`,
)
return
}
// Running a separate process here, otherwise it wouldn't pick up the
// generated Prisma Client due to require module caching
await execa('yarn rw prerender', {
stdio: 'inherit',
shell: true,
cwd: rwjsPaths.web.base,
})
}
const jobs = new Listr(tasks, {
renderer: verbose && 'verbose',
})
await timedTelemetry(process.argv, { type: 'build' }, async () => {
await jobs.run()
if (side.includes('web') && prerender && prismaSchemaExists) {
// This step is outside Listr so that it prints clearer, complete messages
await triggerPrerender()
}
})
}