Skip to content

Commit 0554d6a

Browse files
authored
fix: revert publish from subdirectory (#1771)
This reverts commit 1faf191.
1 parent b400efb commit 0554d6a

File tree

5 files changed

+163
-66
lines changed

5 files changed

+163
-66
lines changed

packages/runtime/src/helpers/files.ts

+23-19
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/* eslint-disable max-lines */
22
import { cpus } from 'os'
33

4+
import type { NetlifyConfig } from '@netlify/build'
45
import { yellowBright } from 'chalk'
56
import { existsSync, readJson, move, copy, writeJson, readFile, writeFile, ensureDir, readFileSync } from 'fs-extra'
67
import globby from 'globby'
@@ -59,11 +60,11 @@ export const matchesRewrite = (file: string, rewrites: Rewrites): boolean => {
5960
return matchesRedirect(file, rewrites.beforeFiles)
6061
}
6162

62-
export const getMiddleware = async (distDir: string): Promise<Array<string>> => {
63+
export const getMiddleware = async (publish: string): Promise<Array<string>> => {
6364
if (process.env.NEXT_DISABLE_NETLIFY_EDGE !== 'true' && process.env.NEXT_DISABLE_NETLIFY_EDGE !== '1') {
6465
return []
6566
}
66-
const manifestPath = join(distDir, 'server', 'middleware-manifest.json')
67+
const manifestPath = join(publish, 'server', 'middleware-manifest.json')
6768
if (existsSync(manifestPath)) {
6869
const manifest = await readJson(manifestPath, { throws: false })
6970
return manifest?.sortedMiddleware ?? []
@@ -73,28 +74,32 @@ export const getMiddleware = async (distDir: string): Promise<Array<string>> =>
7374

7475
// eslint-disable-next-line max-lines-per-function
7576
export const moveStaticPages = async ({
76-
distDir,
77+
netlifyConfig,
78+
target,
7779
i18n,
7880
basePath,
79-
publishDir,
8081
}: {
81-
distDir: string
82+
netlifyConfig: NetlifyConfig
83+
target: 'server' | 'serverless' | 'experimental-serverless-trace'
8284
i18n: NextConfig['i18n']
8385
basePath?: string
84-
publishDir
8586
}): Promise<void> => {
8687
console.log('Moving static page files to serve from CDN...')
87-
const outputDir = join(distDir, 'server')
88+
const outputDir = join(netlifyConfig.build.publish, target === 'server' ? 'server' : 'serverless')
8889
const root = join(outputDir, 'pages')
89-
const buildId = readFileSync(join(distDir, 'BUILD_ID'), 'utf8').trim()
90+
const buildId = readFileSync(join(netlifyConfig.build.publish, 'BUILD_ID'), 'utf8').trim()
9091
const dataDir = join('_next', 'data', buildId)
91-
await ensureDir(join(publishDir, dataDir))
92+
await ensureDir(join(netlifyConfig.build.publish, dataDir))
9293
// Load the middleware manifest so we can check if a file matches it before moving
93-
const middlewarePaths = await getMiddleware(distDir)
94+
const middlewarePaths = await getMiddleware(netlifyConfig.build.publish)
9495
const middleware = middlewarePaths.map((path) => path.slice(1))
9596

96-
const prerenderManifest: PrerenderManifest = await readJson(join(distDir, 'prerender-manifest.json'))
97-
const { redirects, rewrites }: RoutesManifest = await readJson(join(distDir, 'routes-manifest.json'))
97+
const prerenderManifest: PrerenderManifest = await readJson(
98+
join(netlifyConfig.build.publish, 'prerender-manifest.json'),
99+
)
100+
const { redirects, rewrites }: RoutesManifest = await readJson(
101+
join(netlifyConfig.build.publish, 'routes-manifest.json'),
102+
)
98103

99104
const isrFiles = new Set<string>()
100105

@@ -123,7 +128,7 @@ export const moveStaticPages = async ({
123128
files.push(file)
124129
filesManifest[file] = targetPath
125130

126-
const dest = join(publishDir, targetPath)
131+
const dest = join(netlifyConfig.build.publish, targetPath)
127132

128133
try {
129134
await move(source, dest)
@@ -237,10 +242,10 @@ export const moveStaticPages = async ({
237242
}
238243

239244
// Write the manifest for use in the serverless functions
240-
await writeJson(join(distDir, 'static-manifest.json'), Object.entries(filesManifest))
245+
await writeJson(join(netlifyConfig.build.publish, 'static-manifest.json'), Object.entries(filesManifest))
241246

242247
if (i18n?.defaultLocale) {
243-
const rootPath = basePath ? join(publishDir, basePath) : publishDir
248+
const rootPath = basePath ? join(netlifyConfig.build.publish, basePath) : netlifyConfig.build.publish
244249
// Copy the default locale into the root
245250
const defaultLocaleDir = join(rootPath, i18n.defaultLocale)
246251
if (existsSync(defaultLocaleDir)) {
@@ -422,13 +427,12 @@ export const unpatchNextFiles = async (root: string): Promise<void> => {
422427
export const movePublicFiles = async ({
423428
appDir,
424429
outdir,
425-
publishDir,
430+
publish,
426431
}: {
427432
appDir: string
428433
outdir?: string
429-
publishDir: string
434+
publish: string
430435
}): Promise<void> => {
431-
await ensureDir(publishDir)
432436
// `outdir` is a config property added when using Next.js with Nx. It's typically
433437
// a relative path outside of the appDir, e.g. '../../dist/apps/<app-name>', and
434438
// the parent directory of the .next directory.
@@ -437,7 +441,7 @@ export const movePublicFiles = async ({
437441
// directory from the original app directory.
438442
const publicDir = outdir ? join(appDir, outdir, 'public') : join(appDir, 'public')
439443
if (existsSync(publicDir)) {
440-
await copy(publicDir, `${publishDir}/`)
444+
await copy(publicDir, `${publish}/`)
441445
}
442446
}
443447
/* eslint-enable max-lines */

packages/runtime/src/helpers/redirects.ts

+26-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import type { PrerenderManifest, SsgRoute } from 'next/dist/build'
77
import { outdent } from 'outdent'
88
import { join } from 'pathe'
99

10-
import { HANDLER_FUNCTION_PATH, ODB_FUNCTION_PATH } from '../constants'
10+
import { HANDLER_FUNCTION_PATH, HIDDEN_PATHS, ODB_FUNCTION_PATH } from '../constants'
1111

1212
import { getMiddleware } from './files'
1313
import { ApiRouteConfig } from './functions'
@@ -25,6 +25,14 @@ import {
2525
const matchesMiddleware = (middleware: Array<string>, route: string): boolean =>
2626
middleware.some((middlewarePath) => route.startsWith(middlewarePath))
2727

28+
const generateHiddenPathRedirects = ({ basePath }: Pick<NextConfig, 'basePath'>): NetlifyConfig['redirects'] =>
29+
HIDDEN_PATHS.map((path) => ({
30+
from: `${basePath}${path}`,
31+
to: '/404.html',
32+
status: 404,
33+
force: true,
34+
}))
35+
2836
const generateLocaleRedirects = ({
2937
i18n,
3038
basePath,
@@ -58,6 +66,21 @@ const generateLocaleRedirects = ({
5866
return redirects
5967
}
6068

69+
export const generateStaticRedirects = ({
70+
netlifyConfig,
71+
nextConfig: { i18n, basePath },
72+
}: {
73+
netlifyConfig: NetlifyConfig
74+
nextConfig: Pick<NextConfig, 'i18n' | 'basePath'>
75+
}) => {
76+
// Static files are in `static`
77+
netlifyConfig.redirects.push({ from: `${basePath}/_next/static/*`, to: `/static/:splat`, status: 200 })
78+
79+
if (i18n) {
80+
netlifyConfig.redirects.push({ from: `${basePath}/:locale/_next/static/*`, to: `/static/:splat`, status: 200 })
81+
}
82+
}
83+
6184
/**
6285
* Routes that match middleware need to always use the SSR function
6386
* This generates a rewrite for every middleware in every locale, both with and without a splat
@@ -220,6 +243,8 @@ export const generateRedirects = async ({
220243
join(netlifyConfig.build.publish, 'routes-manifest.json'),
221244
)
222245

246+
netlifyConfig.redirects.push(...generateHiddenPathRedirects({ basePath }))
247+
223248
if (i18n && i18n.localeDetection !== false) {
224249
netlifyConfig.redirects.push(...generateLocaleRedirects({ i18n, basePath, trailingSlash }))
225250
}

packages/runtime/src/index.ts

+28-28
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { join, relative } from 'path'
44
import type { NetlifyPlugin } from '@netlify/build'
55
import { bold, redBright } from 'chalk'
66
import destr from 'destr'
7-
import { copy, ensureDir, existsSync, readFileSync } from 'fs-extra'
7+
import { existsSync, readFileSync } from 'fs-extra'
88
import { outdent } from 'outdent'
99

1010
import { HANDLER_FUNCTION_NAME, ODB_FUNCTION_NAME } from './constants'
@@ -26,7 +26,7 @@ import {
2626
getExtendedApiRouteConfigs,
2727
warnOnApiRoutes,
2828
} from './helpers/functions'
29-
import { generateRedirects } from './helpers/redirects'
29+
import { generateRedirects, generateStaticRedirects } from './helpers/redirects'
3030
import { shouldSkip, isNextAuthInstalled, getCustomImageResponseHeaders, getRemotePatterns } from './helpers/utils'
3131
import {
3232
verifyNetlifyBuildVersion,
@@ -80,18 +80,12 @@ const plugin: NetlifyPlugin = {
8080

8181
checkNextSiteHasBuilt({ publish, failBuild })
8282

83-
const { appDir, basePath, i18n, images, target, ignore, trailingSlash, outdir, experimental, distDir } =
84-
await getNextConfig({
83+
const { appDir, basePath, i18n, images, target, ignore, trailingSlash, outdir, experimental } = await getNextConfig(
84+
{
8585
publish,
8686
failBuild,
87-
})
88-
89-
const dotNextDir = join(appDir, distDir)
90-
91-
// This is the *generated* publish dir. The user specifies .next, be we actually use this subdirectory
92-
const publishDir = join(dotNextDir, 'dist')
93-
await ensureDir(publishDir)
94-
87+
},
88+
)
9589
await cleanupEdgeFunctions(constants)
9690

9791
const middlewareManifest = await loadMiddlewareManifest(netlifyConfig)
@@ -123,7 +117,7 @@ const plugin: NetlifyPlugin = {
123117
}
124118

125119
if (isNextAuthInstalled()) {
126-
const config = await getRequiredServerFiles(dotNextDir)
120+
const config = await getRequiredServerFiles(publish)
127121

128122
const userDefinedNextAuthUrl = config.config.env.NEXTAUTH_URL
129123

@@ -140,7 +134,7 @@ const plugin: NetlifyPlugin = {
140134
)
141135
config.config.env.NEXTAUTH_URL = nextAuthUrl
142136

143-
await updateRequiredServerFiles(dotNextDir, config)
137+
await updateRequiredServerFiles(publish, config)
144138
} else {
145139
// Using the deploy prime url in production leads to issues because the unique deploy ID is part of the generated URL
146140
// and will not match the expected URL in the callback URL of an OAuth application.
@@ -151,27 +145,30 @@ const plugin: NetlifyPlugin = {
151145
console.log(`NextAuth package detected, setting NEXTAUTH_URL environment variable to ${nextAuthUrl}`)
152146
config.config.env.NEXTAUTH_URL = nextAuthUrl
153147

154-
await updateRequiredServerFiles(dotNextDir, config)
148+
await updateRequiredServerFiles(publish, config)
155149
}
156150
}
157151

158-
const buildId = readFileSync(join(dotNextDir, 'BUILD_ID'), 'utf8').trim()
152+
const buildId = readFileSync(join(publish, 'BUILD_ID'), 'utf8').trim()
159153

160-
await configureHandlerFunctions({ netlifyConfig, ignore, publish: relative(process.cwd(), dotNextDir) })
161-
const apiRoutes = await getExtendedApiRouteConfigs(dotNextDir, appDir)
154+
await configureHandlerFunctions({ netlifyConfig, ignore, publish: relative(process.cwd(), publish) })
155+
const apiRoutes = await getExtendedApiRouteConfigs(publish, appDir)
162156

163157
await generateFunctions(constants, appDir, apiRoutes)
164158
await generatePagesResolver({ target, constants })
165159

166-
await movePublicFiles({ appDir, outdir, publishDir })
160+
await movePublicFiles({ appDir, outdir, publish })
167161

168162
await patchNextFiles(appDir)
169163

170164
if (!destr(process.env.SERVE_STATIC_FILES_FROM_ORIGIN)) {
171-
await moveStaticPages({ distDir: dotNextDir, i18n, basePath, publishDir })
165+
await moveStaticPages({ target, netlifyConfig, i18n, basePath })
172166
}
173167

174-
await copy(join(dotNextDir, 'static'), join(publishDir, '_next', 'static'))
168+
await generateStaticRedirects({
169+
netlifyConfig,
170+
nextConfig: { basePath, i18n },
171+
})
175172

176173
await setupImageFunction({
177174
constants,
@@ -193,16 +190,20 @@ const plugin: NetlifyPlugin = {
193190
},
194191

195192
async onPostBuild({
196-
netlifyConfig,
193+
netlifyConfig: {
194+
build: { publish },
195+
redirects,
196+
headers,
197+
},
197198
utils: {
198199
status,
199200
cache,
200201
functions,
201202
build: { failBuild },
202203
},
203-
constants: { FUNCTIONS_DIST, PUBLISH_DIR },
204+
constants: { FUNCTIONS_DIST },
204205
}) {
205-
await saveCache({ cache, publish: netlifyConfig.build.publish })
206+
await saveCache({ cache, publish })
206207

207208
if (shouldSkip()) {
208209
status.show({
@@ -218,16 +219,15 @@ const plugin: NetlifyPlugin = {
218219

219220
await checkForOldFunctions({ functions })
220221
await checkZipSize(join(FUNCTIONS_DIST, `${ODB_FUNCTION_NAME}.zip`))
221-
const nextConfig = await getNextConfig({ publish: netlifyConfig.build.publish, failBuild })
222+
const nextConfig = await getNextConfig({ publish, failBuild })
222223

223224
const { basePath, appDir } = nextConfig
224225

225-
generateCustomHeaders(nextConfig, netlifyConfig.headers)
226+
generateCustomHeaders(nextConfig, headers)
226227

227-
warnForProblematicUserRewrites({ basePath, redirects: netlifyConfig.redirects })
228+
warnForProblematicUserRewrites({ basePath, redirects })
228229
warnForRootRedirects({ appDir })
229230
await warnOnApiRoutes({ FUNCTIONS_DIST })
230-
netlifyConfig.build.publish = join(PUBLISH_DIR, 'dist')
231231
},
232232
}
233233
// The types haven't been updated yet

0 commit comments

Comments
 (0)