Skip to content

Commit

Permalink
Merge branch 'canary' into update/href-interpolation
Browse files Browse the repository at this point in the history
  • Loading branch information
ijjk committed Sep 7, 2020
2 parents 0631da6 + 489cad3 commit b24b45c
Show file tree
Hide file tree
Showing 22 changed files with 385 additions and 16 deletions.
36 changes: 34 additions & 2 deletions docs/advanced-features/dynamic-import.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,49 @@ description: Dynamically import JavaScript modules and React Components and spli

# Dynamic Import

<details>
<details open>
<summary><b>Examples</b></summary>
<ul>
<li><a href="https://github.com/vercel/next.js/tree/canary/examples/with-dynamic-import">Dynamic Import</a></li>
</ul>
</details>

Next.js supports ES2020 [dynamic `import()`](https://github.com/tc39/proposal-dynamic-import) for JavaScript. With it you can import JavaScript modules (inc. React Components) dynamically and work with them. They also work with SSR.
Next.js supports ES2020 [dynamic `import()`](https://github.com/tc39/proposal-dynamic-import) for JavaScript. With it you can import JavaScript modules dynamically and work with them. They also work with SSR.

In the following example, we implement fuzzy search using `fuse.js` and only load the module dynamically in the browser after the user types in the search input:

```jsx
import { useState } from 'react'

const names = ['Tim', 'Joe', 'Bel', 'Max', 'Lee']

export default function Page() {
const [results, setResults] = useState()

return (
<div>
<input
type="text"
placeholder="Search"
onChange={async (e) => {
const { value } = e.currentTarget
// Dynamically load fuse.js
const Fuse = (await import('fuse.js')).default
const fuse = new Fuse(names)

setResults(fuse.search(value))
}}
/>
<pre>Results: {JSON.stringify(results, null, 2)}</pre>
</div>
)
}
```

You can think of dynamic imports as another way to split your code into manageable chunks.

React components can also be imported using dynamic imports, but in this case we use it in conjunction with `next/dynamic` to make sure it works just like any other React Component. Check out the sections below for more details on how it works.

## Basic usage

In the following example, the module `../components/hello` will be dynamically loaded by the page:
Expand Down
2 changes: 1 addition & 1 deletion examples/auth0/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"author": "",
"license": "MIT",
"dependencies": {
"@auth0/nextjs-auth0": "^0.6.0",
"@auth0/nextjs-auth0": "^0.8.0",
"next": "latest",
"react": "^16.12.0",
"react-dom": "^16.12.0"
Expand Down
8 changes: 8 additions & 0 deletions examples/with-cssed/.babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"presets": [
"next/babel"
],
"plugins": [
"babel-plugin-macros"
]
}
37 changes: 37 additions & 0 deletions examples/with-cssed/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# local env files
.env.local
.env.development.local
.env.test.local
.env.production.local

# vercel
.vercel

# cssed compilation artifacts
.*.module.css
23 changes: 23 additions & 0 deletions examples/with-cssed/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Example app with cssed

This example shows how to use [cssed](https://github.com/okotoki/cssed), a CSS-in-JS library, with Next.js.

We are creating `div` element with local scoped styles. The styles includes the use of pseudo-selector.

## Deploy your own

Deploy the example using [Vercel](https://vercel.com):

[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/import/project?template=https://github.com/vercel/next.js/tree/canary/examples/with-cssed)

## How to use

Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init) or [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/) to bootstrap the example:

```bash
npx create-next-app --example with-cssed with-cssed-app
# or
yarn create next-app --example with-cssed with-cssed-app
```

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)).
2 changes: 2 additions & 0 deletions examples/with-cssed/lib/theme.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const dark = '#333'
export const light = '#ddd'
18 changes: 18 additions & 0 deletions examples/with-cssed/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "with-cssed",
"version": "1.0.0",
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start"
},
"dependencies": {
"@types/react": "^16.9.48",
"babel-plugin-macros": "^2.8.0",
"cssed": "^1.1.2",
"next": "latest",
"react": "^16.13.1",
"react-dom": "^16.13.1"
},
"license": "MIT"
}
47 changes: 47 additions & 0 deletions examples/with-cssed/pages/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { css } from 'cssed/macro'
import Head from 'next/head'
import { useState } from 'react'

import { dark, light } from '../lib/theme'

const styles = css`
.box {
height: 200px;
width: 200px;
margin: 0 auto;
margin-top: 40px;
display: flex;
align-items: center;
justify-content: center;
}
.dark {
background-color: ${dark};
}
.dark::before {
content: '🌚';
}
.light {
background-color: ${light};
}
.light::before {
content: '🌞';
}
`

