Skip to content

Commit

Permalink
Remove static analysis of process.env (#50260)
Browse files Browse the repository at this point in the history
Since there is no longer a limitation that requires us to static analyze
`process.env`, this PR removes it from the build process and updates the
corresponding documentation.
  • Loading branch information
javivelasco authored May 24, 2023
1 parent f1df0d0 commit aa91de5
Show file tree
Hide file tree
Showing 15 changed files with 6 additions and 208 deletions.
9 changes: 0 additions & 9 deletions docs/api-reference/edge-runtime.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,15 +130,6 @@ The Edge Runtime supports the following web standard APIs:

You can use `process.env` to access [Environment Variables](/docs/basic-features/environment-variables.md) for both `next dev` and `next build`.

Running `console.log` on `process.env` **will not** show all your Environment Variables. You have to access the variables directly as shown below:

```javascript
console.log(process.env)
// { NEXT_RUNTIME: 'edge' }
console.log(process.env.TEST_VARIABLE)
// value
```

## Compatible Node.js Modules

The following modules can be imported with and without the `node:` prefix when using the `import` statement:
Expand Down
4 changes: 0 additions & 4 deletions docs/basic-features/environment-variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,6 @@ export async function getStaticProps() {
}
```

> **Note**: In order to keep server-only secrets safe, environment variables are evaluated at build time, so only environment variables _actually_ used will be included. This means that `process.env` is not a standard JavaScript object, so you’re not able to
> use [object destructuring](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment).
> Environment variables must be referenced as e.g. `process.env.PUBLISHABLE_KEY`, _not_ `const { PUBLISHABLE_KEY } = process.env`.
> **Note**: Next.js will automatically expand variables (`$VAR`) inside of your `.env*` files.
> This allows you to reference other secrets, like so:
>
Expand Down
1 change: 0 additions & 1 deletion packages/next/src/build/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1389,7 +1389,6 @@ export async function isPageStatic({
if (pathIsEdgeRuntime) {
const runtime = await getRuntimeContext({
paths: edgeInfo.files.map((file: string) => path.join(distDir, file)),
env: edgeInfo.env,
edgeFunctionEntry: {
...edgeInfo,
wasm: (edgeInfo.wasm ?? []).map((binding: AssetBinding) => ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ export function getModuleBuildInfo(webpackModule: webpack.Module) {
nextEdgeMiddleware?: EdgeMiddlewareMeta
nextEdgeApiFunction?: EdgeMiddlewareMeta
nextEdgeSSR?: EdgeSSRMeta
nextUsedEnvVars?: Set<string>
nextWasmMiddlewareBinding?: AssetBinding
nextAssetMiddlewareBinding?: AssetBinding
usingIndirectEval?: boolean | Set<string>
Expand Down
83 changes: 0 additions & 83 deletions packages/next/src/build/webpack/plugins/middleware-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ import { INSTRUMENTATION_HOOK_FILENAME } from '../../../lib/constants'
import { NextBuildContext } from '../../build-context'

export interface EdgeFunctionDefinition {
env: string[]
files: string[]
name: string
page: string
Expand All @@ -55,7 +54,6 @@ interface EntryMetadata {
edgeMiddleware?: EdgeMiddlewareMeta
edgeApiFunction?: EdgeMiddlewareMeta
edgeSSR?: EdgeSSRMeta
env: Set<string>
wasmBindings: Map<string, string>
assetBindings: Map<string, string>
regions?: string[] | string
Expand Down Expand Up @@ -188,7 +186,6 @@ function getCreateAssets(params: {
]

const edgeFunctionDefinition: EdgeFunctionDefinition = {
env: Array.from(metadata.env),
files: getEntryFiles(entrypoint.getFiles(), metadata, opts),
name: entrypoint.name,
page: page,
Expand Down Expand Up @@ -248,17 +245,6 @@ function isInMiddlewareLayer(parser: webpack.javascript.JavascriptParser) {
return parser.state.module?.layer === 'middleware'
}

function isProcessEnvMemberExpression(memberExpression: any): boolean {
return (
memberExpression.object?.type === 'Identifier' &&
memberExpression.object.name === 'process' &&
((memberExpression.property?.type === 'Literal' &&
memberExpression.property.value === 'env') ||
(memberExpression.property?.type === 'Identifier' &&
memberExpression.property.name === 'env'))
)
}

function isNodeJsModule(moduleName: string) {
return require('module').builtinModules.includes(moduleName)
}
Expand Down Expand Up @@ -461,32 +447,6 @@ function getCodeAnalyzer(params: {
}
}

/**
* Declares an environment variable that is being used in this module
* through this static analysis.
*/
const addUsedEnvVar = (envVarName: string) => {
const buildInfo = getModuleBuildInfo(parser.state.module)
if (buildInfo.nextUsedEnvVars === undefined) {
buildInfo.nextUsedEnvVars = new Set()
}

buildInfo.nextUsedEnvVars.add(envVarName)
}

/**
* A handler for calls to `process.env` where we identify the name of the
* ENV variable being assigned and store it in the module info.
*/
const handleCallMemberChain = (_: unknown, members: string[]) => {
if (members.length >= 2 && members[0] === 'env') {
addUsedEnvVar(members[1])
if (!isInMiddlewareLayer(parser)) {
return true
}
}
}

/**
* Handler to store original source location of static and dynamic imports into module's buildInfo.
*/
Expand Down Expand Up @@ -541,41 +501,9 @@ Learn More: https://nextjs.org/docs/messages/node-module-in-edge-runtime`,
.tap(NAME, handleWrapWasmInstantiateExpression)
}

