From b23525400ebdc669eb0064a51aaf380222f217f4 Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Wed, 16 Feb 2022 11:15:26 +0100 Subject: [PATCH 1/2] Add failing test for next/link next/image with "type": "module" --- test/e2e/type-module-interop/index.test.ts | 28 ++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/test/e2e/type-module-interop/index.test.ts b/test/e2e/type-module-interop/index.test.ts index 21e13a32586bf9e..918ceaef1151483 100644 --- a/test/e2e/type-module-interop/index.test.ts +++ b/test/e2e/type-module-interop/index.test.ts @@ -2,6 +2,7 @@ import { createNext } from 'e2e-utils' import { NextInstance } from 'test/lib/next-modes/base' import { hasRedbox, renderViaHTTP } from 'next-test-utils' import webdriver from 'next-webdriver' +import cheerio from 'cheerio' describe('Type module interop', () => { let next: NextInstance @@ -14,6 +15,21 @@ describe('Type module interop', () => { return

hello world

} `, + 'pages/modules.jsx': ` + import Link from 'next/link' + import Image from 'next/image' + + export default function Modules() { + return ( + <> + + link to home + + + + ) + } + `, }, dependencies: {}, }) @@ -39,4 +55,16 @@ describe('Type module interop', () => { expect(await hasRedbox(browser)).toBe(false) await browser.close() }) + + it('should render server-side with modules', async () => { + const html = await renderViaHTTP(next.url, '/modules') + const $ = cheerio.load(html) + expect($('#link-to-home').text()).toBe('link to home') + }) + + it('should render client-side with modules', async () => { + const browser = await webdriver(next.url, '/modules') + expect(await hasRedbox(browser)).toBe(false) + await browser.close() + }) }) From ac62c756964a7af68c5d28935604825092e0254d Mon Sep 17 00:00:00 2001 From: LongYinan Date: Wed, 6 Apr 2022 19:01:41 +0800 Subject: [PATCH 2/2] Interpolate default exports --- examples/hello-world-esm/.gitignore | 34 +++++++++++++++++++++ examples/hello-world-esm/README.md | 23 ++++++++++++++ examples/hello-world-esm/package.json | 14 +++++++++ examples/hello-world-esm/pages/about.js | 3 ++ examples/hello-world-esm/pages/day/index.js | 3 ++ examples/hello-world-esm/pages/index.js | 12 ++++++++ packages/next/taskfile-swc.js | 15 ++++++++- packages/next/taskfile.js | 2 +- 8 files changed, 104 insertions(+), 2 deletions(-) create mode 100644 examples/hello-world-esm/.gitignore create mode 100644 examples/hello-world-esm/README.md create mode 100644 examples/hello-world-esm/package.json create mode 100644 examples/hello-world-esm/pages/about.js create mode 100644 examples/hello-world-esm/pages/day/index.js create mode 100644 examples/hello-world-esm/pages/index.js diff --git a/examples/hello-world-esm/.gitignore b/examples/hello-world-esm/.gitignore new file mode 100644 index 000000000000000..1437c53f70bc211 --- /dev/null +++ b/examples/hello-world-esm/.gitignore @@ -0,0 +1,34 @@ +# 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 diff --git a/examples/hello-world-esm/README.md b/examples/hello-world-esm/README.md new file mode 100644 index 000000000000000..4a9755ba2230248 --- /dev/null +++ b/examples/hello-world-esm/README.md @@ -0,0 +1,23 @@ +# ESM Hello World example + +This example shows the most basic idea behind Next.js, and it's running on native [esm](https://nodejs.org/api/esm.html) mode. We have 2 pages: `pages/index.js` and `pages/about.js`. The former responds to `/` requests and the latter to `/about`. Using `next/link` you can add hyperlinks between them with universal routing capabilities. The `day` directory shows that you can have subdirectories. + +## Deploy your own + +Deploy the example using [Vercel](https://vercel.com?utm_source=github&utm_medium=readme&utm_campaign=next-example-esm) or preview live with [StackBlitz](https://stackblitz.com/github/vercel/next.js/tree/canary/examples/hello-world-esm) + +[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/git/external?repository-url=https://github.com/vercel/next.js/tree/canary/examples/hello-world-esm&project-name=hello-world-esm&repository-name=hello-world-esm) + +## 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 hello-world-esm hello-world-esm-app +# or +yarn create next-app --example hello-world-esm hello-world-esm-app +# or +pnpm create next-app -- --example hello-world-esm hello-world-esm-app +``` + +Deploy it to the cloud with [Vercel](https://vercel.com/new?utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)). diff --git a/examples/hello-world-esm/package.json b/examples/hello-world-esm/package.json new file mode 100644 index 000000000000000..4611e0b34c614ec --- /dev/null +++ b/examples/hello-world-esm/package.json @@ -0,0 +1,14 @@ +{ + "private": true, + "type": "module", + "scripts": { + "dev": "next", + "build": "next build", + "start": "next start" + }, + "dependencies": { + "next": "latest", + "react": "^18.0.0", + "react-dom": "^18.0.0" + } +} diff --git a/examples/hello-world-esm/pages/about.js b/examples/hello-world-esm/pages/about.js new file mode 100644 index 000000000000000..71c7703a7bd2acf --- /dev/null +++ b/examples/hello-world-esm/pages/about.js @@ -0,0 +1,3 @@ +export default function AboutPage() { + return
About us
+} diff --git a/examples/hello-world-esm/pages/day/index.js b/examples/hello-world-esm/pages/day/index.js new file mode 100644 index 000000000000000..bd2d2fed9524fef --- /dev/null +++ b/examples/hello-world-esm/pages/day/index.js @@ -0,0 +1,3 @@ +export default function DayPage() { + return
Hello Day
+} diff --git a/examples/hello-world-esm/pages/index.js b/examples/hello-world-esm/pages/index.js new file mode 100644 index 000000000000000..dd2c3af8cab8563 --- /dev/null +++ b/examples/hello-world-esm/pages/index.js @@ -0,0 +1,12 @@ +import Link from 'next/link' + +export default function IndexPage() { + return ( +
+ Hello World.{' '} + + About + +
+ ) +} diff --git a/packages/next/taskfile-swc.js b/packages/next/taskfile-swc.js index 38395cc19aefb04..c1e78d2496d88ad 100644 --- a/packages/next/taskfile-swc.js +++ b/packages/next/taskfile-swc.js @@ -14,7 +14,11 @@ module.exports = function (task) { function* ( file, serverOrClient, - { stripExtension, keepImportAssertions = false } = {} + { + stripExtension, + keepImportAssertions = false, + interopClientDefaultExport = false, + } = {} ) { // Don't compile .d.ts if (file.base.endsWith('.d.ts')) return @@ -113,6 +117,15 @@ module.exports = function (task) { if (output.map) { const map = `${file.base}.map` + if (interopClientDefaultExport) { + output.code += ` +if (typeof exports.default === 'function' || (typeof exports.default === 'object' && exports.default !== null)) { + Object.assign(exports.default, exports); + module.exports = exports.default; +} +` + } + output.code += Buffer.from(`\n//# sourceMappingURL=${map}`) // add sourcemap to `files` array diff --git a/packages/next/taskfile.js b/packages/next/taskfile.js index fc4a1ee697fa957..c9064ba074d39c9 100644 --- a/packages/next/taskfile.js +++ b/packages/next/taskfile.js @@ -1826,7 +1826,7 @@ export async function nextbuild(task, opts) { export async function client(task, opts) { await task .source(opts.src || 'client/**/*.+(js|ts|tsx)') - .swc('client', { dev: opts.dev }) + .swc('client', { dev: opts.dev, interopClientDefaultExport: true }) .target('dist/client') notify('Compiled client files') }