Skip to content

Commit

Permalink
Merge branch 'canary' into fix/incoming-message-cookies-type
Browse files Browse the repository at this point in the history
  • Loading branch information
mattfwood committed Dec 8, 2020
2 parents 71e7a27 + e3244e9 commit eceba3f
Show file tree
Hide file tree
Showing 26 changed files with 301 additions and 25 deletions.
17 changes: 17 additions & 0 deletions .github/workflows/cancel.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
name: Cancel
on:
pull_request_target:
types:
- edited
- synchronize

jobs:
cancel:
name: 'Cancel Previous Runs'
runs-on: ubuntu-latest
timeout-minutes: 2
steps:
- uses: styfle/cancel-workflow-action@0.5.0
with:
workflow_id: 444921, 444987
access_token: ${{ github.token }}
10 changes: 10 additions & 0 deletions errors/next-export-no-build-id.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Could not find a production build

#### Why This Error Occurred

When running `next export` a production build is needed.

#### Possible Ways to Fix It

- Run `next build` to create a production build before running `next export`.
- If your intention was to run the development server run `next dev` instead.
10 changes: 10 additions & 0 deletions errors/production-start-no-build-id.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Could not find a production build

#### Why This Error Occurred

When running `next start` or a custom server in production mode a production build is needed.

#### Possible Ways to Fix It

