Skip to content

Commit

Permalink
Allow dependencies to use environment variables in middlewares (#33141)
Browse files Browse the repository at this point in the history
After discussing with @sokra, seems that the proposed solution is split in two:

* We need to make sure that the `process` polyfill uses `global.process` if available. This is because middlewares are bundled using `browser` target and therefore `process.env.MY_ENV` gets shimmed into `require('process').env.MY_ENV`.

* Allow `process.env` to be statically analyzed for dependencies so they will be exported to the manifest.

Related issues:

* should fix #33043.
  • Loading branch information
Schniz committed Jan 10, 2022
1 parent f0ad19a commit 4aa9879
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 4 deletions.
1 change: 1 addition & 0 deletions packages/next/build/polyfills/process.js
@@ -0,0 +1 @@
module.exports = global.process || require('../../compiled/process')
2 changes: 1 addition & 1 deletion packages/next/build/webpack-config.ts
Expand Up @@ -635,7 +635,7 @@ export default async function getBaseWebpackConfig(
os: require.resolve('next/dist/compiled/os-browserify'),
path: require.resolve('next/dist/compiled/path-browserify'),
punycode: require.resolve('next/dist/compiled/punycode'),
process: require.resolve('next/dist/compiled/process'),
process: require.resolve('./polyfills/process'),
// Handled in separate alias
querystring: require.resolve('next/dist/compiled/querystring-es3'),
// TODO: investigate ncc'ing stream-browserify
Expand Down
4 changes: 1 addition & 3 deletions packages/next/build/webpack/plugins/middleware-plugin.ts
Expand Up @@ -295,8 +295,6 @@ export default class MiddlewarePlugin {
.tap(PLUGIN_NAME, ignore)

const memberChainHandler = (_expr: any, members: string[]) => {
if (!isMiddlewareModule()) return

if (members.length >= 2 && members[0] === 'env') {
const envName = members[1]
const { buildInfo } = parser.state.module
Expand All @@ -305,7 +303,7 @@ export default class MiddlewarePlugin {
}

buildInfo.nextUsedEnvVars.add(envName)
return true
if (isMiddlewareModule()) return true
}
}

Expand Down
@@ -0,0 +1,73 @@
import { createNext } from 'e2e-utils'
import { NextInstance } from 'test/lib/next-modes/base'
import { renderViaHTTP } from 'next-test-utils'
import { readJson } from 'fs-extra'
import path from 'path'

describe('dependencies can use env vars in middlewares', () => {
let next: NextInstance

beforeAll(() => {
process.env.MY_CUSTOM_PACKAGE_ENV_VAR = 'my-custom-package-env-var'
process.env.ENV_VAR_USED_IN_MIDDLEWARE = 'env-var-used-in-middleware'
})

beforeAll(async () => {
next = await createNext({
files: {
// A 3rd party dependency
'node_modules/my-custom-package/package.json': JSON.stringify({
name: 'my-custom-package',
version: '1.0.0',
browser: 'index.js',
}),
'node_modules/my-custom-package/index.js': `
module.exports = () => process.env.MY_CUSTOM_PACKAGE_ENV_VAR;
`,

// The actual middleware code
'pages/api/_middleware.js': `
import customPackage from 'my-custom-package';
export default function middleware(_req) {
return new Response(JSON.stringify({
string: "a constant string",
hello: process.env.ENV_VAR_USED_IN_MIDDLEWARE,
customPackage: customPackage(),
}), {
headers: {
'Content-Type': 'application/json'
}
})
}
`,
},
dependencies: {},
})
})
afterAll(() => next.destroy())

it('parses the env vars correctly', async () => {
const testDir = next.testDir
const manifestPath = path.join(
testDir,
'.next/server/middleware-manifest.json'
)
const manifest = await readJson(manifestPath)
const envVars = manifest?.middleware?.['/api']?.env

expect(envVars).toHaveLength(2)
expect(envVars).toContain('ENV_VAR_USED_IN_MIDDLEWARE')
expect(envVars).toContain('MY_CUSTOM_PACKAGE_ENV_VAR')
})

it('uses the environment variables', async () => {
const html = await renderViaHTTP(next.url, '/api')
expect(html).toContain(
JSON.stringify({
string: 'a constant string',
hello: 'env-var-used-in-middleware',
customPackage: 'my-custom-package-env-var',
})
)
})
})

0 comments on commit 4aa9879

Please sign in to comment.