export default function Home() {
const [isDark, setDark] = useState(false)
return (
<>
<Head>
<title>With cssed</title>
</Head>
<div
onClick={() => setDark(!isDark)}
className={styles.box + ' ' + (isDark ? styles.dark : styles.light)}
>
Cssed demo
</div>
</>
)
}
2 changes: 1 addition & 1 deletion examples/with-dynamic-import/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
"start": "next start"
},
"dependencies": {
"fuse.js": "6.4.1",
"next": "latest",
"react": "^16.13.1",
"react-dom": "^16.13.1"
},
"author": "",
"license": "MIT"
}
20 changes: 20 additions & 0 deletions examples/with-dynamic-import/pages/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,12 @@ const DynamicComponent4 = dynamic(() => import('../components/hello4'))

const DynamicComponent5 = dynamic(() => import('../components/hello5'))

const names = ['Tim', 'Joe', 'Bel', 'Max', 'Lee']

const IndexPage = () => {
const [showMore, setShowMore] = useState(false)
const [falsyField] = useState(false)
const [results, setResults] = useState()

return (
<div>
Expand All @@ -41,6 +44,23 @@ const IndexPage = () => {
{/* Load on demand */}
{showMore && <DynamicComponent5 />}
<button onClick={() => setShowMore(!showMore)}>Toggle Show More</button>

{/* Load library on demand */}
<div style={{ marginTop: '1rem' }}>
<input
type="text"
placeholder="Search"
onChange={async (e) => {
const { value } = e.currentTarget
// Dynamically load fuse.js
const Fuse = (await import('fuse.js')).default
const fuse = new Fuse(names)

setResults(fuse.search(value))
}}
/>
<pre>Results: {JSON.stringify(results, null, 2)}</pre>
</div>
</div>
)
}
Expand Down
12 changes: 1 addition & 11 deletions examples/with-http2/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,9 @@ const server = http2.createSecureServer({

app.prepare().then(() => {
server.on('error', (err) => console.error(err))

// Process the various routes based on `req`
// `/` -> Render index.js
// `/about` -> Render about.js
server.on('request', (req, res) => {
switch (req.url) {
case '/about':
return app.render(req, res, '/about', req.query)
default:
return app.render(req, res, '/', req.query)
}
app.render(req, res, req.url || '/', req.query)
})

server.listen(port)

console.log(`Listening on HTTPS port ${port}`)
Expand Down
4 changes: 3 additions & 1 deletion packages/next/next-server/lib/router/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -951,7 +951,9 @@ export default class Router implements BaseRouter {

_resolveHref(parsedHref: UrlObject, pages: string[]) {
const { pathname } = parsedHref
const cleanPathname = denormalizePagePath(delBasePath(pathname!))
const cleanPathname = removePathTrailingSlash(
denormalizePagePath(delBasePath(pathname!))
)

if (cleanPathname === '/404' || cleanPathname === '/_error') {
return parsedHref
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
trailingSlash: true,
}
3 changes: 3 additions & 0 deletions test/integration/trailing-slashes-href-resolving/pages/404.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function NotFound() {
return <div id="page-404">404</div>
}
11 changes: 11 additions & 0 deletions test/integration/trailing-slashes-href-resolving/pages/[slug].js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { useRouter } from 'next/router'

export default function Page() {
const router = useRouter()

return (
<>
<p id="slug">top level slug {router.query.slug}</p>
</>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default function Page() {
return (
<>
<p id="another">top level another</p>
</>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { useRouter } from 'next/router'

export default function Page() {
const router = useRouter()

return (
<>
<p id="slug">blog slug {router.query.slug}</p>
</>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default function Page() {
return (
<>
<p id="another">blog another</p>
</>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { useRouter } from 'next/router'

export default function Page() {
const router = useRouter()

return (
<>
<p id="slug">catch-all slug {router.query.slug?.join('/')}</p>
</>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default function Page() {
return (
<>
<p id="first">catch-all first</p>
</>
)
}
32 changes: 32 additions & 0 deletions test/integration/trailing-slashes-href-resolving/pages/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import Link from 'next/link'

export default function Index() {
return (
<>
<Link href="/blog/another/">
<a id="to-blog-another">to /blog/another/</a>
</Link>
<br />
<Link href="/blog/first-post/">
<a id="to-blog-post">to /blog/first-post/</a>
</Link>
<br />
<Link href="/catch-all/hello/world/">
<a id="to-catch-all-item">to /catch-all/hello/world/</a>
</Link>
<br />
<Link href="/catch-all/first/">
<a id="to-catch-all-first">to /catch-all/first/</a>
</Link>
<br />
<Link href="/another/">
<a id="to-another">to /another/</a>
</Link>
<br />
<Link href="/top-level-slug/">
<a id="to-slug">to /top-level-slug/</a>
</Link>
<br />
</>
)
}

0 comments on commit b24b45c

Please sign in to comment.