Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 39f5ae1

Browse files
piehmrstork
andauthored
feat: support dotenv files (#429)
* test: add e2e tests for checking access to env vars defined in dot env files * fix: support dotenv files in generated handler function --------- Co-authored-by: Mateusz Bocian <mrstork@users.noreply.github.com>
1 parent 9620588 commit 39f5ae1

File tree

20 files changed

+115
-27
lines changed

20 files changed

+115
-27
lines changed

‎src/build/functions/server.ts‎

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,30 +20,38 @@ const tracer = wrapTracer(trace.getTracer('Next runtime'))
2020
const copyHandlerDependencies = async (ctx: PluginContext) => {
2121
await tracer.withActiveSpan('copyHandlerDependencies', async (span) => {
2222
const promises: Promise<void>[] = []
23-
const { included_files: includedFiles = [] } = ctx.netlifyConfig.functions?.['*'] || {}
2423
// if the user specified some files to include in the lambda
2524
// we need to copy them to the functions-internal folder
25+
const { included_files: includedFiles = [] } = ctx.netlifyConfig.functions?.['*'] || {}
26+
27+
// we also force including the .env files to ensure those are available in the lambda
28+
includedFiles.push(
29+
posixJoin(ctx.relativeAppDir, '.env'),
30+
posixJoin(ctx.relativeAppDir, '.env.production'),
31+
posixJoin(ctx.relativeAppDir, '.env.local'),
32+
posixJoin(ctx.relativeAppDir, '.env.production.local'),
33+
)
34+
2635
span.setAttribute('next.includedFiles', includedFiles.join(','))
27-
if (includedFiles.length !== 0) {
28-
const resolvedFiles = await Promise.all(
29-
includedFiles.map((globPattern) => glob(globPattern, { cwd: process.cwd() })),
36+
37+
const resolvedFiles = await Promise.all(
38+
includedFiles.map((globPattern) => glob(globPattern, { cwd: process.cwd() })),
39+
)
40+
for (const filePath of resolvedFiles.flat()) {
41+
promises.push(
42+
cp(
43+
join(process.cwd(), filePath),
44+
// the serverHandlerDir is aware of the dist dir.
45+
// The distDir must not be the package path therefore we need to rely on the
46+
// serverHandlerDir instead of the serverHandlerRootDir
47+
// therefore we need to remove the package path from the filePath
48+
join(ctx.serverHandlerDir, relative(ctx.relativeAppDir, filePath)),
49+
{
50+
recursive: true,
51+
force: true,
52+
},
53+
),
3054
)
31-
for (const filePath of resolvedFiles.flat()) {
32-
promises.push(
33-
cp(
34-
join(process.cwd(), filePath),
35-
// the serverHandlerDir is aware of the dist dir.
36-
// The distDir must not be the package path therefore we need to rely on the
37-
// serverHandlerDir instead of the serverHandlerRootDir
38-
// therefore we need to remove the package path from the filePath
39-
join(ctx.serverHandlerDir, relative(ctx.relativeAppDir, filePath)),
40-
{
41-
recursive: true,
42-
force: true,
43-
},
44-
),
45-
)
46-
}
4755
}
4856

4957
const fileList = await glob('dist/**/*', { cwd: ctx.pluginDir })

‎tests/e2e/nx-integrated.test.ts‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,16 @@ test('Renders the Home page correctly with distDir', async ({ page, nxIntegrated
2929

3030
await expectImageWasLoaded(page.locator('img'))
3131
})
32+
33+
test('environment variables from .env files should be available for functions', async ({
34+
nxIntegratedDistDir,
35+
}) => {
36+
const response = await fetch(`${nxIntegratedDistDir.url}/api/env`)
37+
const data = await response.json()
38+
expect(data).toEqual({
39+
'.env': 'defined in .env',
40+
'.env.local': 'defined in .env.local',
41+
'.env.production': 'defined in .env.production',
42+
'.env.production.local': 'defined in .env.production.local',
43+
})
44+
})

‎tests/e2e/page-router.test.ts‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,19 @@ test.describe('Simple Page Router (no basePath, no i18n)', () => {
379379
expect(headers['netlify-cdn-cache-control']).toBe('max-age=31536000')
380380
expect(headers['cache-control']).toBe('public,max-age=0,must-revalidate')
381381
})
382+
383+
test('environment variables from .env files should be available for functions', async ({
384+
pageRouter,
385+
}) => {
386+
const response = await fetch(`${pageRouter.url}/api/env`)
387+
const data = await response.json()
388+
expect(data).toEqual({
389+
'.env': 'defined in .env',
390+
'.env.local': 'defined in .env.local',
391+
'.env.production': 'defined in .env.production',
392+
'.env.production.local': 'defined in .env.production.local',
393+
})
394+
})
382395
})
383396

384397
test.describe('Page Router with basePath and i18n', () => {

‎tests/e2e/turborepo.test.ts‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,4 +206,17 @@ test.describe('[NPM] Package manager', () => {
206206
const date3 = await page.textContent('[data-testid="date-now"]')
207207
expect(date3).not.toBe(date2)
208208
})
209+
210+
test('environment variables from .env files should be available for functions', async ({
211+
turborepoNPM,
212+
}) => {
213+
const response = await fetch(`${turborepoNPM.url}/api/env`)
214+
const data = await response.json()
215+
expect(data).toEqual({
216+
'.env': 'defined in .env',
217+
'.env.local': 'defined in .env.local',
218+
'.env.production': 'defined in .env.production',
219+
'.env.production.local': 'defined in .env.production.local',
220+
})
221+
})
209222
})
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
FROM_DOT_ENV="defined in .env"
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
FROM_DOT_ENV_DOT_LOCAL="defined in .env.local"
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
FROM_DOT_ENV_DOT_PRODUCTION="defined in .env.production"
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
FROM_DOT_ENV_DOT_PRODUCTION_DOT_LOCAL="defined in .env.production.local"
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { NextResponse } from 'next/server'
2+
3+
export async function GET() {
4+
return NextResponse.json({
5+
'.env': process.env.FROM_DOT_ENV ?? 'undefined',
6+
'.env.local': process.env.FROM_DOT_ENV_DOT_LOCAL ?? 'undefined',
7+
'.env.production': process.env.FROM_DOT_ENV_DOT_PRODUCTION ?? 'undefined',
8+
'.env.production.local': process.env.FROM_DOT_ENV_DOT_PRODUCTION_DOT_LOCAL ?? 'undefined',
9+
})
10+
}
11+
12+
export const dynamic = 'force-dynamic'

‎tests/fixtures/page-router/.env‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
FROM_DOT_ENV="defined in .env"

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /