Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix gsp generation with file extension #27144

Merged
merged 6 commits into from
Jul 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 11 additions & 4 deletions packages/next/export/worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,15 +199,22 @@ export default async function exportPage({
publicRuntimeConfig: renderOpts.runtimeConfig,
})

let htmlFilename = `${filePath}${sep}index.html`
if (!subFolders) htmlFilename = `${filePath}.html`
const getHtmlFilename = (_path: string) =>
subFolders ? `${_path}${sep}index.html` : `${_path}.html`
let htmlFilename = getHtmlFilename(filePath)

const pageExt = extname(page)
const pathExt = extname(path)
// Make sure page isn't a folder with a dot in the name e.g. `v1.2`
if (pageExt !== pathExt && pathExt !== '') {
// If the path has an extension, use that as the filename instead
htmlFilename = path
const isBuiltinPaths = ['/500', '/404'].some(
(p) => p === path || p === path + '.html'
)
// If the ssg path has .html extension, and it's not builtin paths, use it directly
// Otherwise, use that as the filename instead
const isHtmlExtPath =
!serverless && !isBuiltinPaths && path.endsWith('.html')
htmlFilename = isHtmlExtPath ? getHtmlFilename(path) : path
} else if (path === '/') {
// If the path is the root, just use index.html
htmlFilename = 'index.html'
Expand Down
20 changes: 20 additions & 0 deletions test/integration/gsp-extension/pages/[slug].js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
export default function Page({ value }) {
return value
}

export const getStaticProps = ({ params }) => ({
props: {
value: params.slug,
},
})

export const getStaticPaths = () => {
return {
paths: [
{ params: { slug: '1' } },
{ params: { slug: '2.ext' } },
{ params: { slug: '3.html' } },
],
fallback: false,
}
}
59 changes: 59 additions & 0 deletions test/integration/gsp-extension/test/index.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/* eslint-env jest */

import fs from 'fs-extra'
import { join } from 'path'
import {
fetchViaHTTP,
findPort,
killApp,
nextBuild,
nextStart,
renderViaHTTP,
} from 'next-test-utils'

jest.setTimeout(1000 * 60 * 2)
const appDir = join(__dirname, '..')

let appPort
let app
const fileNames = ['1', '2.ext', '3.html']

describe('GS(S)P with file extension', () => {
beforeAll(async () => {
await fs.remove(join(appDir, '.next'))
const { code } = await nextBuild(appDir)
if (code !== 0) throw new Error(`build failed with code ${code}`)

appPort = await findPort()
app = await nextStart(appDir, appPort)
})
afterAll(() => killApp(app))

it('should support slug with different extensions', async () => {
huozhi marked this conversation as resolved.
Show resolved Hide resolved
const baseDir = join(appDir, '.next/server/pages')
fileNames.forEach((name) => {
const filePath = join(baseDir, name)
expect(fs.existsSync(filePath + '.html')).toBe(true)
expect(fs.existsSync(filePath + '.json')).toBe(true)
})
})

it('should render properly for routes with extension', async () => {
const paths = fileNames.map((name) => `/${name}`)
const contentPromises = paths.map((path) => renderViaHTTP(appPort, path))
const contents = await Promise.all(contentPromises)
contents.forEach((content, i) => expect(content).toContain(fileNames[i]))
})

it('should contain extension in name of json files in _next/data', async () => {
const buildId = await fs.readFile(join(appDir, '.next/BUILD_ID'), 'utf8')
const requests = fileNames.map((name) => {
const pathname = `/_next/data/${buildId}/${name}.json`
return fetchViaHTTP(appPort, pathname).then((r) => r.json())
})
const results = await Promise.all(requests)
results.forEach((result, i) =>
expect(result.pageProps.value).toBe(fileNames[i])
)
})
})