Skip to content

Commit

Permalink
Emit Static Export Intent (#9737)
Browse files Browse the repository at this point in the history
* Emit Static Export Intent

* Remove the old export detail on rebuild

* Add test cases

* fix export

* Add a resolve return
  • Loading branch information
Timer authored and ijjk committed Dec 13, 2019
1 parent 677a950 commit 62a6ece
Show file tree
Hide file tree
Showing 17 changed files with 292 additions and 3 deletions.
18 changes: 18 additions & 0 deletions packages/next/build/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import { verifyTypeScriptSetup } from '../lib/verifyTypeScriptSetup'
import {
BUILD_MANIFEST,
DEFAULT_REDIRECT_STATUS,
EXPORT_DETAIL,
EXPORT_MARKER,
PAGES_MANIFEST,
PHASE_PRODUCTION_BUILD,
PRERENDER_MANIFEST,
Expand Down Expand Up @@ -716,6 +718,22 @@ export default async function build(dir: string, conf = null): Promise<void> {
)
}

await fsWriteFile(
path.join(distDir, EXPORT_MARKER),
JSON.stringify({
version: 1,
hasExportPathMap: typeof config.exportPathMap === 'function',
exportTrailingSlash: config.exportTrailingSlash === true,
}),
'utf8'
)
await fsUnlink(path.join(distDir, EXPORT_DETAIL)).catch(err => {
if (err.code === 'ENOENT') {
return Promise.resolve()
}
return Promise.reject(err)
})

staticPages.forEach(pg => allStaticPages.add(pg))
pageInfos.forEach((info: PageInfo, key: string) => {
allPageInfos.set(key, info)
Expand Down
32 changes: 29 additions & 3 deletions packages/next/export/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import chalk from 'chalk'
import { copyFile as copyFileOrig, existsSync, readFileSync } from 'fs'
import findUp from 'find-up'
import {
copyFile as copyFileOrig,
existsSync,
readFileSync,
writeFileSync,
} from 'fs'
import Worker from 'jest-worker'
import mkdirpModule from 'mkdirp'
import { cpus } from 'os'
import { dirname, join, resolve, sep } from 'path'
import { promisify } from 'util'
import findUp from 'find-up'
import { AmpPageStatus, formatAmpMessages } from '../build/output/index'
import createSpinner from '../build/spinner'
import { API_ROUTE } from '../lib/constants'
Expand All @@ -16,11 +21,12 @@ import {
CLIENT_PUBLIC_FILES_PATH,
CLIENT_STATIC_FILES_PATH,
CONFIG_FILE,
EXPORT_DETAIL,
PAGES_MANIFEST,
PHASE_EXPORT,
PRERENDER_MANIFEST,
SERVER_DIRECTORY,
SERVERLESS_DIRECTORY,
SERVER_DIRECTORY,
} from '../next-server/lib/constants'
import loadConfig, {
isTargetLikeServerless,
Expand Down Expand Up @@ -180,6 +186,16 @@ export default async function(
await recursiveDelete(join(outDir))
await mkdirp(join(outDir, '_next', buildId))

writeFileSync(
join(distDir, EXPORT_DETAIL),
JSON.stringify({
version: 1,
outDirectory: outDir,
success: false,
}),
'utf8'
)

// Copy static directory
if (!options.buildExport && existsSync(join(dir, 'static'))) {
log(' copying "static" directory')
Expand Down Expand Up @@ -372,6 +388,16 @@ export default async function(
// Add an empty line to the console for the better readability.
log('')

writeFileSync(
join(distDir, EXPORT_DETAIL),
JSON.stringify({
version: 1,
outDirectory: outDir,
success: true,
}),
'utf8'
)

if (telemetry) {
await telemetry.flush()
}
Expand Down
2 changes: 2 additions & 0 deletions packages/next/next-server/lib/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ export const PHASE_PRODUCTION_SERVER = 'phase-production-server'
export const PHASE_DEVELOPMENT_SERVER = 'phase-development-server'
export const PAGES_MANIFEST = 'pages-manifest.json'
export const BUILD_MANIFEST = 'build-manifest.json'
export const EXPORT_MARKER = 'export-marker.json'
export const EXPORT_DETAIL = 'export-detail.json'
export const PRERENDER_MANIFEST = 'prerender-manifest.json'
export const ROUTES_MANIFEST = 'routes-manifest.json'
export const REACT_LOADABLE_MANIFEST = 'react-loadable-manifest.json'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/out
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
const A = () => {
throw new Error('fail da export')
}
A.getInitialProps = () => {}
export default A
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/out
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module.exports = {
exportPathMap() {
return { '/': { page: '/' } }
},
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default () => <div>Hello Export</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/lel
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
exportTrailingSlash: true,
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default () => <div>Hello Export</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/out
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default () => <div>Hello Export</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/out
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default () => <div>Hello Export</div>
217 changes: 217 additions & 0 deletions test/integration/export-intent/test/index.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
/* eslint-env jest */
/* global jasmine */
import { remove } from 'fs-extra'
import { nextBuild, nextExport, nextExportDefault } from 'next-test-utils'
import path, { join } from 'path'
import fs from 'fs'

jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000 * 60 * 2

const fixturesDir = join(__dirname, '..', 'fixtures')

describe('Application Export Intent Output', () => {
describe('Default Export', () => {
const appDir = join(fixturesDir, 'default-export')
const distDir = join(appDir, '.next')

beforeAll(async () => {
await remove(distDir)
})

it('should build and export', async () => {
await nextBuild(appDir)
await nextExportDefault(appDir)
})

it('should have the expected outputs for export', () => {
expect(
JSON.parse(fs.readFileSync(join(distDir, 'export-marker.json'), 'utf8'))
).toMatchInlineSnapshot(`
Object {
"exportTrailingSlash": false,
"hasExportPathMap": false,
"version": 1,
}
`)

const detail = JSON.parse(
fs.readFileSync(join(distDir, 'export-detail.json'), 'utf8')
)
expect({
...detail,
outDirectory: path.basename(detail.outDirectory),
}).toMatchInlineSnapshot(`
Object {
"outDirectory": "out",
"success": true,
"version": 1,
}
`)
})
})

describe('Custom Export', () => {
const appDir = join(fixturesDir, 'custom-export')
const distDir = join(appDir, '.next')

beforeAll(async () => {
await remove(distDir)
})

it('should build and export', async () => {
await nextBuild(appDir)
await nextExportDefault(appDir)
})

it('should have the expected outputs for export', () => {
expect(
JSON.parse(fs.readFileSync(join(distDir, 'export-marker.json'), 'utf8'))
).toMatchInlineSnapshot(`
Object {
"exportTrailingSlash": false,
"hasExportPathMap": true,
"version": 1,
}
`)

const detail = JSON.parse(
fs.readFileSync(join(distDir, 'export-detail.json'), 'utf8')
)
expect({
...detail,
outDirectory: path.basename(detail.outDirectory),
}).toMatchInlineSnapshot(`
Object {
"outDirectory": "out",
"success": true,
"version": 1,
}
`)
})
})

describe('Custom Out', () => {
const appDir = join(fixturesDir, 'custom-out')
const distDir = join(appDir, '.next')

beforeAll(async () => {
await remove(distDir)
})

it('should build and export', async () => {
await nextBuild(appDir)
await nextExport(appDir, { outdir: join(appDir, 'lel') })
})

it('should have the expected outputs for export', () => {
expect(
JSON.parse(fs.readFileSync(join(distDir, 'export-marker.json'), 'utf8'))
).toMatchInlineSnapshot(`
Object {
"exportTrailingSlash": true,
"hasExportPathMap": false,
"version": 1,
}
`)

const detail = JSON.parse(
fs.readFileSync(join(distDir, 'export-detail.json'), 'utf8')
)
expect({
...detail,
outDirectory: path.basename(detail.outDirectory),
}).toMatchInlineSnapshot(`
Object {
"outDirectory": "lel",
"success": true,
"version": 1,
}
`)
})
})

describe('Bad Export', () => {
const appDir = join(fixturesDir, 'bad-export')
const distDir = join(appDir, '.next')

beforeAll(async () => {
await remove(distDir)
})

it('should build and export', async () => {
await nextBuild(appDir)
await nextExportDefault(appDir)
})

it('should have the expected outputs for export', () => {
expect(
JSON.parse(fs.readFileSync(join(distDir, 'export-marker.json'), 'utf8'))
).toMatchInlineSnapshot(`
Object {
"exportTrailingSlash": false,
"hasExportPathMap": false,
"version": 1,
}
`)

const detail = JSON.parse(
fs.readFileSync(join(distDir, 'export-detail.json'), 'utf8')
)
expect({
...detail,
outDirectory: path.basename(detail.outDirectory),
}).toMatchInlineSnapshot(`
Object {
"outDirectory": "out",
"success": false,
"version": 1,
}
`)
})
})

describe('No Export', () => {
const appDir = join(fixturesDir, 'no-export')
const distDir = join(appDir, '.next')

beforeAll(async () => {
await remove(distDir)
})

it('should build and not export', async () => {
await nextBuild(appDir)
})

it('should have the expected outputs for export', () => {
expect(
JSON.parse(fs.readFileSync(join(distDir, 'export-marker.json'), 'utf8'))
).toMatchInlineSnapshot(`
Object {
"exportTrailingSlash": false,
"hasExportPathMap": false,
"version": 1,
}
`)

expect(() => {
fs.readFileSync(join(distDir, 'export-detail.json'), 'utf8')
}).toThrowError(/ENOENT/)
})

it('should export and create file', async () => {
await nextExportDefault(appDir)

expect(() => {
fs.readFileSync(join(distDir, 'export-detail.json'), 'utf8')
}).not.toThrow()
})

it('should build and clean up', async () => {
await nextBuild(appDir)

expect(() => {
fs.readFileSync(join(distDir, 'export-detail.json'), 'utf8')
}).toThrowError(/ENOENT/)
})
})
})
4 changes: 4 additions & 0 deletions test/lib/next-test-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,10 @@ export function nextExport(dir, { outdir }, opts = {}) {
return runNextCommand(['export', dir, '--outdir', outdir], opts)
}

export function nextExportDefault(dir, opts = {}) {
return runNextCommand(['export', dir], opts)
}

export function nextStart(dir, port, opts = {}) {
return runNextCommandDev(['start', '-p', port, dir], undefined, opts)
}
Expand Down

0 comments on commit 62a6ece

Please sign in to comment.