Skip to content

Commit

Permalink
Merge branch 'canary' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
iliran11 authored Oct 16, 2019
2 parents 17de15c + 117d023 commit 0b5a513
Show file tree
Hide file tree
Showing 21 changed files with 115 additions and 67 deletions.
7 changes: 5 additions & 2 deletions examples/using-inferno/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
# Hello World example
# Inferno example

> **Important**: Inferno does not support hooks nor Suspense. It may work on development where React is utilized instead of Inferno, but it will break as soon as you try to build it or start it out of development.
## How to use

Expand Down Expand Up @@ -39,8 +41,9 @@ now

## The idea behind the example

This example uses [Inferno](https://github.com/infernojs/inferno), an insanely fast, 9kb React-like library for building high-performance user interfaces on both the client and server. Here we've customized Next.js to use Inferno instead of React.
This example uses [Inferno](https://github.com/infernojs/inferno), an insanely fast, 9kb React-like library for building high-performance user interfaces on both the client and server. Here we've customized Next.js to use Inferno instead of React in the production build.

Here's how we did it:

- Use `next.config.js` to customize our webpack config to support [inferno-compat](https://www.npmjs.com/package/inferno-compat)
- Create `lib/inferno-compat.js` to polyfill the `React.createContext` API (required by Next.js) that is not available by `inferno-compat`
11 changes: 11 additions & 0 deletions examples/using-inferno/lib/inferno-compat.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const React = require('inferno-compat')
const createContext = require('create-react-context/lib/implementation')

Object.keys(React).forEach(key => {
if (key === 'default' || key === '__esModule') return
exports[key] = React[key]
})

// bypass export of React.createContext
exports.createContext = createContext
exports.default = React.default
8 changes: 6 additions & 2 deletions examples/using-inferno/next.config.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
const path = require('path')

module.exports = {
webpack: function (config, { dev }) {
// For the development version, we'll use React.
Expand All @@ -8,9 +10,11 @@ module.exports = {

config.resolve.alias = {
...config.resolve.alias,
react: 'inferno-compat',
'react-dom': 'inferno-compat'
react: path.resolve('./lib/inferno-compat.js'),
'react-dom': path.resolve('./lib/inferno-compat.js'),
'react-dom/server': 'inferno-server'
}

return config
}
}
7 changes: 4 additions & 3 deletions examples/using-inferno/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@
"start": "NODE_ENV=production node server.js"
},
"dependencies": {
"inferno": "^1.4.0",
"inferno-compat": "^1.4.0",
"inferno-server": "^1.4.0",
"create-react-context": "0.3.0",
"inferno": "7.3.2",
"inferno-compat": "7.3.2",
"inferno-server": "7.3.2",
"module-alias": "^2.0.0",
"next": "latest",
"react": "^16.7.0",
Expand Down
5 changes: 3 additions & 2 deletions examples/using-inferno/server.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
const port = parseInt(process.env.PORT, 10) || 3000
const dev = process.env.NODE_ENV !== 'production'
const moduleAlias = require('module-alias')
const path = require('path')

// For the development version, we'll use React.
// Because, it support react hot loading and so on.
if (!dev) {
moduleAlias.addAlias('react', 'inferno-compat')
moduleAlias.addAlias('react', path.resolve('./lib/inferno-compat.js'))
moduleAlias.addAlias('react-dom/server', 'inferno-server')
moduleAlias.addAlias('react-dom', 'inferno-compat')
moduleAlias.addAlias('react-dom', path.resolve('./lib/inferno-compat.js'))
}

const { createServer } = require('http')
Expand Down
4 changes: 2 additions & 2 deletions examples/with-typescript/components/Layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ const Layout: React.FunctionComponent<Props> = ({
<a>About</a>
</Link>{' '}
|{' '}
<Link href="/initial-props">
<a>With Initial Props</a>
<Link href="/users">
<a>Users List</a>
</Link>
</nav>
</header>
Expand Down
2 changes: 1 addition & 1 deletion examples/with-typescript/components/ListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ type Props = {
}

const ListItem: React.FunctionComponent<Props> = ({ data }) => (
<Link href={`/detail?id=${data.id}`}>
<Link href="/users/[id]" as={`/users/${data.id}`}>
<a>
{data.id}: {data.name}
</a>
Expand Down
1 change: 1 addition & 0 deletions examples/with-typescript/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"type-check": "tsc"
},
"dependencies": {
"isomorphic-unfetch": "3.0.0",
"next": "latest",
"react": "^16.10.1",
"react-dom": "^16.10.1"
Expand Down
18 changes: 18 additions & 0 deletions examples/with-typescript/pages/api/users/[id].ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { NextApiRequest, NextApiResponse } from 'next'
import { sampleUserData } from '../../../utils/sample-data'

export default (req: NextApiRequest, res: NextApiResponse) => {
try {
const { id } = req.query;
const selected = sampleUserData.find(data => data.id === Number(id))

if (!selected) {
throw new Error('Cannot find user')
}

res.status(200).json(selected)
} catch (err) {
res.status(404).json({ statusCode: 404, message: err.message })
}
}

14 changes: 14 additions & 0 deletions examples/with-typescript/pages/api/users/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { NextApiRequest, NextApiResponse } from 'next'
import { sampleUserData } from '../../../utils/sample-data'

export default (_: NextApiRequest, res: NextApiResponse) => {
try {
if (!Array.isArray(sampleUserData)) {
throw new Error('Cannot find user data')
}

res.status(200).json(sampleUserData)
} catch (err) {
res.status(500).json({ statusCode: 500, message: err.message })
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import * as React from 'react'
import { NextPageContext } from 'next'
import Layout from '../components/Layout'
import { User } from '../interfaces'
import { findData } from '../utils/sample-api'
import ListDetail from '../components/ListDetail'

import { User } from '../../interfaces'
import Layout from '../../components/Layout'
import ListDetail from '../../components/ListDetail'
import { sampleFetchWrapper } from '../../utils/sample-api'

type Props = {
item?: User
Expand All @@ -14,7 +15,7 @@ class InitialPropsDetail extends React.Component<Props> {
static getInitialProps = async ({ query }: NextPageContext) => {
try {
const { id } = query
const item = await findData(Array.isArray(id) ? id[0] : id)
const item = await sampleFetchWrapper(`http://localhost:3000/api/users/${Array.isArray(id) ? id[0] : id}`)
return { item }
} catch (err) {
return { errors: err.message }
Expand All @@ -36,7 +37,7 @@ class InitialPropsDetail extends React.Component<Props> {

return (
<Layout
title={`${item ? item.name : 'Detail'} | Next.js + TypeScript Example`}
title={`${item ? item.name : 'User Detail'} | Next.js + TypeScript Example`}
>
{item && <ListDetail item={item} />}
</Layout>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
import { NextPage } from 'next'
import Link from 'next/link'
import Layout from '../components/Layout'
import List from '../components/List'
import { User } from '../interfaces'
import { findAll } from '../utils/sample-api'

import Layout from '../../components/Layout'
import List from '../../components/List'
import { User } from '../../interfaces'
import { sampleFetchWrapper } from '../../utils/sample-api'

type Props = {
items: User[]
pathname: string
}

const WithInitialProps: NextPage<Props> = ({ items, pathname }) => (
<Layout title="List Example (as Functional Component) | Next.js + TypeScript Example">
<h1>List Example (as Function Component)</h1>
<Layout title="Users List | Next.js + TypeScript Example">
<h1>Users List</h1>
<p>
Example fetching data from inside <code>getInitialProps()</code>.
</p>
<p>You are currently on: {pathname}</p>
<List items={items} />
<p>
Expand All @@ -24,10 +28,12 @@ const WithInitialProps: NextPage<Props> = ({ items, pathname }) => (
)

WithInitialProps.getInitialProps = async ({ pathname }) => {
// Example for including initial props in a Next.js function compnent page.
// Example for including initial props in a Next.js function component page.
// Don't forget to include the respective types for any props passed into
// the component.
const items: User[] = await findAll()
const items: User[] = await sampleFetchWrapper(
'http://localhost:3000/api/users'
)

return { items, pathname }
}
Expand Down
43 changes: 11 additions & 32 deletions examples/with-typescript/utils/sample-api.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,13 @@
import { User } from '../interfaces'

/** Dummy user data. */
export const dataArray: User[] = [
{ id: 101, name: 'Alice' },
{ id: 102, name: 'Bob' },
{ id: 103, name: 'Caroline' },
{ id: 104, name: 'Dave' },
]

/**
* Calls a mock API which finds a user by ID from the list above.
*
* Throws an error if not found.
*/
export async function findData(id: number | string) {
const selected = dataArray.find(data => data.id === Number(id))

if (!selected) {
throw new Error('Cannot find user')
}

return selected
}

/** Calls a mock API which returns the above array to simulate "get all". */
export async function findAll() {
// Throw an error, just for example.
if (!Array.isArray(dataArray)) {
throw new Error('Cannot find users')
import fetch from 'isomorphic-unfetch'

export async function sampleFetchWrapper(
input: RequestInfo,
init?: RequestInit
) {
try {
const data = await fetch(input, init).then(res => res.json())
return data
} catch (err) {
throw new Error(err.message)
}

return dataArray
}
9 changes: 9 additions & 0 deletions examples/with-typescript/utils/sample-data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { User } from '../interfaces'

/** Dummy user data. */
export const sampleUserData: User[] = [
{ id: 101, name: 'Alice' },
{ id: 102, name: 'Bob' },
{ id: 103, name: 'Caroline' },
{ id: 104, name: 'Dave' },
]
2 changes: 1 addition & 1 deletion lerna.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@
"registry": "https://registry.npmjs.org/"
}
},
"version": "9.1.2-canary.3"
"version": "9.1.2-canary.4"
}
2 changes: 1 addition & 1 deletion packages/create-next-app/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "create-next-app",
"version": "9.1.2-canary.3",
"version": "9.1.2-canary.4",
"keywords": [
"react",
"next",
Expand Down
2 changes: 1 addition & 1 deletion packages/next-bundle-analyzer/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@next/bundle-analyzer",
"version": "9.1.2-canary.3",
"version": "9.1.2-canary.4",
"main": "index.js",
"license": "MIT",
"repository": {
Expand Down
2 changes: 1 addition & 1 deletion packages/next-mdx/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@next/mdx",
"version": "9.1.2-canary.3",
"version": "9.1.2-canary.4",
"main": "index.js",
"license": "MIT",
"repository": {
Expand Down
6 changes: 3 additions & 3 deletions packages/next/build/webpack/loaders/next-serverless-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,13 +133,13 @@ const nextServerlessLoader: loader.Loader = function() {
: `const params = {};`
}
${
// Temporary work around -- `x-now-route-params` is a platform header
// Temporary work around: `x-now-route-matches` is a platform header
// _only_ set for `Prerender` requests. We should move this logic
// into our builder to ensure we're decoupled. However, this entails
// removing reliance on `req.url` and using `req.query` instead
// (which is needed for "custom routes" anyway).
isDynamicRoute(page)
? `const nowParams = req.headers && req.headers["x-now-route-params"]
? `const nowParams = req.headers && req.headers["x-now-route-matches"]
? getRouteMatcher(
(function() {
const { re, groups } = getRouteRegex("${page}");
Expand All @@ -160,7 +160,7 @@ const nextServerlessLoader: loader.Loader = function() {
groups
};
})()
)(req.headers["x-now-route-params"])
)(req.headers["x-now-route-matches"])
: null;
`
: `const nowParams = null;`
Expand Down
2 changes: 1 addition & 1 deletion packages/next/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "next",
"version": "9.1.2-canary.3",
"version": "9.1.2-canary.4",
"description": "The React Framework",
"main": "./dist/server/next.js",
"license": "MIT",
Expand Down
2 changes: 1 addition & 1 deletion test/integration/serverless/test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ describe('Serverless', () => {
it('should have the correct query string for a spr route', async () => {
const paramRaw = 'test % 123'
const html = await fetchViaHTTP(appPort, `/dr/[slug]`, '', {
headers: { 'x-now-route-params': qs.stringify({ 1: paramRaw }) }
headers: { 'x-now-route-matches': qs.stringify({ 1: paramRaw }) }
}).then(res => res.text())
const $ = cheerio.load(html)
const data = JSON.parse($('#__NEXT_DATA__').html())
Expand Down

0 comments on commit 0b5a513

Please sign in to comment.