Skip to content

Commit e41f145

Browse files
n1ru4lardatan
authored andcommitted
add example
update lockfile chore: add vercel edge end2end test lockfile run e2e test adjustments fix lockfile pls work adjust example might this work? small documentation improvements try use cli
1 parent a4b82fa commit e41f145

29 files changed

+2706
-120
lines changed

.github/workflows/deployment-e2e.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ jobs:
1616
'azure-function',
1717
'aws-lambda',
1818
'vercel-function',
19+
'vercel-edge',
1920
]
2021
name: e2e / ${{ matrix.plan }}
2122

e2e/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ On each PR, this workflow runs, and tried to deploy and test an actual environme
1515
- [x] [AWS Lambda](./tests/aws-lambda.ts)
1616
- [x] [Docker container](./tests/docker.ts)
1717
- [x] [Vercel Function](./tests/vercel.ts)
18+
- [x] [Vercel Edge Function](./tests/vercel-edge.ts)
1819
- [ ] K8s Pod
1920
- [ ] Docker
2021

e2e/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@ import { dockerDeployment } from './tests/docker'
77
import { DeploymentConfiguration } from './types'
88
import { env, getCommitId } from './utils'
99
import { vercelDeployment } from './tests/vercel'
10+
import { vercelEdgeDeployment } from './tests/vercel-edge'
1011

1112
const AVAILABLE_TEST_PLANS = {
1213
'cf-worker': cloudFlareDeployment,
1314
'cf-modules': cfModulesDeployment,
1415
'azure-function': azureFunctionDeployment,
1516
'aws-lambda': awsLambdaDeployment,
1617
'vercel-function': vercelDeployment,
18+
'vercel-edge': vercelEdgeDeployment,
1719
'docker-node-17': dockerDeployment('node:17.8.0-alpine3.14'),
1820
}
1921

e2e/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
"@pulumi/aws": "5.34.0",
1212
"@pulumi/docker": "4.1.2",
1313
"@types/node": "18.15.11",
14+
"execa": "^5.1.0",
1415
"typescript": "5.0.3",
1516
"ts-node": "10.9.1"
1617
},