- Run `next build` to create a production build before booting up the production server.
- If your intention was to run the development server run `next dev` instead.
2 changes: 1 addition & 1 deletion examples/with-apollo/pages/client-only.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const ClientOnlyPage = (props) => (
<App>
<Header />
<InfoBox>
ℹ️ This page shows how use Apollo only in the client. If you{' '}
ℹ️ This page shows how to use Apollo only in the client. If you{' '}
<a href="/client-only">reload</a> this page, you will see a loader since
Apollo didn't fetch any data on the server. This is useful when the page
doesn't have SEO requirements or blocking data fetching requirements.
Expand Down
2 changes: 1 addition & 1 deletion examples/with-docker/Dockerfile.multistage
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ RUN yarn install --production --frozen-lockfile


# Stage 2: And then copy over node_modules, etc from that stage to the smaller base image
FROM mhart/alpine-node:base as production
FROM mhart/alpine-node:slim as production

WORKDIR /app

Expand Down
4 changes: 2 additions & 2 deletions examples/with-electron/README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Electron application example

This example show how you can use Next.js inside an Electron application to avoid a lot of configuration, use Next.js router as view and use server-render to speed up the initial render of the application.
This example shows how you can use Next.js inside an Electron application to avoid a lot of configuration. It uses the Next.js router as view and server-render to speed up the initial render of the application.

For development it's going to run a HTTP server and let Next.js handle routing. In production it use `next export` to pre-generate HTML static files and use them in your app instead of running an HTTP server.
For development it's going to run an HTTP server and let Next.js handle routing. In production it uses `next export` to pre-generate HTML static files and uses them in your app instead of running an HTTP server.

**You can find a detailed documentation about how to build Electron apps with Next.js [here](https://leo.im/2017/electron-next)!**

Expand Down
4 changes: 2 additions & 2 deletions examples/with-facebook-pixel/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
## Example app using Facebook Pixel

This example shows how to use Next.js along with Facebook Pixel. A [custom `App`](https://nextjs.org/docs/advanced-features/custom-app) is used to track route changes and send page views to Facebook Pixel. This example uses [react-facebook-pixel](https://www.npmjs.com/package/react-facebook-pixel).
This example shows how to use Next.js along with Facebook Pixel. A custom [\_document](https://nextjs.org/docs/advanced-features/custom-document) is used to inject [base code](https://developers.facebook.com/docs/facebook-pixel/implementation/?locale=en_US). A [\_app](https://nextjs.org/docs/advanced-features/custom-app) is used to track route changes and send page views to Facebook Pixel.

## Deploy your own

Expand All @@ -24,6 +24,6 @@ Next, copy the `.env.local.example` file in this directory to `.env.local` (whic
cp .env.local.example .env.local
```

Set the `NEXT_PUBLIC_FACEBOOK_PIXEL_ID` variable in `.env.local` to match your facebook app's pixel ID. If not specified, tracking will be disabled.
Set the `NEXT_PUBLIC_FACEBOOK_PIXEL_ID` variable in `.env.local` to match your facebook app's pixel ID.

Deploy it to the cloud with [Vercel](https://vercel.com/import?filter=next.js&utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)).
3 changes: 1 addition & 2 deletions examples/with-facebook-pixel/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@
"dependencies": {
"next": "latest",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-facebook-pixel": "^1.0.3"
"react-dom": "^16.13.1"
},
"license": "MIT"
}
9 changes: 0 additions & 9 deletions packages/next/build/webpack-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -364,15 +364,6 @@ export default async function getBaseWebpackConfig(
...nodePathList, // Support for NODE_PATH environment variable
],
alias: {
// These aliases make sure the wrapper module is not included in the bundles
// Which makes bundles slightly smaller, but also skips parsing a module that we know will result in this alias
'next/head': 'next/dist/next-server/lib/head.js',
'next/router': 'next/dist/client/router.js',
'next/experimental-script': config.experimental.scriptLoader
? 'next/dist/client/experimental-script.js'
: '',
'next/config': 'next/dist/next-server/lib/runtime-config.js',
'next/dynamic': 'next/dist/next-server/lib/dynamic.js',
next: NEXT_PROJECT_ROOT,
...(isWebpack5 && !isServer
? {
Expand Down
2 changes: 1 addition & 1 deletion packages/next/cli/next-export.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ const nextExport: cliCommand = (argv) => {

exportApp(dir, options)
.then(() => {
printAndExit('Export successful', 0)
printAndExit(`Export successful. Files written to ${options.outdir}`, 0)
})
.catch((err) => {
printAndExit(err)
Expand Down
8 changes: 5 additions & 3 deletions packages/next/export/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,11 @@ export default async function exportApp(
Log.info(`using build directory: ${distDir}`)
}

if (!existsSync(distDir)) {
const buildIdFile = join(distDir, BUILD_ID_FILE)

if (!existsSync(buildIdFile)) {
throw new Error(
`Build directory ${distDir} does not exist. Make sure you run "next build" before running "next start" or "next export".`
`Could not find a production build in the '${distDir}' directory. Try building your app with 'next build' before starting the static export. https://err.sh/vercel/next.js/next-export-no-build-id`
)
}

Expand All @@ -186,7 +188,7 @@ export default async function exportApp(
)
}

const buildId = readFileSync(join(distDir, BUILD_ID_FILE), 'utf8')
const buildId = readFileSync(buildIdFile, 'utf8')
const pagesManifest =
!options.pages &&
(require(join(
Expand Down
5 changes: 5 additions & 0 deletions packages/next/lib/load-custom-routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -466,12 +466,14 @@ export default async function loadCustomRoutes(
destination: '/:file',
permanent: true,
locale: config.i18n ? false : undefined,
internal: true,
} as Redirect,
{
source: '/:notfile((?!\\.well-known(?:/.*)?)(?:[^/]+/)*[^/\\.]+)',
destination: '/:notfile/',
permanent: true,
locale: config.i18n ? false : undefined,
internal: true,
} as Redirect
)
if (config.basePath) {
Expand All @@ -481,6 +483,7 @@ export default async function loadCustomRoutes(
permanent: true,
basePath: false,
locale: config.i18n ? false : undefined,
internal: true,
} as Redirect)
}
} else {
Expand All @@ -489,6 +492,7 @@ export default async function loadCustomRoutes(
destination: '/:path+',
permanent: true,
locale: config.i18n ? false : undefined,
internal: true,
} as Redirect)
if (config.basePath) {
redirects.unshift({
Expand All @@ -497,6 +501,7 @@ export default async function loadCustomRoutes(
permanent: true,
basePath: false,
locale: config.i18n ? false : undefined,
internal: true,
} as Redirect)
}
}
Expand Down
3 changes: 2 additions & 1 deletion packages/next/next-server/lib/post-process.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { parse, HTMLElement } from 'node-html-parser'
import { OPTIMIZED_FONT_PROVIDERS } from './constants'

const MIDDLEWARE_TIME_BUDGET = 10
const MIDDLEWARE_TIME_BUDGET =
parseInt(process.env.__POST_PROCESS_MIDDLEWARE_TIME_BUDGET || '', 10) || 10
const MAXIMUM_IMAGE_PRELOADS = 2
const IMAGE_PRELOAD_SIZE_THRESHOLD = 2500

Expand Down
2 changes: 1 addition & 1 deletion packages/next/next-server/server/api-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export async function apiResolver(
)

// Parsing of body
if (bodyParser) {
if (bodyParser && !apiReq.body) {
apiReq.body = await parseBody(
apiReq,
config.api && config.api.bodyParser && config.api.bodyParser.sizeLimit
Expand Down
3 changes: 2 additions & 1 deletion packages/next/next-server/server/next-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -720,6 +720,7 @@ export default class Server {
const redirects = this.customRoutes.redirects.map((redirect) => {
const redirectRoute = getCustomRoute(redirect, 'redirect')
return {
internal: redirectRoute.internal,
type: redirectRoute.type,
match: redirectRoute.match,
statusCode: redirectRoute.statusCode,
Expand Down Expand Up @@ -1898,7 +1899,7 @@ export default class Server {
} catch (err) {
if (!fs.existsSync(buildIdFile)) {
throw new Error(
`Could not find a valid build in the '${this.distDir}' directory! Try building your app with 'next build' before starting the server.`
`Could not find a production build in the '${this.distDir}' directory. Try building your app with 'next build' before starting the production server. https://err.sh/vercel/next.js/production-start-no-build-id`
)
}

Expand Down
7 changes: 6 additions & 1 deletion packages/next/next-server/server/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export type Route = {
statusCode?: number
name: string
requireBasePath?: false
internal?: true
fn: (
req: IncomingMessage,
res: ServerResponse,
Expand Down Expand Up @@ -197,7 +198,11 @@ export default class Router {
const activeBasePath = keepBasePath ? this.basePath : ''

if (keepLocale) {
if (!localePathResult.detectedLocale && parsedUrl.query.__nextLocale) {
if (
!testRoute.internal &&
parsedUrl.query.__nextLocale &&
!localePathResult.detectedLocale
) {
currentPathname = `${activeBasePath}/${parsedUrl.query.__nextLocale}${
currentPathnameNoBasePath === '/' ? '' : currentPathnameNoBasePath
}`
Expand Down
1 change: 1 addition & 0 deletions run-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@ const configuredTestTypes = [UNIT_TEST_EXT]
...(isAzure
? {
HEADLESS: 'true',
__POST_PROCESS_MIDDLEWARE_TIME_BUDGET: '50',
}
: {}),
...(usePolling
Expand Down
5 changes: 5 additions & 0 deletions test/integration/api-body-parser/pages/api/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export default ({ method, body }, res) => {
if (method === 'POST') {
res.status(200).json(body)
}
}
28 changes: 28 additions & 0 deletions test/integration/api-body-parser/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
const next = require('next')
const bodyParser = require('body-parser')
const express = require('express')

const dev = process.env.NODE_ENV !== 'production'
const dir = __dirname
const port = process.env.PORT || 3000

const app = next({ dev, dir })
const handleNextRequests = app.getRequestHandler()

app.prepare().then(() => {
const server = express()

server.use(bodyParser.json({ limit: '5mb' }))

server.all('*', (req, res) => {
handleNextRequests(req, res)
})

server.listen(port, (err) => {
if (err) {
throw err
}

console.log(`> Ready on http://localhost:${port}`)
})
})
72 changes: 72 additions & 0 deletions test/integration/api-body-parser/test/index.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/* eslint-env jest */

import { join } from 'path'
import {
killApp,
findPort,
launchApp,
fetchViaHTTP,
initNextServerScript,
} from 'next-test-utils'
import clone from 'clone'
import getPort from 'get-port'

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

let app
let server
jest.setTimeout(1000 * 60 * 2)

const context = {}

function runTests() {
it('should parse JSON body', async () => {
appPort = await findPort()
app = await launchApp(appDir, appPort, {})
const data = await makeRequest()
expect(data).toEqual([{ title: 'Nextjs' }])
killApp(app)
})

it('should not throw if request body is already parsed in custom middleware', async () => {
await startServer()
const data = await makeRequest()
expect(data).toEqual([{ title: 'Nextjs' }])
killApp(server)
})
}

async function makeRequest() {
const data = await fetchViaHTTP(appPort, '/api', null, {
method: 'POST',
headers: {
'Content-Type': 'application/json; charset=utf-8',
},
body: JSON.stringify([{ title: 'Nextjs' }]),
}).then((res) => res.ok && res.json())

return data
}

const startServer = async (optEnv = {}, opts) => {
const scriptPath = join(appDir, 'server.js')
context.appPort = appPort = await getPort()
const env = Object.assign(
{},
clone(process.env),
{ PORT: `${appPort}` },
optEnv
)

server = await initNextServerScript(
scriptPath,
/ready on/i,
env,
/ReferenceError: options is not defined/,
opts
)
}

runTests()
1 change: 1 addition & 0 deletions test/integration/custom-routes/test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,7 @@ const runTests = (isDev = false) => {
),
source: '/:path+/',
statusCode: 308,
internal: true,
},
{
destination: '/:lang/about',
Expand Down

0 comments on commit eceba3f

Please sign in to comment.