hooks.callMemberChain.for('process').tap(NAME, handleCallMemberChain)
hooks.expressionMemberChain.for('process').tap(NAME, handleCallMemberChain)
hooks.importCall.tap(NAME, handleImport)
hooks.import.tap(NAME, handleImport)

/**
* Support static analyzing environment variables through
* destructuring `process.env` or `process["env"]`:
*
* const { MY_ENV, "MY-ENV": myEnv } = process.env
* ^^^^^^ ^^^^^^
*/
hooks.declarator.tap(NAME, (declarator) => {
if (
declarator.init?.type === 'MemberExpression' &&
isProcessEnvMemberExpression(declarator.init) &&
declarator.id?.type === 'ObjectPattern'
) {
for (const property of declarator.id.properties) {
if (property.type === 'RestElement') continue
if (
property.key.type === 'Literal' &&
typeof property.key.value === 'string'
) {
addUsedEnvVar(property.key.value)
} else if (property.key.type === 'Identifier') {
addUsedEnvVar(property.key.name)
}
}

if (!isInMiddlewareLayer(parser)) {
return true
}
}
})
if (!dev) {
// do not issue compilation warning on dev: invoking code will provide details
registerUnsupportedApiHooks(parser, compilation)
Expand Down Expand Up @@ -653,7 +581,6 @@ function getExtractMetadata(params: {
entry.includeDependencies.forEach(addEntriesFromDependency)

const entryMetadata: EntryMetadata = {
env: new Set<string>(),
wasmBindings: new Map(),
assetBindings: new Map(),
}
Expand Down Expand Up @@ -760,16 +687,6 @@ function getExtractMetadata(params: {
entryMetadata.edgeApiFunction = buildInfo.nextEdgeApiFunction
}

/**
* If there are env vars found in the module, append them to the set
* of env vars for the entry.
*/
if (buildInfo?.nextUsedEnvVars !== undefined) {
for (const envName of buildInfo.nextUsedEnvVars) {
entryMetadata.env.add(envName)
}
}

/**
* If the module is a WASM module we read the binding information and
* append it to the entry wasm bindings.
Expand Down
1 change: 0 additions & 1 deletion packages/next/src/server/lib/route-resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,6 @@ export async function makeResolver(
return {
name: 'middleware',
paths: middleware.files.map((file) => join(process.cwd(), file)),
env: Object.keys(process.env),
wasm: [],
assets: [],
}
Expand Down
4 changes: 0 additions & 4 deletions packages/next/src/server/next-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2183,7 +2183,6 @@ export default class NextNodeServer extends BaseServer {
}): {
name: string
paths: string[]
env: string[]
wasm: { filePath: string; name: string }[]
assets: { filePath: string; name: string }[]
} | null {
Expand Down Expand Up @@ -2214,7 +2213,6 @@ export default class NextNodeServer extends BaseServer {
return {
name: pageInfo.name,
paths: pageInfo.files.map((file) => join(this.distDir, file)),
env: pageInfo.env ?? [],
wasm: (pageInfo.wasm ?? []).map((binding) => ({
...binding,
filePath: join(this.distDir, binding.filePath),
Expand Down Expand Up @@ -2322,7 +2320,6 @@ export default class NextNodeServer extends BaseServer {
distDir: this.distDir,
name: middlewareInfo.name,
paths: middlewareInfo.paths,
env: middlewareInfo.env,
edgeFunctionEntry: middlewareInfo,
request: {
headers: params.request.headers,
Expand Down Expand Up @@ -2825,7 +2822,6 @@ export default class NextNodeServer extends BaseServer {
distDir: this.distDir,
name: edgeInfo.name,
paths: edgeInfo.paths,
env: edgeInfo.env,
edgeFunctionEntry: edgeInfo,
request: {
headers: params.req.headers,
Expand Down
15 changes: 5 additions & 10 deletions packages/next/src/server/web/sandbox/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,8 @@ async function loadWasm(
return modules
}

function buildEnvironmentVariablesFrom(
keys: string[]
): Record<string, string | undefined> {
const pairs = keys.map((key) => [key, process.env[key]])
function buildEnvironmentVariablesFrom(): Record<string, string | undefined> {
const pairs = Object.keys(process.env).map((key) => [key, process.env[key]])
const env = Object.fromEntries(pairs)
env.NEXT_RUNTIME = 'edge'
return env
Expand All @@ -108,10 +106,8 @@ Learn more: https://nextjs.org/docs/api-reference/edge-runtime`)
throw error
}

function createProcessPolyfill(options: Pick<ModuleContextOptions, 'env'>) {
const env = buildEnvironmentVariablesFrom(options.env)

const processPolyfill = { env }
function createProcessPolyfill() {
const processPolyfill = { env: buildEnvironmentVariablesFrom() }
const overridenValue: Record<string, any> = {}
for (const key of Object.keys(process)) {
if (key === 'env') continue
Expand Down Expand Up @@ -236,7 +232,7 @@ async function createModuleContext(options: ModuleContextOptions) {
: undefined,
extend: (context) => {
context.WebSocket = require('next/dist/compiled/ws').WebSocket
context.process = createProcessPolyfill(options)
context.process = createProcessPolyfill()

Object.defineProperty(context, 'require', {
enumerable: false,
Expand Down Expand Up @@ -416,7 +412,6 @@ interface ModuleContextOptions {
moduleName: string
onWarning: (warn: Error) => void
useCache: boolean
env: string[]
distDir: string
edgeFunctionEntry: Pick<EdgeFunctionDefinition, 'assets' | 'wasm'>
}
Expand Down
3 changes: 0 additions & 3 deletions packages/next/src/server/web/sandbox/sandbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ const FORBIDDEN_HEADERS = [

type RunnerFn = (params: {
name: string
env: string[]
onWarning?: (warn: Error) => void
paths: string[]
request: NodejsRequestData
Expand Down Expand Up @@ -49,7 +48,6 @@ export const getRuntimeContext = async (params: {
name: string
onWarning?: any
useCache: boolean
env: string[]
edgeFunctionEntry: any
distDir: string
paths: string[]
Expand All @@ -59,7 +57,6 @@ export const getRuntimeContext = async (params: {
moduleName: params.name,
onWarning: params.onWarning ?? (() => {}),
useCache: params.useCache !== false,
env: params.env,
edgeFunctionEntry: params.edgeFunctionEntry,
distDir: params.distDir,
})
Expand Down
16 changes: 0 additions & 16 deletions test/e2e/middleware-general/app/middleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,22 +116,6 @@ export async function middleware(request) {
}

if (url.pathname === '/global') {
// The next line is required to allow to find the env variable
// eslint-disable-next-line no-unused-expressions
process.env.MIDDLEWARE_TEST

// The next line is required to allow to find the env variable
// eslint-disable-next-line no-unused-expressions
const { ANOTHER_MIDDLEWARE_TEST } = process.env
if (!ANOTHER_MIDDLEWARE_TEST) {
console.log('missing ANOTHER_MIDDLEWARE_TEST')
}

const { STRING_ENV_VAR: stringEnvVar } = process['env']
if (!stringEnvVar) {
console.log('missing STRING_ENV_VAR')
}

return serializeData(JSON.stringify({ process: { env: process.env } }))
}

Expand Down
7 changes: 1 addition & 6 deletions test/e2e/middleware-general/test/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -138,11 +138,6 @@ describe('Middleware Runtime', () => {
)
expect(manifest.middleware).toEqual({
'/': {
env: expect.arrayContaining([
'MIDDLEWARE_TEST',
'ANOTHER_MIDDLEWARE_TEST',
'STRING_ENV_VAR',
]),
files: expect.arrayContaining([
'server/edge-runtime-webpack.js',
'server/middleware.js',
Expand Down Expand Up @@ -481,7 +476,7 @@ describe('Middleware Runtime', () => {
})
}

it('should contain process polyfill', async () => {
it('allows to access env variables', async () => {
const res = await fetchViaHTTP(next.url, `/global`)
const json = readMiddlewareJSON(res)

Expand Down
1 change: 0 additions & 1 deletion test/e2e/middleware-trailing-slash/test/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,6 @@ describe('Middleware Runtime trailing slash', () => {
'/': {
files: ['server/edge-runtime-webpack.js', 'server/middleware.js'],
name: 'middleware',
env: expect.arrayContaining([]),
page: '/',
matchers: [{ regexp: '^/.*$', originalSource: '/:path*' }],
wasm: [],
Expand Down
4 changes: 0 additions & 4 deletions test/e2e/switchable-runtime/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,6 @@ describe('Switchable runtime', () => {
expect(manifest).toMatchObject({
functions: {
'/api/hello': {
env: expect.arrayContaining([]),
files: [
'server/edge-runtime-webpack.js',
'server/pages/api/hello.js',
Expand All @@ -200,7 +199,6 @@ describe('Switchable runtime', () => {
wasm: [],
},
'/api/edge': {
env: expect.arrayContaining([]),
files: [
'server/edge-runtime-webpack.js',
'server/pages/api/edge.js',
Expand Down Expand Up @@ -623,7 +621,6 @@ describe('Switchable runtime', () => {
expect(manifest).toMatchObject({
functions: {
'/api/hello': {
env: expect.arrayContaining([]),
files: [
'server/edge-runtime-webpack.js',
'server/pages/api/hello.js',
Expand All @@ -636,7 +633,6 @@ describe('Switchable runtime', () => {
wasm: [],
},
'/api/edge': {
env: expect.arrayContaining([]),
files: [
'server/edge-runtime-webpack.js',
'server/pages/api/edge.js',
Expand Down
Loading

0 comments on commit aa91de5

Please sign in to comment.