e2e/tests/vercel-edge.ts

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
import * as pulumi from '@pulumi/pulumi'
2+
import * as fs from 'fs/promises'
3+
import * as path from 'path'
4+
import execa = require('execa')
5+
import {
6+
assertGraphiQL,
7+
assertQuery,
8+
env,
9+
fsPromises,
10+
waitForEndpoint,
11+
} from '../utils'
12+
import { DeploymentConfiguration } from '../types'
13+
14+
type VercelDeploymentInputs = {}
15+
16+
class VercelProvider implements pulumi.dynamic.ResourceProvider {
17+
private baseUrl = 'https://api.vercel.com'
18+
private authToken = env('VERCEL_AUTH_TOKEN')
19+
private directory = path.resolve(__dirname, '..', 'examples', 'nextjs-edge')
20+
21+
private getTeamId(): string | null {
22+
try {
23+
return env('VERCEL_TEAM_ID')
24+
} catch {
25+
return null
26+
}
27+
}
28+
29+
async delete(id: string) {
30+
const teamId = this.getTeamId()
31+
const response = await fetch(
32+
`${this.baseUrl}/v13/deployments/${id}${
33+
teamId ? `?teamId=${teamId}` : ''
34+
}`,
35+
{
36+
method: 'DELETE',
37+
headers: {
38+
Authorization: `Bearer ${this.authToken}`,
39+
},
40+
},
41+
)
42+
43+
if (response.status !== 200) {
44+
throw new Error(
45+
`Failed to delete Vercel deployment: invalid status code (${
46+
response.status
47+
}), body: ${await response.text()}`,
48+
)
49+
}
50+
}
51+
52+
async create(): Promise<pulumi.dynamic.CreateResult> {
53+
// Create project
54+
const teamId = this.getTeamId()
55+
56+
const url = new URL(`${this.baseUrl}/v9/projects`)
57+
url.searchParams.set('teamId', teamId)
58+
59+
const response = await fetch(url.toString(), {
60+
method: 'POST',
61+
headers: {
62+
Authorization: `Bearer ${this.authToken}`,
63+
},
64+
body: JSON.stringify({
65+
name: new Date().toISOString(),
66+
framework: 'nextjs',
67+
}),
68+
})
69+
70+
await pulumi.log.info(`Create deployment (status=${response.status})`)
71+
72+
if (response.status !== 200) {
73+
throw new Error(
74+
`Failed to create Vercel deployment: invalid status code (${
75+
response.status
76+
}), body: ${await response.text()}`,
77+
)
78+
}
79+
80+
const responseJson: {
81+
id: string
82+
// url: string
83+
} = await response.json()
84+
85+
// Deploy project
86+
await fs.rmdir(path.join(this.directory, '.vercel'), {
87+
recursive: true,
88+
// @ts-expect-error
89+
force: true,
90+
})
91+
92+
await fs.mkdir(path.join(this.directory, '.vercel'))
93+
94+
await fs.writeFile(
95+
path.join(this.directory, '.vercel', 'project.json'),
96+
JSON.stringify({
97+
projectId: responseJson.id,
98+
// TODO: figure out how we can `orgId` without inlining it.
99+
orgId: this.getTeamId(),
100+
settings: {
101+
createdAt: 1677572115659,
102+
framework: 'nextjs',
103+
devCommand: null,
104+
installCommand: null,
105+
buildCommand: null,
106+
outputDirectory: null,
107+
rootDirectory: null,
108+
directoryListing: false,
109+
nodeVersion: '18.x',
110+
},
111+
}),
112+
)
113+
114+
await execa('pnpm', ['run', 'end2end:build'], {
115+
cwd: this.directory,
116+
})
117+
118+
const deployment = await execa('pnpm', ['run', 'end2end:deploy'], {
119+
cwd: this.directory,
120+
})
121+
122+
const regex = /\n Production: (https:\/\/.*.vercel.app) \[/
123+
124+
const result = deployment.all?.match(regex)
125+
126+
if (!Array.isArray(result)) {
127+
pulumi.log.info("Couldn't find deployment URL in output.")
128+
throw new Error("Couldn't find deployment URL in output.")
129+
}
130+
131+
const deploymentUrl = result[1]
132+
133+
return {
134+
id: responseJson.id,
135+
outs: {
136+
url: deploymentUrl,
137+
},
138+
}
139+
}
140+
}
141+
142+
export class VercelDeployment extends pulumi.dynamic.Resource {
143+
public readonly url: pulumi.Output<string>
144+
145+
constructor(
146+
name: string,
147+
props: VercelDeploymentInputs,
148+
opts?: pulumi.CustomResourceOptions,
149+
) {
150+
super(
151+
new VercelProvider(),
152+
name,
153+
{
154+
url: undefined,
155+
...props,
156+
},
157+
opts,
158+
)
159+
}
160+
}
161+
162+
export const vercelEdgeDeployment: DeploymentConfiguration<{
163+
functionUrl: string
164+
}> = {
165+
program: async () => {
166+
const deployment = new VercelDeployment('vercel-edge', {})
167+
168+
return {
169+
functionUrl: pulumi.interpolate`https://${deployment.url}/api/graphql`,
170+
}
171+
},
172+
test: async ({ functionUrl }) => {
173+
console.log(`ℹ️ Vercel Edge Function deployed to URL: ${functionUrl.value}`)
174+
await waitForEndpoint(functionUrl.value, 5, 10000)
175+
await assertGraphiQL(functionUrl.value)
176+
await assertQuery(functionUrl.value)
177+
},
178+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"extends": "next/core-web-vitals"
3+
}

examples/nextjs-edge/.gitignore

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2+
3+
# dependencies
4+
/node_modules
5+
/.pnp
6+
.pnp.js
7+
8+
# testing
9+
/coverage
10+
11+
# next.js
12+
/.next/
13+
/out/
14+
15+
# production
16+
/build
17+
18+
# misc
19+
.DS_Store
20+
*.pem
21+
22+
# debug
23+
npm-debug.log*
24+
25+
# local env files
26+
.env.local
27+
.env.development.local
28+
.env.test.local
29+
.env.production.local
30+
31+
# vercel
32+
.vercel

examples/nextjs-edge/README.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
2+
3+
## Getting Started
4+
5+
First, run the development server:
6+
7+
```bash
8+
npm run dev
9+
# or
10+
pnpm dev
11+
```
12+
13+
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
14+
15+
You can start editing the page by modifying `pages/index.js`. The page auto-updates as you edit the file.
16+
17+
[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.js`.
18+
19+
The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.
20+
21+
## Learn More
22+
23+
To learn more about Next.js, take a look at the following resources:
24+
25+
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
26+
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
27+
28+
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
29+
30+
## Deploy on Vercel
31+
32+
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
33+
34+
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.

examples/nextjs-edge/next-env.d.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/// <reference types="next" />
2+
/// <reference types="next/image-types/global" />
3+
4+
// NOTE: This file should not be edited
5+
// see https://nextjs.org/docs/basic-features/typescript for more information.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
module.exports = {
2+
reactStrictMode: true,
3+
eslint: {
4+
// Warning: This allows production builds to successfully complete even if
5+
// your project has ESLint errors.
6+
ignoreDuringBuilds: true,
7+
},
8+
}

0 commit comments

Comments
 (0)