Skip to content

Commit

Permalink
chore: expose globalThis.crypto when not available (#48941)
Browse files Browse the repository at this point in the history
### What?

Exposing `globalThis.crypto`, based on [Node.js' WebCrypto
API](https://nodejs.org/api/globals.html#crypto_1)

### Why?

Similar to `fetch`, `crypto` is a popular API that is currently not
available on `globalThis` in all active Node.js versions yet.

This can help library authors to create runtime-agnostic packages.

### How?

Node.js already has the WebCrypto API that can be imported, we just
expose it on `globalThis` in Node.js versions where this is not
available.

Closes NEXT-1063

[Slack
thread](https://vercel.slack.com/archives/C03KAR5DCKC/p1681821510191059)
  • Loading branch information
balazsorban44 authored Apr 28, 2023
1 parent 0918ebd commit 88a033f
Show file tree
Hide file tree
Showing 11 changed files with 74 additions and 2 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@
"@types/react-dom": "18.0.11"
},
"engines": {
"node": ">=16"
"node": ">=16.8.0"
},
"packageManager": "[email protected]"
}
2 changes: 1 addition & 1 deletion packages/next/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,6 @@
"caniuse-lite": "1.0.30001406"
},
"engines": {
"node": ">=16"
"node": ">=16.8.0"
}
}
1 change: 1 addition & 0 deletions packages/next/src/build/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import type { StaticGenerationAsyncStorage } from '../client/components/static-g

import '../server/require-hook'
import '../server/node-polyfill-fetch'
import '../server/node-polyfill-crypto'
import chalk from 'next/dist/compiled/chalk'
import getGzipSize from 'next/dist/compiled/gzip-size'
import textTable from 'next/dist/compiled/text-table'
Expand Down
1 change: 1 addition & 0 deletions packages/next/src/server/next-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import './require-hook'
import './node-polyfill-fetch'
import './node-polyfill-form'
import './node-polyfill-web-streams'
import './node-polyfill-crypto'

import type { TLSSocket } from 'tls'
import type { Route, RouterOptions } from './router'
Expand Down
1 change: 1 addition & 0 deletions packages/next/src/server/next.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type { NextConfigComplete } from './config-shared'

import './require-hook'
import './node-polyfill-fetch'
import './node-polyfill-crypto'
import { default as Server } from './next-server'
import * as log from '../build/output/log'
import loadConfig from './config'
Expand Down
12 changes: 12 additions & 0 deletions packages/next/src/server/node-polyfill-crypto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// Polyfill crypto() in the Node.js environment

if (!(global as any).crypto) {
function getCryptoImpl() {
return require('node:crypto').webcrypto
}
Object.defineProperty(global, 'crypto', {
get() {
return getCryptoImpl()
},
})
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export function GET() {
return new Response(
typeof globalThis.crypto === 'object'
? 'crypto is available'
: 'crypto is not available'
)
}

export const runtime = 'nodejs'
7 changes: 7 additions & 0 deletions test/e2e/app-dir/crypto-globally-available/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default function Root({ children }: { children: React.ReactNode }) {
return (
<html>
<body>{children}</body>
</html>
)
}
11 changes: 11 additions & 0 deletions test/e2e/app-dir/crypto-globally-available/app/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export default function Page() {
return (
<p>
{typeof globalThis.crypto === 'object'
? 'crypto is available'
: 'crypto is not available'}
</p>
)
}

export const runtime = 'nodejs'
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { createNextDescribe } from 'e2e-utils'

createNextDescribe(
'Web Crypto API is available globally',
{
files: __dirname,
},
({ next }) => {
// Recommended for tests that need a full browser
it('should be available in Server Components', async () => {
const browser = await next.browser('/')
expect(await browser.elementByCss('p').text()).toBe('crypto is available')
})

// In case you need to test the response object
it('should be available in Route Handlers', async () => {
const res = await next.fetch('/handler')
const html = await res.text()
expect(html).toContain('crypto is available')
})
}
)
8 changes: 8 additions & 0 deletions test/e2e/app-dir/crypto-globally-available/next.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/**
* @type {import('next').NextConfig}
*/
const nextConfig = {
experimental: { appDir: true },
}

module.exports = nextConfig

0 comments on commit 88a033f

Please sign in to comment.