Skip to content

Commit

Permalink
Merge branch 'canary' into update/getserversideprops-invalid-return-v…
Browse files Browse the repository at this point in the history
…alue-format
  • Loading branch information
kodiakhq[bot] committed Apr 6, 2022
2 parents da11a58 + 9805399 commit b953271
Show file tree
Hide file tree
Showing 39 changed files with 297 additions and 939 deletions.
33 changes: 22 additions & 11 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ pnpm create next-app -- --typescript

After the installation is complete:

- Run `npm run dev` or `yarn dev` to start the development server on `http://localhost:3000`
- Run `npm run dev` or `yarn dev` or `pnpm dev` to start the development server on `http://localhost:3000`
- Visit `http://localhost:3000` to view your application
- Edit `pages/index.js` and see the updated result in your browser

Expand All @@ -55,6 +55,8 @@ Install `next`, `react` and `react-dom` in your project:
npm install next react react-dom
# or
yarn add next react react-dom
# or
pnpm add next react react-dom
```

Open `package.json` and add the following `scripts`:
Expand All @@ -70,18 +72,21 @@ Open `package.json` and add the following `scripts`:

These scripts refer to the different stages of developing an application:

- `dev` - Runs [`next dev`](/docs/api-reference/cli.md#development) which starts Next.js in development mode
- `build` - Runs [`next build`](/docs/api-reference/cli.md#build) which builds the application for production usage
- `start` - Runs [`next start`](/docs/api-reference/cli.md#production) which starts a Next.js production server
- `lint` - Runs [`next lint`](/docs/api-reference/cli.md#lint) which sets up Next.js' built-in ESLint configuration
- `dev` - Runs [`next dev`](/docs/api-reference/cli.md#development) to start Next.js in development mode
- `build` - Runs [`next build`](/docs/api-reference/cli.md#build) to build the application for production usage
- `start` - Runs [`next start`](/docs/api-reference/cli.md#production) to start a Next.js production server
- `lint` - Runs [`next lint`](/docs/api-reference/cli.md#lint) to set up Next.js' built-in ESLint configuration

Create two directories `pages` and `public` at the root of your application:

Next.js is built around the concept of [pages](/docs/basic-features/pages.md). A page is a [React Component](https://reactjs.org/docs/components-and-props.html) exported from a `.js`, `.jsx`, `.ts`, or `.tsx` file in the `pages` directory.
- `pages` - Associated with a route based on their file name. For example `pages/about.js` is mapped to `/about`
- `public` - Stores static assets such as images, fonts, etc. Files inside `public` directory can then be referenced by your code starting from the base URL (`/`).

Pages are associated with a route based on their file name. For example `pages/about.js` is mapped to `/about`. You can even add dynamic route parameters with the filename.
Next.js is built around the concept of [pages](/docs/basic-features/pages.md). A page is a [React Component](https://reactjs.org/docs/components-and-props.html) exported from a `.js`, `.jsx`, `.ts`, or `.tsx` file in the `pages` directory. You can even add [dynamic route](/docs/routing/dynamic-routes) parameters with the filename.

Create a `pages` directory inside your project.
Inside the `pages` directory add the `index.js` file to get started. This is the page that is rendered when the user visits the root of your application

Populate `./pages/index.js` with the following contents:
Populate `pages/index.js` with the following contents:

```jsx
function HomePage() {
Expand All @@ -91,12 +96,18 @@ function HomePage() {
export default HomePage
```

After the set up is complete:

- Run `npm run dev` or `yarn dev` or `pnpm dev` to start the development server on `http://localhost:3000`
- Visit `http://localhost:3000` to view your application
- Edit `pages/index.js` and see the updated result in your browser

So far, we get:

- Automatic compilation and [bundling](/docs/advanced-features/compiler.md)
- [React Fast Refresh](https://nextjs.org/blog/next-9-4#fast-refresh)
- [Static generation and server-side rendering](/docs/basic-features/data-fetching/overview.md) of [`./pages/`](/docs/basic-features/pages.md)
- [Static file serving](/docs/basic-features/static-file-serving.md). `./public/` is mapped to `/`
- [Static generation and server-side rendering](/docs/basic-features/data-fetching/overview.md) of [`pages/`](/docs/basic-features/pages.md)
- [Static file serving](/docs/basic-features/static-file-serving.md) through `public/` which is mapped to the base URL (`/`)

In addition, any Next.js application is ready for production from the start. Read more in our [Deployment documentation](/docs/deployment.md).

Expand Down
1 change: 1 addition & 0 deletions docs/testing.md
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,7 @@ For example, we can add a test to check if the `<Home />` component successfully

import { render, screen } from '@testing-library/react'
import Home from '../pages/index'
import '@testing-library/jest-dom'

describe('Home', () => {
it('renders a heading', () => {
Expand Down
35 changes: 9 additions & 26 deletions packages/next/build/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -450,18 +450,12 @@ export default async function build(
namedRegex?: string
routeKeys?: { [key: string]: string }
}>
dynamicRoutes: Array<
| {
page: string
regex: string
namedRegex?: string
routeKeys?: { [key: string]: string }
}
| {
page: string
isMiddleware: true
}
>
dynamicRoutes: Array<{
page: string
regex: string
namedRegex?: string
routeKeys?: { [key: string]: string }
}>
dataRoutes: Array<{
page: string
routeKeys?: { [key: string]: string }
Expand All @@ -480,14 +474,14 @@ export default async function build(
localeDetection?: false
}
} = nextBuildSpan.traceChild('generate-routes-manifest').traceFn(() => ({
version: 4,
version: 3,
pages404: true,
basePath: config.basePath,
redirects: redirects.map((r: any) => buildCustomRoute(r, 'redirect')),
headers: headers.map((r: any) => buildCustomRoute(r, 'header')),
dynamicRoutes: getSortedRoutes(pageKeys)
.filter((page) => isDynamicRoute(page))
.map(pageToRouteOrMiddleware),
.filter((page) => isDynamicRoute(page) && !page.match(MIDDLEWARE_ROUTE))
.map(pageToRoute),
staticRoutes: getSortedRoutes(pageKeys)
.filter(
(page) =>
Expand Down Expand Up @@ -2206,14 +2200,3 @@ function pageToRoute(page: string) {
namedRegex: routeRegex.namedRegex,
}
}

function pageToRouteOrMiddleware(page: string) {
if (page.match(MIDDLEWARE_ROUTE)) {
return {
page: page.replace(/\/_middleware$/, '') || '/',
isMiddleware: true as const,
}
}

return pageToRoute(page)
}
2 changes: 1 addition & 1 deletion packages/next/client/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -778,7 +778,7 @@ if (process.env.__NEXT_RSC) {
if (serialized) {
const readable = new ReadableStream({
start(controller) {
controller.enqueue(new TextEncoder().encode(serialized))
controller.enqueue(encoder.encode(serialized))
controller.close()
},
})
Expand Down
91 changes: 43 additions & 48 deletions packages/next/server/base-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@ import {
TEMPORARY_REDIRECT_STATUS,
} from '../shared/lib/constants'
import {
getRoutingItems,
getRouteMatcher,
getRouteRegex,
getSortedRoutes,
isDynamicRoute,
RoutingItem,
} from '../shared/lib/router/utils'
import {
setLazyProp,
Expand Down Expand Up @@ -70,6 +71,12 @@ export type FindComponentsResult = {
query: NextParsedUrlQuery
}

interface RoutingItem {
page: string
match: ReturnType<typeof getRouteMatcher>
ssr?: boolean
}

export interface Options {
/**
* Object containing the configuration next.config.js
Expand Down Expand Up @@ -170,8 +177,8 @@ export default abstract class Server {
protected dynamicRoutes?: DynamicRoutes
protected customRoutes: CustomRoutes
protected middlewareManifest?: MiddlewareManifest
protected middleware?: RoutingItem[]
protected serverComponentManifest?: any
protected allRoutes?: RoutingItem[]
public readonly hostname?: string
public readonly port?: number

Expand All @@ -183,8 +190,7 @@ export default abstract class Server {
protected abstract generateImageRoutes(): Route[]
protected abstract generateStaticRoutes(): Route[]
protected abstract generateFsStaticRoutes(): Route[]
protected abstract generateCatchAllStaticMiddlewareRoute(): Route | undefined
protected abstract generateCatchAllDynamicMiddlewareRoute(): Route | undefined
protected abstract generateCatchAllMiddlewareRoute(): Route | undefined
protected abstract generateRewrites({
restrictedRedirectPaths,
}: {
Expand All @@ -195,6 +201,14 @@ export default abstract class Server {
fallback: Route[]
}
protected abstract getFilesystemPaths(): Set<string>
protected abstract getMiddleware(): {
match: (pathname: string | null | undefined) =>
| false
| {
[paramName: string]: string | string[]
}
page: string
}[]
protected abstract findPageComponents(
pathname: string,
query?: NextParsedUrlQuery,
Expand Down Expand Up @@ -640,11 +654,9 @@ export default abstract class Server {
fallback: Route[]
}
fsRoutes: Route[]
internalFsRoutes: Route[]
redirects: Route[]
catchAllRoute: Route
catchAllStaticMiddleware?: Route
catchAllDynamicMiddleware?: Route
catchAllMiddleware?: Route
pageChecker: PageChecker
useFileSystemPublicRoutes: boolean
dynamicRoutes: DynamicRoutes | undefined
Expand All @@ -654,7 +666,7 @@ export default abstract class Server {
const imageRoutes = this.generateImageRoutes()
const staticFilesRoutes = this.generateStaticRoutes()

const internalFsRoutes: Route[] = [
const fsRoutes: Route[] = [
...this.generateFsStaticRoutes(),
{
match: route('/_next/data/:path*'),
Expand Down Expand Up @@ -744,10 +756,10 @@ export default abstract class Server {
}
},
},
...publicRoutes,
...staticFilesRoutes,
]

const fsRoutes: Route[] = [...publicRoutes, ...staticFilesRoutes]

const restrictedRedirectPaths = this.nextConfig.basePath
? [`${this.nextConfig.basePath}/_next`]
: ['/_next']
Expand All @@ -766,10 +778,7 @@ export default abstract class Server {
)

const rewrites = this.generateRewrites({ restrictedRedirectPaths })
const catchAllStaticMiddleware =
this.generateCatchAllStaticMiddlewareRoute()
const catchAllDynamicMiddleware =
this.generateCatchAllDynamicMiddlewareRoute()
const catchAllMiddleware = this.generateCatchAllMiddlewareRoute()

const catchAllRoute: Route = {
match: route('/:path*'),
Expand Down Expand Up @@ -804,7 +813,7 @@ export default abstract class Server {
}
}

if (isApiRoute(pathname)) {
if (pathname === '/api' || pathname.startsWith('/api/')) {
delete query._nextBubbleNoFallback

const handled = await this.handleApiRequest(req, res, pathname, query)
Expand Down Expand Up @@ -833,19 +842,19 @@ export default abstract class Server {
const { useFileSystemPublicRoutes } = this.nextConfig

if (useFileSystemPublicRoutes) {
this.allRoutes = this.getAllRoutes()
this.dynamicRoutes = this.getDynamicRoutes()
if (!this.minimalMode) {
this.middleware = this.getMiddleware()
}
}

return {
headers,
fsRoutes,
internalFsRoutes,
rewrites,
redirects,
catchAllRoute,
catchAllStaticMiddleware,
catchAllDynamicMiddleware,
catchAllMiddleware,
useFileSystemPublicRoutes,
dynamicRoutes: this.dynamicRoutes,
basePath: this.nextConfig.basePath,
Expand Down Expand Up @@ -922,34 +931,24 @@ export default abstract class Server {
return this.runApi(req, res, query, params, page, builtPagePath)
}

protected getAllRoutes(): RoutingItem[] {
const pages = Object.keys(this.pagesManifest!).map(
(page) =>
normalizeLocalePath(page, this.nextConfig.i18n?.locales).pathname
)
const middlewareMap = this.minimalMode
? {}
: this.middlewareManifest?.middleware || {}
const middleware = Object.keys(middlewareMap).map((page) => ({
page,
ssr: !MIDDLEWARE_ROUTE.test(middlewareMap[page].name),
}))
return getRoutingItems(pages, middleware)
}

protected getDynamicRoutes(): Array<RoutingItem> {
const addedPages = new Set<string>()

return this.allRoutes!.filter((item) => {
if (
item.isMiddleware ||
addedPages.has(item.page) ||
!isDynamicRoute(item.page)
return getSortedRoutes(
Object.keys(this.pagesManifest!).map(
(page) =>
normalizeLocalePath(page, this.nextConfig.i18n?.locales).pathname
)
return false
addedPages.add(item.page)
return true
})
)
.map((page) => {
if (addedPages.has(page) || !isDynamicRoute(page)) return null
addedPages.add(page)
return {
page,
match: getRouteMatcher(getRouteRegex(page)),
}
})
.filter((item): item is RoutingItem => Boolean(item))
}

protected async run(
Expand Down Expand Up @@ -1941,10 +1940,6 @@ export function prepareServerlessUrl(

export { stringifyQuery } from './server-route-utils'

export function isApiRoute(pathname: string) {
return pathname === '/api' || pathname.startsWith('/api/')
}

class NoFallbackError extends Error {}

// Internal wrapper around build errors at development
Expand Down

0 comments on commit b953271

Please sign in to comment.