Compare commits

..

7 Commits

Author SHA1 Message Date
chloetedder
191ce739a1 test 2023-02-13 21:03:01 -07:00
chloetedder
d51832edf1 test 2023-02-13 20:18:31 -07:00
chloetedder
dcab764ef1 test 2023-02-13 19:50:07 -07:00
chloetedder
ba80da4957 test 2023-02-13 18:33:44 -07:00
chloetedder
89e5ce7256 no change 2023-02-13 18:20:14 -07:00
chloetedder
a244493778 Test fix 2023-02-13 17:48:45 -07:00
chloetedder
52472dbd43 Fix tests 2023-02-13 15:09:06 -07:00
91 changed files with 705 additions and 18296 deletions

View File

@@ -41,7 +41,7 @@ jobs:
run: npm i -g pnpm@7.24.2
- run: pnpm install
- run: pnpm run build
- run: pnpm test-cli
- run: pnpm test-integration-cli
env:
VERCEL_TEST_TOKEN: ${{ secrets.VERCEL_TEST_TOKEN }}
VERCEL_TEST_REGISTRATION_URL: ${{ secrets.VERCEL_TEST_REGISTRATION_URL }}

View File

@@ -11,4 +11,4 @@ Remove the `functions` config from your `now.json` or `vercel.json` to take adva
### Useful Links
- [Functions Config Documentation](https://vercel.com/docs/concepts/projects/project-configuration#functions)
- [Functions Config Documentation](https://vercel.com/docs/configuration?query=functions#project/functions)

View File

@@ -11,6 +11,6 @@ Migrate from using legacy `routes` to the new `rewrites`, `redirects`, and `head
### Useful Links
- [Rewrites Documentation](https://vercel.com/docs/concepts/projects/project-configuration#rewrites)
- [Redirects Documentation](https://vercel.com/docs/concepts/projects/project-configuration#redirects)
- [Headers Documentation](https://vercel.com/docs/concepts/projects/project-configuration#headers)
- [Rewrites Documentation](https://vercel.com/docs/configuration?query=rewrites#project/rewrites)
- [Redirects Documentation](https://vercel.com/docs/configuration?query=rewrites#project/redirects)
- [Headers Documentation](https://vercel.com/docs/configuration?query=rewrites#project/headers)

View File

@@ -2,15 +2,15 @@
#### Why This Error Occurred
This error is often caused by a misconfigured "Build Command" or "Output Directory" for your Next.js project.
This could be caused by a misconfigured "Build Command" or "Output Directory" for your Next.js project.
#### Possible Ways to Fix It
In the Vercel dashboard, open your "Project Settings" and draw attention to "Build & Development Settings":
1. Ensure that the "Build Command" setting is not overridden, or that it calls `next build`. If this command is not overridden but you are seeing this error, double check that your `build` script in `package.json` calls `next build`. If `buildCommand` exists in `vercel.json`, make sure it calls `next build`.
2. Ensure that the "Output Directory" setting is not overridden. This value almost never needs to be configured, and is only necessary if you override `distDir` in `next.config.js`. If `outputDirectory` exists in `vercel.json`, remove that property.
3. For `next export` users: **do not override the "Output Directory"**, even if you customized the `next export` output directory. It will automatically detects the correct output.
1. Ensure that the "Build Command" setting is not changed, or that it calls `next build`. If this command is not changed but you are seeing this error, double check that your `build` script in `package.json` calls `next build`.
2. Ensure that the "Output Directory" setting is not changed. This value almost never needs to be configured, and is only necessary if you override `distDir` in `next.config.js`.
3. For `next export` users: **do not override the "Output Directory"**. Next.js automatically detects what folder you outputted `next export` to.
In rare scenarios, this error message can also be caused by a Next.js build failure (if your "Build Command" accidentally returns an exit code that is not 0).
Double check for any error messages above the Routes Manifest error, which may provide additional details.

View File

@@ -4,7 +4,7 @@
"description": "Each subdirectory is an example boilerplate for a framework. This package.json only exists for testing purposes.",
"scripts": {
"test-unit": "pnpm test __tests__/unit/",
"test-e2e": "pnpm test __tests__/integration/",
"test-integration-once": "pnpm test __tests__/integration/",
"test": "jest --env node --verbose --runInBand --bail"
},
"devDependencies": {

View File

@@ -32,7 +32,7 @@
"source-map-support": "0.5.12",
"ts-eager": "2.0.2",
"ts-jest": "28.0.5",
"turbo": "1.7.4"
"turbo": "1.7.0"
},
"scripts": {
"lerna": "lerna",
@@ -47,9 +47,9 @@
"pre-commit": "lint-staged",
"test": "jest --rootDir=\"test\" --testPathPattern=\"\\.test.js\"",
"test-unit": "pnpm test && node utils/gen.js && turbo run test-unit",
"test-cli": "node utils/gen.js && turbo run test-cli",
"test-e2e": "node utils/gen.js && turbo run test-e2e",
"test-dev": "node utils/gen.js && turbo run test-dev",
"test-integration-cli": "node utils/gen.js && turbo run test-integration-cli",
"test-integration-once": "node utils/gen.js && turbo run test-integration-once",
"test-integration-dev": "node utils/gen.js && turbo run test-integration-dev",
"lint": "eslint . --cache --ext .ts,.js",
"prepare": "husky install",
"pack": "cd utils && node -r ts-eager/register ./pack.ts"

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/build-utils",
"version": "6.2.3",
"version": "6.2.2",
"license": "MIT",
"main": "./dist/index.js",
"types": "./dist/index.d.js",
@@ -14,7 +14,7 @@
"build": "node build",
"test": "jest --env node --verbose --runInBand --bail",
"test-unit": "pnpm test test/unit.*test.*",
"test-e2e": "pnpm test test/integration.test.ts"
"test-integration-once": "pnpm test test/integration.test.ts"
},
"devDependencies": {
"@iarna/toml": "2.2.3",

View File

@@ -44,8 +44,7 @@ export function getPrettyError(obj: {
message?: string;
params: any;
}): NowBuildError {
const docsUrl =
'https://vercel.com/docs/concepts/projects/project-configuration';
const docsUrl = 'https://vercel.com/docs/configuration';
try {
const { dataPath, params, message: ajvMessage } = obj;
const prop = getTopLevelPropertyName(dataPath);
@@ -64,7 +63,7 @@ export function getPrettyError(obj: {
return new NowBuildError({
code: 'INVALID_VERCEL_CONFIG',
message: message,
link: prop ? `${docsUrl}#${prop.toLowerCase()}` : docsUrl,
link: prop ? `${docsUrl}#project/${prop.toLowerCase()}` : docsUrl,
action: 'View Documentation',
});
} catch (e) {

View File

@@ -13,8 +13,10 @@ export const functionsSchema = {
maxLength: 256,
},
memory: {
minimum: 128,
maximum: 3008,
// Number between 128 and 3008 in steps of 64
enum: Object.keys(Array.from({ length: 50 }))
.slice(2, 48)
.map(x => Number(x) * 64),
},
maxDuration: {
type: 'number',

View File

@@ -1,6 +1,6 @@
{
"name": "vercel",
"version": "28.15.5",
"version": "28.15.4",
"preferGlobal": true,
"license": "Apache-2.0",
"description": "The command-line interface for Vercel",
@@ -14,8 +14,8 @@
"preinstall": "node ./scripts/preinstall.js",
"test": "jest --env node --verbose --bail",
"test-unit": "pnpm test test/unit/",
"test-cli": "rimraf test/fixtures/integration && ava test/integration.js --serial --fail-fast --verbose",
"test-dev": "pnpm test test/dev/",
"test-integration-cli": "rimraf test/fixtures/integration && ava test/integration.js --serial --fail-fast --verbose",
"test-integration-dev": "pnpm test test/dev/",
"coverage": "codecov",
"build": "ts-node ./scripts/build.ts",
"dev": "ts-node ./src/index.ts"
@@ -41,16 +41,16 @@
"node": ">= 14"
},
"dependencies": {
"@vercel/build-utils": "6.2.3",
"@vercel/go": "2.3.5",
"@vercel/hydrogen": "0.0.51",
"@vercel/next": "3.4.4",
"@vercel/node": "2.9.4",
"@vercel/python": "3.1.47",
"@vercel/redwood": "1.1.3",
"@vercel/remix": "1.3.0",
"@vercel/ruby": "1.3.63",
"@vercel/static-build": "1.3.7"
"@vercel/build-utils": "6.2.2",
"@vercel/go": "2.3.4",
"@vercel/hydrogen": "0.0.50",
"@vercel/next": "3.4.3",
"@vercel/node": "2.9.3",
"@vercel/python": "3.1.46",
"@vercel/redwood": "1.1.2",
"@vercel/remix": "1.2.13",
"@vercel/ruby": "1.3.62",
"@vercel/static-build": "1.3.6"
},
"devDependencies": {
"@alex_neo/jest-expect-message": "1.0.5",
@@ -93,10 +93,10 @@
"@types/which": "1.3.2",
"@types/write-json-file": "2.2.1",
"@types/yauzl-promise": "2.1.0",
"@vercel/client": "12.3.9",
"@vercel/client": "12.3.8",
"@vercel/error-utils": "1.0.8",
"@vercel/frameworks": "1.3.0",
"@vercel/fs-detectors": "3.7.12",
"@vercel/fs-detectors": "3.7.11",
"@vercel/fun": "1.0.4",
"@vercel/ncc": "0.24.0",
"@vercel/routing-utils": "2.1.8",

View File

@@ -701,7 +701,7 @@ function expandBuild(files: string[], build: Builder): Builder[] {
throw new NowBuildError({
code: `invalid_build_specification`,
message: 'Field `use` is missing in build specification',
link: 'https://vercel.com/docs/concepts/projects/project-configuration#builds',
link: 'https://vercel.com/docs/configuration#project/builds',
action: 'View Documentation',
});
}
@@ -711,7 +711,7 @@ function expandBuild(files: string[], build: Builder): Builder[] {
throw new NowBuildError({
code: `invalid_build_specification`,
message: 'A build `src` path resolves to an empty string',
link: 'https://vercel.com/docs/concepts/projects/project-configuration#builds',
link: 'https://vercel.com/docs/configuration#project/builds',
action: 'View Documentation',
});
}

View File

@@ -1,10 +1,6 @@
{
"name": "app-2",
"version": "0.0.1",
"main": "dist/index.js",
"files": [
"dist"
],
"scripts": {
"build": "node script.js"
}

View File

@@ -271,7 +271,7 @@ module.exports = async function prepare(session, binaryPath, tmpFixturesDir) {
},
}),
},
'lambda-with-123-memory': {
'lambda-with-200-memory': {
'api/memory.js': `
module.exports = (req, res) => {
res.json({ memory: parseInt(process.env.AWS_LAMBDA_FUNCTION_MEMORY_SIZE) });
@@ -280,7 +280,7 @@ module.exports = async function prepare(session, binaryPath, tmpFixturesDir) {
'now.json': JSON.stringify({
functions: {
'api/**/*.js': {
memory: 123,
memory: 200,
},
},
}),

View File

@@ -1967,11 +1967,7 @@ test('try to create a builds deployments with wrong now.json', async t => {
'Error: Invalid now.json - should NOT have additional property `builder`. Did you mean `builds`?'
)
);
t.true(
stderr.includes(
'https://vercel.com/docs/concepts/projects/project-configuration'
)
);
t.true(stderr.includes('https://vercel.com/docs/configuration'));
});
test('try to create a builds deployments with wrong vercel.json', async t => {
@@ -1995,11 +1991,7 @@ test('try to create a builds deployments with wrong vercel.json', async t => {
'Error: Invalid vercel.json - should NOT have additional property `fake`. Please remove it.'
)
);
t.true(
stderr.includes(
'https://vercel.com/docs/concepts/projects/project-configuration'
)
);
t.true(stderr.includes('https://vercel.com/docs/configuration'));
});
test('try to create a builds deployments with wrong `build.env` property', async t => {
@@ -2022,9 +2014,7 @@ test('try to create a builds deployments with wrong `build.env` property', async
formatOutput({ stdout, stderr })
);
t.true(
stderr.includes(
'https://vercel.com/docs/concepts/projects/project-configuration'
),
stderr.includes('https://vercel.com/docs/configuration'),
formatOutput({ stdout, stderr })
);
});
@@ -2729,15 +2719,11 @@ test('deploy a Lambda with 128MB of memory', async t => {
});
test('fail to deploy a Lambda with an incorrect value for of memory', async t => {
const directory = fixture('lambda-with-123-memory');
const directory = fixture('lambda-with-200-memory');
const output = await execute([directory, '--yes']);
t.is(output.exitCode, 1, formatOutput(output));
t.regex(
output.stderr,
/Serverless Functions.+memory/gm,
formatOutput(output)
);
t.regex(output.stderr, /steps of 64/gm, formatOutput(output));
t.regex(output.stderr, /Learn More/gm, formatOutput(output));
});

View File

@@ -1080,7 +1080,7 @@ describe('build', () => {
await expect(client.stderr).toOutput(
'Error: Invalid vercel.json - `rewrites[2]` should NOT have additional property `src`. Did you mean `source`?' +
'\n' +
'View Documentation: https://vercel.com/docs/concepts/projects/project-configuration#rewrites'
'View Documentation: https://vercel.com/docs/configuration#project/rewrites'
);
const builds = await fs.readJSON(join(output, 'builds.json'));
expect(builds.builds).toBeUndefined();
@@ -1091,7 +1091,7 @@ describe('build', () => {
stack: expect.stringContaining('at validateConfig'),
hideStackTrace: true,
code: 'INVALID_VERCEL_CONFIG',
link: 'https://vercel.com/docs/concepts/projects/project-configuration#rewrites',
link: 'https://vercel.com/docs/configuration#project/rewrites',
action: 'View Documentation',
});
const configJson = await fs.readJSON(join(output, 'config.json'));

View File

@@ -41,7 +41,7 @@ describe('validateConfig', () => {
'Invalid vercel.json - `rewrites[0]` should NOT have additional property `src`. Did you mean `source`?'
);
expect(error!.link).toEqual(
'https://vercel.com/docs/concepts/projects/project-configuration#rewrites'
'https://vercel.com/docs/configuration#project/rewrites'
);
});
@@ -54,7 +54,7 @@ describe('validateConfig', () => {
'Invalid vercel.json - `routes[0]` should NOT have additional property `source`. Did you mean `src`?'
);
expect(error!.link).toEqual(
'https://vercel.com/docs/concepts/projects/project-configuration#routes'
'https://vercel.com/docs/configuration#project/routes'
);
});
@@ -67,7 +67,7 @@ describe('validateConfig', () => {
'Invalid vercel.json - `routes` should be array.'
);
expect(error!.link).toEqual(
'https://vercel.com/docs/concepts/projects/project-configuration#routes'
'https://vercel.com/docs/configuration#project/routes'
);
});
@@ -84,7 +84,7 @@ describe('validateConfig', () => {
'Invalid vercel.json - `redirects[0]` missing required property `source`.'
);
expect(error!.link).toEqual(
'https://vercel.com/docs/concepts/projects/project-configuration#redirects'
'https://vercel.com/docs/configuration#project/redirects'
);
});
@@ -97,7 +97,7 @@ describe('validateConfig', () => {
'Invalid vercel.json - `redirects[0].permanent` should be boolean.'
);
expect(error!.link).toEqual(
'https://vercel.com/docs/concepts/projects/project-configuration#redirects'
'https://vercel.com/docs/configuration#project/redirects'
);
});
@@ -110,7 +110,7 @@ describe('validateConfig', () => {
'Invalid vercel.json - `cleanUrls` should be boolean.'
);
expect(error!.link).toEqual(
'https://vercel.com/docs/concepts/projects/project-configuration#cleanurls'
'https://vercel.com/docs/configuration#project/cleanurls'
);
});
@@ -123,7 +123,7 @@ describe('validateConfig', () => {
'Invalid vercel.json - `trailingSlash` should be boolean.'
);
expect(error!.link).toEqual(
'https://vercel.com/docs/concepts/projects/project-configuration#trailingslash'
'https://vercel.com/docs/configuration#project/trailingslash'
);
});
@@ -136,7 +136,7 @@ describe('validateConfig', () => {
'Invalid vercel.json - `headers[0]` should NOT have additional property `Content-Type`. Please remove it.'
);
expect(error!.link).toEqual(
'https://vercel.com/docs/concepts/projects/project-configuration#headers'
'https://vercel.com/docs/configuration#project/headers'
);
});
@@ -149,7 +149,7 @@ describe('validateConfig', () => {
'Invalid vercel.json - `headers[0].source` should be string.'
);
expect(error!.link).toEqual(
'https://vercel.com/docs/concepts/projects/project-configuration#headers'
'https://vercel.com/docs/configuration#project/headers'
);
});
@@ -162,7 +162,7 @@ describe('validateConfig', () => {
'Invalid vercel.json - `headers[0]` should NOT have additional property `stuff`. Please remove it.'
);
expect(error!.link).toEqual(
'https://vercel.com/docs/concepts/projects/project-configuration#headers'
'https://vercel.com/docs/configuration#project/headers'
);
});
@@ -175,7 +175,7 @@ describe('validateConfig', () => {
'Invalid vercel.json - `headers[0].headers[0]` should NOT have additional property `Content-Type`. Please remove it.'
);
expect(error!.link).toEqual(
'https://vercel.com/docs/concepts/projects/project-configuration#headers'
'https://vercel.com/docs/configuration#project/headers'
);
});
@@ -190,7 +190,7 @@ describe('validateConfig', () => {
'Invalid vercel.json - `headers[0].headers[0]` should NOT have additional property `val`. Please remove it.'
);
expect(error!.link).toEqual(
'https://vercel.com/docs/concepts/projects/project-configuration#headers'
'https://vercel.com/docs/configuration#project/headers'
);
});
@@ -205,7 +205,7 @@ describe('validateConfig', () => {
'Invalid vercel.json - `redirects` should NOT have more than 1024 items.'
);
expect(error!.link).toEqual(
'https://vercel.com/docs/concepts/projects/project-configuration#redirects'
'https://vercel.com/docs/configuration#project/redirects'
);
});
@@ -229,39 +229,7 @@ describe('validateConfig', () => {
'Invalid vercel.json - `headers[1].headers` should NOT have more than 1024 items.'
);
expect(error!.link).toEqual(
'https://vercel.com/docs/concepts/projects/project-configuration#headers'
);
});
it('should error with too low memory value', async () => {
const error = validateConfig({
functions: {
'api/test.js': {
memory: 127,
},
},
});
expect(error!.message).toEqual(
"Invalid vercel.json - `functions['api/test.js'].memory` should be >= 128."
);
expect(error!.link).toEqual(
'https://vercel.com/docs/concepts/projects/project-configuration#functions'
);
});
it('should error with too high memory value', async () => {
const error = validateConfig({
functions: {
'api/test.js': {
memory: 3009,
},
},
});
expect(error!.message).toEqual(
"Invalid vercel.json - `functions['api/test.js'].memory` should be <= 3008."
);
expect(error!.link).toEqual(
'https://vercel.com/docs/concepts/projects/project-configuration#functions'
'https://vercel.com/docs/configuration#project/headers'
);
});

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/client",
"version": "12.3.9",
"version": "12.3.8",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
"homepage": "https://vercel.com",
@@ -15,7 +15,7 @@
},
"scripts": {
"build": "tsc",
"test-e2e": "pnpm test tests/create-deployment.test.ts tests/create-legacy-deployment.test.ts tests/paths.test.ts",
"test-integration-once": "pnpm test tests/create-deployment.test.ts tests/create-legacy-deployment.test.ts tests/paths.test.ts",
"test": "jest --env node --verbose --runInBand --bail",
"test-unit": "pnpm test tests/unit.*test.*"
},
@@ -43,7 +43,7 @@
]
},
"dependencies": {
"@vercel/build-utils": "6.2.3",
"@vercel/build-utils": "6.2.2",
"@vercel/routing-utils": "2.1.8",
"@zeit/fetch": "5.2.0",
"async-retry": "1.2.3",

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/fs-detectors",
"version": "3.7.12",
"version": "3.7.11",
"description": "Vercel filesystem detectors",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
@@ -35,7 +35,7 @@
"@types/minimatch": "3.0.5",
"@types/node": "14.18.33",
"@types/semver": "7.3.10",
"@vercel/build-utils": "6.2.3",
"@vercel/build-utils": "6.2.2",
"typescript": "4.3.4"
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/gatsby-plugin-vercel-builder",
"version": "1.1.5",
"version": "1.1.4",
"main": "dist/index.js",
"files": [
"dist",
@@ -14,8 +14,8 @@
"build:src": "tsc -p tsconfig.src.json"
},
"dependencies": {
"@vercel/build-utils": "6.2.3",
"@vercel/node": "2.9.4",
"@vercel/build-utils": "6.2.2",
"@vercel/node": "2.9.3",
"@vercel/routing-utils": "2.1.8",
"ajv": "8.12.0",
"esbuild": "0.14.47",

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/go",
"version": "2.3.5",
"version": "2.3.4",
"license": "MIT",
"main": "./dist/index",
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/go",
@@ -12,7 +12,7 @@
"scripts": {
"build": "node build",
"test": "jest --env node --verbose --runInBand --bail",
"test-e2e": "pnpm test"
"test-integration-once": "pnpm test"
},
"files": [
"dist"
@@ -36,7 +36,7 @@
"@types/node": "14.18.33",
"@types/node-fetch": "^2.3.0",
"@types/tar": "^4.0.0",
"@vercel/build-utils": "6.2.3",
"@vercel/build-utils": "6.2.2",
"@vercel/ncc": "0.24.0",
"async-retry": "1.3.1",
"execa": "^1.0.0",

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/hydrogen",
"version": "0.0.51",
"version": "0.0.50",
"license": "MIT",
"main": "./dist/index.js",
"homepage": "https://vercel.com/docs",
@@ -11,7 +11,7 @@
},
"scripts": {
"build": "node build.js",
"test-e2e": "pnpm test test/test.js",
"test-integration-once": "pnpm test test/test.js",
"test": "jest --env node --verbose --bail --runInBand"
},
"files": [
@@ -21,7 +21,7 @@
"devDependencies": {
"@types/jest": "27.5.1",
"@types/node": "14.18.33",
"@vercel/build-utils": "6.2.3",
"@vercel/build-utils": "6.2.2",
"@vercel/static-config": "2.0.12",
"execa": "3.2.0",
"fs-extra": "11.1.0",

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/next",
"version": "3.4.4",
"version": "3.4.3",
"license": "MIT",
"main": "./dist/index",
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/next-js",
@@ -11,7 +11,7 @@
"test-unit": "pnpm test test/unit/",
"test-next-local": "pnpm test test/integration/*.test.js test/integration/*.test.ts",
"test-next-local:middleware": "pnpm test test/integration/middleware.test.ts",
"test-e2e": "rm -f test/builder-info.json; pnpm test test/fixtures/**/*.test.js"
"test-integration-once": "rm -f test/builder-info.json; pnpm test test/fixtures/**/*.test.js"
},
"repository": {
"type": "git",
@@ -45,7 +45,7 @@
"@types/semver": "6.0.0",
"@types/text-table": "0.2.1",
"@types/webpack-sources": "3.2.0",
"@vercel/build-utils": "6.2.3",
"@vercel/build-utils": "6.2.2",
"@vercel/nft": "0.22.5",
"@vercel/routing-utils": "2.1.8",
"async-sema": "3.0.1",

View File

@@ -269,7 +269,12 @@ export async function getRoutesManifest(
if (shouldHaveManifest && !hasRoutesManifest) {
throw new NowBuildError({
message: `The file "${pathRoutesManifest}" couldn't be found. This is often caused by a misconfiguration in your project.`,
message:
`The file "${pathRoutesManifest}" couldn't be found. This is normally caused by a misconfiguration in your project.\n` +
'Please check the following, and reach out to support if you cannot resolve the problem:\n' +
' 1. If present, be sure your `build` script in "package.json" calls `next build`.' +
' 2. Navigate to your project\'s settings in the Vercel dashboard, and verify that the "Build Command" is not overridden, or that it calls `next build`.' +
' 3. Navigate to your project\'s settings in the Vercel dashboard, and verify that the "Output Directory" is not overridden. Note that `next export` does **not** require you change this setting, even if you customize the `next export` output directory.',
link: 'https://err.sh/vercel/vercel/now-next-routes-manifest',
code: 'NEXT_NO_ROUTES_MANIFEST',
});
@@ -2026,8 +2031,7 @@ export const onPrerenderRoute =
const rscVaryHeader =
routesManifest?.rsc?.varyHeader ||
'__rsc__, __next_router_state_tree__, __next_router_prefetch__';
const rscContentTypeHeader =
routesManifest?.rsc?.contentTypeHeader || 'application/octet-stream';
const rscContentTypeHeader = routesManifest?.rsc?.contentTypeHeader || 'application/octet-stream';
prerenders[outputPathPage] = new Prerender({
expiration: initialRevalidate,

View File

@@ -27,7 +27,7 @@
"RSC": "1"
},
"responseHeaders": {
"content-type": "text/x-component"
"content-type": "application/octet-stream"
}
},
{
@@ -51,7 +51,7 @@
"RSC": "1"
},
"responseHeaders": {
"content-type": "text/x-component"
"content-type": "application/octet-stream"
}
}
]

View File

@@ -30,7 +30,7 @@
"RSC": "1"
},
"responseHeaders": {
"content-type": "text/x-component",
"content-type": "application/octet-stream",
"vary": "RSC, Next-Router-State-Tree, Next-Router-Prefetch"
}
},

View File

@@ -122,7 +122,7 @@
"RSC": "1"
},
"responseHeaders": {
"content-type": "text/x-component",
"content-type": "application/octet-stream",
"vary": "RSC, Next-Router-State-Tree, Next-Router-Prefetch"
}
},

View File

@@ -119,7 +119,7 @@
"RSC": "1"
},
"responseHeaders": {
"content-type": "text/x-component",
"content-type": "application/octet-stream",
"vary": "RSC, Next-Router-State-Tree, Next-Router-Prefetch"
}
},

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/node",
"version": "2.9.4",
"version": "2.9.3",
"license": "MIT",
"main": "./dist/index",
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/node-js",
@@ -13,7 +13,7 @@
"build": "node build",
"test": "jest --env node --verbose --bail --runInBand",
"test-unit": "pnpm test test/prepare-cache.test.ts test/utils.test.ts",
"test-e2e": "pnpm test test/integration-*.test.js"
"test-integration-once": "pnpm test test/integration-*.test.js"
},
"files": [
"dist"
@@ -31,7 +31,7 @@
"dependencies": {
"@edge-runtime/vm": "2.0.0",
"@types/node": "14.18.33",
"@vercel/build-utils": "6.2.3",
"@vercel/build-utils": "6.2.2",
"@vercel/node-bridge": "3.1.11",
"@vercel/static-config": "2.0.12",
"edge-runtime": "2.0.0",

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/python",
"version": "3.1.47",
"version": "3.1.46",
"main": "./dist/index.js",
"license": "MIT",
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/python",
@@ -17,13 +17,13 @@
"build": "node build",
"test": "jest --env node --verbose --runInBand --bail",
"test-unit": "pnpm test test/unit.test.ts",
"test-e2e": "pnpm test test/integration.test.ts"
"test-integration-once": "pnpm test test/integration.test.ts"
},
"devDependencies": {
"@types/execa": "^0.9.0",
"@types/jest": "27.4.1",
"@types/node": "14.18.33",
"@vercel/build-utils": "6.2.3",
"@vercel/build-utils": "6.2.2",
"@vercel/ncc": "0.24.0",
"execa": "^1.0.0",
"typescript": "4.3.4"

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/redwood",
"version": "1.1.3",
"version": "1.1.2",
"main": "./dist/index.js",
"license": "MIT",
"homepage": "https://vercel.com/docs",
@@ -14,7 +14,7 @@
},
"scripts": {
"build": "node build.js",
"test-e2e": "pnpm test test/test.js",
"test-integration-once": "pnpm test test/test.js",
"test": "jest --env node --verbose --bail --runInBand",
"test-unit": "pnpm test test/prepare-cache.test.js"
},
@@ -27,7 +27,7 @@
"@types/aws-lambda": "8.10.19",
"@types/node": "14.18.33",
"@types/semver": "6.0.0",
"@vercel/build-utils": "6.2.3",
"@vercel/build-utils": "6.2.2",
"execa": "3.2.0",
"fs-extra": "11.1.0",
"typescript": "4.3.4"

View File

@@ -1,30 +0,0 @@
# `@vercel/remix-entry-server`
This package is meant for use within Remix applications when deploying to Vercel. It provides implementations for the `app/entry.server.tsx` file for both the Node.js Serverless Runtime and the Edge Runtime. The implementations are configured to [handle streaming responses](https://remix.run/docs/en/v1/guides/streaming).
## Usage
Make sure `@vercel/remix-entry-server` is installed with your package manager of choice, then replace your `app/entry.server.tsx` file with the following:
```tsx
// `app/entry.server.tsx`
import handleRequest from '@vercel/remix-entry-server';
import { RemixServer } from '@remix-run/react';
import type { EntryContext } from '@remix-run/server-runtime';
export default function (
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext
) {
const remixServer = <RemixServer context={remixContext} url={request.url} />;
return handleRequest(
request,
responseStatusCode,
responseHeaders,
remixServer
);
}
```

View File

@@ -1,12 +0,0 @@
const execa = require('execa');
const { remove } = require('fs-extra');
async function main() {
await remove('dist');
await execa('tsc', [], { stdio: 'inherit' });
}
main().catch(err => {
console.error(err);
process.exit(1);
});

View File

@@ -1,34 +0,0 @@
{
"name": "@vercel/remix-entry-server",
"version": "0.1.0",
"description": "Isomorphic `entry.server` implementation for Vercel's Serverless and Edge runtimes",
"homepage": "https://vercel.com/docs",
"repository": {
"type": "git",
"url": "https://github.com/vercel/vercel.git",
"directory": "packages/remix-entry-server"
},
"main": "./dist/entry.server.node.js",
"browser": "./dist/entry.server.edge.js",
"scripts": {
"build": "node build.js"
},
"license": "MIT",
"files": [
"dist"
],
"dependencies": {
"@remix-run/node": "1.12.0",
"isbot": "3.6.5",
"react-dom": "18.2.0"
},
"devDependencies": {
"@types/react-dom": "18.0.10",
"execa": "3.2.0",
"fs-extra": "11.1.0",
"typescript": "4.9.4"
},
"peerDependencies": {
"react": "^18.0.0"
}
}

View File

@@ -1,27 +0,0 @@
import isbot from 'isbot';
import { renderToReadableStream } from 'react-dom/server';
export default async function handleRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixServer: JSX.Element
) {
const body = await renderToReadableStream(remixServer, {
signal: request.signal,
onError(error) {
console.error(error);
responseStatusCode = 500;
},
});
if (isbot(request.headers.get('user-agent'))) {
await body.allReady;
}
responseHeaders.set('Content-Type', 'text/html');
return new Response(body, {
headers: responseHeaders,
status: responseStatusCode,
});
}

View File

@@ -1,81 +0,0 @@
import { PassThrough } from 'stream';
import { renderToPipeableStream } from 'react-dom/server';
import { Response } from '@remix-run/node';
import isbot from 'isbot';
const ABORT_DELAY = 5000;
export default function handleRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixServer: JSX.Element
) {
// If the request is from a bot, we want to wait for the full
// response to render before sending it to the client. This
// ensures that bots can see the full page content.
if (isbot(request.headers.get('user-agent'))) {
return serveTheBots(responseStatusCode, responseHeaders, remixServer);
}
return serveBrowsers(responseStatusCode, responseHeaders, remixServer);
}
function serveTheBots(
responseStatusCode: number,
responseHeaders: Headers,
remixServer: any
) {
return new Promise((resolve, reject) => {
const { pipe, abort } = renderToPipeableStream(remixServer, {
// Use onAllReady to wait for the entire document to be ready
onAllReady() {
responseHeaders.set('Content-Type', 'text/html');
const body = new PassThrough();
pipe(body);
resolve(
new Response(body, {
status: responseStatusCode,
headers: responseHeaders,
})
);
},
onShellError(err) {
reject(err);
},
});
setTimeout(abort, ABORT_DELAY);
});
}
function serveBrowsers(
responseStatusCode: number,
responseHeaders: Headers,
remixServer: any
) {
return new Promise((resolve, reject) => {
let didError = false;
const { pipe, abort } = renderToPipeableStream(remixServer, {
// use onShellReady to wait until a suspense boundary is triggered
onShellReady() {
responseHeaders.set('Content-Type', 'text/html');
const body = new PassThrough();
pipe(body);
resolve(
new Response(body, {
status: didError ? 500 : responseStatusCode,
headers: responseHeaders,
})
);
},
onShellError(err) {
reject(err);
},
onError(err) {
didError = true;
console.error(err);
},
});
setTimeout(abort, ABORT_DELAY);
});
}

View File

@@ -1,21 +0,0 @@
{
"compilerOptions": {
"declaration": true,
"esModuleInterop": true,
"lib": ["ES2020", "DOM"],
"module": "commonjs",
"moduleResolution": "node",
"noEmitOnError": true,
"noFallthroughCasesInSwitch": true,
"noImplicitReturns": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"outDir": "./dist",
"types": ["node", "jest"],
"strict": true,
"target": "ES2020",
"sourceMap": true
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}

View File

@@ -0,0 +1,3 @@
const { createRequestHandler } = require('@remix-run/vercel');
const build = require('./');
module.exports = createRequestHandler({ build });

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/remix",
"version": "1.3.0",
"version": "1.2.13",
"license": "MIT",
"main": "./dist/index.js",
"homepage": "https://vercel.com/docs",
@@ -11,25 +11,20 @@
},
"scripts": {
"build": "node build.js",
"test-e2e": "pnpm test test/integration.test.ts",
"test-integration-once": "pnpm test test/integration.test.ts",
"test": "jest --env node --verbose --bail --runInBand"
},
"files": [
"dist",
"server-node.mjs",
"server-edge.mjs"
"default-server.js"
],
"dependencies": {
"@remix-run/dev": "1.12.0",
"@vercel/nft": "0.22.5",
"@vercel/static-config": "2.0.12",
"path-to-regexp": "6.2.1",
"ts-morph": "12.0.0"
"@vercel/nft": "0.22.5"
},
"devDependencies": {
"@types/jest": "27.5.1",
"@types/node": "14.18.33",
"@vercel/build-utils": "6.2.3",
"@vercel/build-utils": "6.2.2",
"typescript": "4.9.4"
}
}

View File

@@ -1,3 +0,0 @@
import { createRequestHandler } from '@remix-run/server-runtime';
import build from './index.js';
export default createRequestHandler(build);

View File

@@ -1,70 +0,0 @@
import {
AbortController as NodeAbortController,
createRequestHandler as createRemixRequestHandler,
Headers as NodeHeaders,
Request as NodeRequest,
writeReadableStreamToWritable,
} from '@remix-run/node';
import build from './index.js';
const handleRequest = createRemixRequestHandler(build, process.env.NODE_ENV);
function createRemixHeaders(requestHeaders) {
const headers = new NodeHeaders();
for (const key in requestHeaders) {
const header = requestHeaders[key];
// set-cookie is an array (maybe others)
if (Array.isArray(header)) {
for (const value of header) {
headers.append(key, value);
}
} else {
headers.append(key, header);
}
}
return headers;
}
function createRemixRequest(req, res) {
const host = req.headers['x-forwarded-host'] || req.headers['host'];
const protocol = req.headers['x-forwarded-proto'] || 'https';
const url = new URL(req.url, `${protocol}://${host}`);
// Abort action/loaders once we can no longer write a response
const controller = new NodeAbortController();
res.on('close', () => controller.abort());
const init = {
method: req.method,
headers: createRemixHeaders(req.headers),
signal: controller.signal,
};
if (req.method !== 'GET' && req.method !== 'HEAD') {
init.body = req;
}
return new NodeRequest(url.href, init);
}
async function sendRemixResponse(res, nodeResponse) {
res.statusCode = nodeResponse.status;
res.statusMessage = nodeResponse.statusText;
for (const [name, value] of nodeResponse.headers.entries()) {
res.setHeader(name, value);
}
if (nodeResponse.body) {
await writeReadableStreamToWritable(nodeResponse.body, res);
} else {
res.end();
}
}
export default async (req, res) => {
const request = createRemixRequest(req, res);
const response = await handleRequest(request);
await sendRemixResponse(res, response);
};

View File

@@ -1,7 +1,6 @@
import { Project } from 'ts-morph';
import { promises as fs } from 'fs';
import { basename, dirname, extname, join, relative, sep } from 'path';
import { pathToRegexp, Key } from 'path-to-regexp';
import { runInContext, createContext } from 'vm';
import { dirname, join, relative } from 'path';
import {
debug,
download,
@@ -11,7 +10,6 @@ import {
getNodeVersion,
getSpawnOptions,
glob,
EdgeFunction,
NodejsLambda,
readConfigFile,
runNpmInstall,
@@ -19,20 +17,22 @@ import {
scanParentDirs,
walkParentDirs,
} from '@vercel/build-utils';
import { getConfig } from '@vercel/static-config';
import { nodeFileTrace } from '@vercel/nft';
import { readConfig, RemixConfig } from '@remix-run/dev/dist/config';
import type {
BuildV2,
Files,
NodeVersion,
PackageJson,
BuildResultV2Typical,
} from '@vercel/build-utils';
import type { ConfigRoute } from '@remix-run/dev/dist/config/routes';
import { nodeFileTrace } from '@vercel/nft';
import { findConfig } from './utils';
import type { AppConfig, RemixBuildManifest } from './types';
import type { BuildResultV2Typical } from '@vercel/build-utils';
const _require: typeof require = eval('require');
// Name of the Remix runtime adapter npm package for Vercel
const REMIX_RUNTIME_ADAPTER_NAME = '@remix-run/vercel';
// Pinned version of the last verified working version of the adapter
const REMIX_RUNTIME_ADAPTER_VERSION = '1.6.1';
export const build: BuildV2 = async ({
entrypoint,
@@ -72,6 +72,51 @@ export const build: BuildV2 = async ({
env: spawnOpts.env || {},
});
// Ensure `@remix-run/vercel` is in the project's `package.json`
const packageJsonPath = await walkParentDirs({
base: repoRootPath,
start: workPath,
filename: 'package.json',
});
if (packageJsonPath) {
const packageJson: PackageJson = JSON.parse(
await fs.readFile(packageJsonPath, 'utf8')
);
const { dependencies = {}, devDependencies = {} } = packageJson;
let modified = false;
if (REMIX_RUNTIME_ADAPTER_NAME in devDependencies) {
dependencies[REMIX_RUNTIME_ADAPTER_NAME] =
devDependencies[REMIX_RUNTIME_ADAPTER_NAME];
delete devDependencies[REMIX_RUNTIME_ADAPTER_NAME];
console.log(
`Warning: Moving "${REMIX_RUNTIME_ADAPTER_NAME}" from \`devDependencies\` to \`dependencies\`. You should commit this change.`
);
modified = true;
} else if (!(REMIX_RUNTIME_ADAPTER_NAME in dependencies)) {
dependencies[REMIX_RUNTIME_ADAPTER_NAME] = REMIX_RUNTIME_ADAPTER_VERSION;
console.log(
`Warning: Adding "${REMIX_RUNTIME_ADAPTER_NAME}" v${REMIX_RUNTIME_ADAPTER_VERSION} to \`dependencies\`. You should commit this change.`
);
modified = true;
}
if (modified) {
const packageJsonString = JSON.stringify(
{
...packageJson,
dependencies,
devDependencies,
},
null,
2
);
await fs.writeFile(packageJsonPath, `${packageJsonString}\n`);
}
} else {
debug(`Failed to find "package.json" file in project`);
}
if (typeof installCommand === 'string') {
if (installCommand.trim()) {
console.log(`Running "install" command: \`${installCommand}\`...`);
@@ -89,206 +134,116 @@ export const build: BuildV2 = async ({
// Make `remix build` output production mode
spawnOpts.env.NODE_ENV = 'production';
// We need to patch the `remix.config.js` file to force some values necessary
// for a build that works on either Node.js or the Edge runtime
const remixConfigPath = findConfig(entrypointFsDirname, 'remix.config');
const renamedRemixConfigPath = remixConfigPath
? `${remixConfigPath}.original${extname(remixConfigPath)}`
: undefined;
if (remixConfigPath && renamedRemixConfigPath) {
await fs.rename(remixConfigPath, renamedRemixConfigPath);
// Figure out if the `remix.config` file is using ESM syntax
let isESM = false;
try {
_require(renamedRemixConfigPath);
} catch (err: any) {
if (err.code === 'ERR_REQUIRE_ESM') {
isESM = true;
} else {
throw err;
}
}
let patchedConfig: string;
if (isESM) {
patchedConfig = `import config from './${basename(
renamedRemixConfigPath
)}';
config.serverBuildTarget = undefined;
config.server = undefined;
config.serverModuleFormat = 'cjs';
config.serverPlatform = 'node';
config.serverBuildPath = 'build/index.js';
export default config;`;
} else {
patchedConfig = `const config = require('./${basename(
renamedRemixConfigPath
)}');
config.serverBuildTarget = undefined;
config.server = undefined;
config.serverModuleFormat = 'cjs';
config.serverPlatform = 'node';
config.serverBuildPath = 'build/index.js';
module.exports = config;`;
}
await fs.writeFile(remixConfigPath, patchedConfig);
}
// Run "Build Command"
let remixConfig: RemixConfig;
try {
if (buildCommand) {
debug(`Executing build command "${buildCommand}"`);
await execCommand(buildCommand, {
if (buildCommand) {
debug(`Executing build command "${buildCommand}"`);
await execCommand(buildCommand, {
...spawnOpts,
cwd: entrypointFsDirname,
});
} else {
const pkg = await readConfigFile<PackageJson>(
join(entrypointFsDirname, 'package.json')
);
if (hasScript('vercel-build', pkg)) {
debug(`Executing "yarn vercel-build"`);
await runPackageJsonScript(
entrypointFsDirname,
'vercel-build',
spawnOpts
);
} else if (hasScript('build', pkg)) {
debug(`Executing "yarn build"`);
await runPackageJsonScript(entrypointFsDirname, 'build', spawnOpts);
} else {
await execCommand('remix build', {
...spawnOpts,
cwd: entrypointFsDirname,
});
} else {
const pkg = await readConfigFile<PackageJson>(
join(entrypointFsDirname, 'package.json')
);
if (hasScript('vercel-build', pkg)) {
debug(`Executing "yarn vercel-build"`);
await runPackageJsonScript(
entrypointFsDirname,
'vercel-build',
spawnOpts
);
} else if (hasScript('build', pkg)) {
debug(`Executing "yarn build"`);
await runPackageJsonScript(entrypointFsDirname, 'build', spawnOpts);
} else {
await execCommand('remix build', {
...spawnOpts,
cwd: entrypointFsDirname,
});
}
}
let serverBuildPath = 'build/index.js';
let needsHandler = true;
const remixConfigFile = findConfig(entrypointFsDirname, 'remix.config');
try {
if (remixConfigFile) {
const remixConfigModule = await eval('import(remixConfigFile)');
const remixConfig: AppConfig = remixConfigModule?.default || {};
// If `serverBuildTarget === 'vercel'` then Remix will output a handler
// that is already in Vercel (req, res) format, so don't inject the handler
if (remixConfig.serverBuildTarget) {
if (remixConfig.serverBuildTarget !== 'vercel') {
throw new Error(
`\`serverBuildTarget\` in Remix config must be "vercel" (got "${remixConfig.serverBuildTarget}")`
);
}
serverBuildPath = 'api/index.js';
needsHandler = false;
}
if (remixConfig.serverBuildPath) {
// Explicit file path where the server output file will be
serverBuildPath = remixConfig.serverBuildPath;
} else if (remixConfig.serverBuildDirectory) {
// Explicit directory path the server output will be
serverBuildPath = join(remixConfig.serverBuildDirectory, 'index.js');
}
// Also check for whether were in a monorepo.
// If we are, prepend the app root directory from config onto the build path.
// e.g. `/apps/my-remix-app/api/index.js`
const isMonorepo = repoRootPath && repoRootPath !== workPath;
if (isMonorepo) {
const rootDirectory = relative(repoRootPath, workPath);
serverBuildPath = join(rootDirectory, serverBuildPath);
}
}
remixConfig = await readConfig(entrypointFsDirname);
} finally {
// Clean up our patched `remix.config.js` to be polite
if (remixConfigPath && renamedRemixConfigPath) {
await fs.rename(renamedRemixConfigPath, remixConfigPath);
}
} catch (err: any) {
// Ignore error if `remix.config.js` does not exist
if (err.code !== 'MODULE_NOT_FOUND') throw err;
}
const { serverBuildPath, routes: remixRoutes } = remixConfig;
// Figure out which pages should be edge functions
const edgePages = new Set<ConfigRoute>();
const project = new Project();
for (const route of Object.values(remixRoutes)) {
const routePath = join(remixConfig.appDirectory, route.file);
const staticConfig = getConfig(project, routePath);
const isEdge =
staticConfig?.runtime === 'edge' ||
staticConfig?.runtime === 'experimental-edge';
if (isEdge) {
edgePages.add(route);
}
}
// This needs to happen before we run NFT to create the Node/Edge functions
await Promise.all([
ensureResolvable(
entrypointFsDirname,
repoRootPath,
'@remix-run/server-runtime'
),
ensureResolvable(entrypointFsDirname, repoRootPath, '@remix-run/node'),
]);
const [staticFiles, nodeFunction, edgeFunction] = await Promise.all([
const [staticFiles, renderFunction, ssrRoutes] = await Promise.all([
glob('**', join(entrypointFsDirname, 'public')),
createRenderNodeFunction(
createRenderFunction(
entrypointFsDirname,
repoRootPath,
serverBuildPath,
needsHandler,
nodeVersion
),
edgePages.size > 0
? createRenderEdgeFunction(
entrypointFsDirname,
repoRootPath,
serverBuildPath
)
: undefined,
getSsrRoutes(entrypointFsDirname),
]);
const output: BuildResultV2Typical['output'] = staticFiles;
const routes: any[] = [
{
src: '^/build/(.*)$',
headers: { 'cache-control': 'public, max-age=31536000, immutable' },
continue: true,
},
{
handle: 'filesystem',
},
];
for (const route of Object.values(remixRoutes)) {
// Layout routes don't get a function / route added
const isLayoutRoute = Object.values(remixRoutes).some(
r => r.parentId === route.id
);
if (isLayoutRoute) continue;
// Build up the full request path
let currentRoute: ConfigRoute | undefined = route;
const pathParts: string[] = [];
do {
if (currentRoute.index) pathParts.push('index');
if (currentRoute.path) pathParts.push(currentRoute.path);
if (currentRoute.parentId) {
currentRoute = remixRoutes[currentRoute.parentId];
} else {
currentRoute = undefined;
}
} while (currentRoute);
const path = join(...pathParts.reverse());
const isEdge = edgePages.has(route);
const fn =
isEdge && edgeFunction
? // `EdgeFunction` currently requires the "name" property to be set.
// Ideally this property will be removed, at which point we can
// return the same `edgeFunction` instance instead of creating a
// new one for each page.
new EdgeFunction({
...edgeFunction,
name: path,
})
: nodeFunction;
output[path] = fn;
// If this is a dynamic route then add a Vercel route
const keys: Key[] = [];
// Replace "/*" at the end to handle "splat routes"
const rePath = `/${path.replace(/\/\*$/, '/:params+')}`;
const re = pathToRegexp(rePath, keys);
if (keys.length > 0) {
routes.push({
src: re.source,
dest: path,
});
}
for (const path of ssrRoutes) {
output[path] = renderFunction;
}
// Add a 404 path for not found pages to be server-side rendered by Remix.
// Use the edge function if one was generated, otherwise use Node.js.
if (!output['404']) {
output['404'] = edgeFunction
? new EdgeFunction({ ...edgeFunction, name: '404' })
: nodeFunction;
}
routes.push({
src: '/(.*)',
dest: '/404',
});
// Add a 404 path for not found pages to be server-side rendered by Remix
output['404'] = renderFunction;
return { routes, output };
return {
routes: [
{
src: '^/build/(.*)$',
headers: { 'cache-control': 'public, max-age=31536000, immutable' },
continue: true,
},
{
handle: 'filesystem',
},
{
src: '/(.*)',
dest: '/404',
},
],
output,
};
};
function hasScript(scriptName: string, pkg: PackageJson | null) {
@@ -296,21 +251,24 @@ function hasScript(scriptName: string, pkg: PackageJson | null) {
return typeof scripts[scriptName] === 'string';
}
async function createRenderNodeFunction(
async function createRenderFunction(
entrypointDir: string,
rootDir: string,
serverBuildPath: string,
needsHandler: boolean,
nodeVersion: NodeVersion
): Promise<NodejsLambda> {
const files: Files = {};
const relativeServerBuildPath = relative(rootDir, serverBuildPath);
const handler = join(dirname(relativeServerBuildPath), 'server-node.mjs');
const handler = needsHandler
? join(dirname(serverBuildPath), '__vc_handler.js')
: serverBuildPath;
const handlerPath = join(rootDir, handler);
// Copy the `server-node.mjs` file into the "build" directory
const sourceHandlerPath = join(__dirname, '../server-node.mjs');
await fs.copyFile(sourceHandlerPath, handlerPath);
if (needsHandler) {
// Copy the `default-server.js` file into the "build" directory
const sourceHandlerPath = join(__dirname, '../default-server.js');
await fs.copyFile(sourceHandlerPath, handlerPath);
}
// Trace the handler with `@vercel/nft`
const trace = await nodeFileTrace([handlerPath], {
@@ -326,152 +284,41 @@ async function createRenderNodeFunction(
files[file] = await FileFsRef.fromFsPath({ fsPath: join(rootDir, file) });
}
const fn = new NodejsLambda({
const lambda = new NodejsLambda({
files,
handler,
runtime: nodeVersion.runtime,
shouldAddHelpers: false,
shouldAddSourcemapSupport: false,
operationType: 'SSR',
experimentalResponseStreaming: true,
});
return fn;
return lambda;
}
async function createRenderEdgeFunction(
entrypointDir: string,
rootDir: string,
serverBuildPath: string
): Promise<EdgeFunction> {
const files: Files = {};
const relativeServerBuildPath = relative(rootDir, serverBuildPath);
const handler = join(dirname(relativeServerBuildPath), 'server-edge.mjs');
const handlerPath = join(rootDir, handler);
// Copy the `server-edge.mjs` file into the "build" directory
const sourceHandlerPath = join(__dirname, '../server-edge.mjs');
await fs.copyFile(sourceHandlerPath, handlerPath);
// Trace the handler with `@vercel/nft`
const trace = await nodeFileTrace([handlerPath], {
base: rootDir,
processCwd: entrypointDir,
conditions: ['worker', 'browser'],
async readFile(fsPath) {
let source: Buffer | string;
try {
source = await fs.readFile(fsPath);
} catch (err: any) {
if (err.code === 'ENOENT' || err.code === 'EISDIR') {
return null;
}
throw err;
}
if (basename(fsPath) === 'package.json') {
// For Edge Functions, patch "main" field to prefer "browser" or "module"
const pkgJson = JSON.parse(source.toString());
for (const prop of ['browser', 'module']) {
const val = pkgJson[prop];
if (typeof val === 'string') {
pkgJson.main = val;
// Return the modified `package.json` to nft
source = JSON.stringify(pkgJson);
break;
}
}
}
return source;
},
});
for (const warning of trace.warnings) {
debug(`Warning from trace: ${warning.message}`);
}
for (const file of trace.fileList) {
files[file] = await FileFsRef.fromFsPath({ fsPath: join(rootDir, file) });
}
const fn = new EdgeFunction({
files,
deploymentTarget: 'v8-worker',
name: 'render',
entrypoint: handler,
});
return fn;
}
async function ensureResolvable(start: string, base: string, pkgName: string) {
try {
const resolvedPath = _require.resolve(pkgName, { paths: [start] });
if (!relative(base, resolvedPath).startsWith(`..${sep}`)) {
// Resolved path is within the root of the project, so all good
debug(`"${pkgName}" resolved to '${resolvedPath}'`);
return;
}
} catch (err: any) {
if (err.code !== 'MODULE_NOT_FOUND') {
throw err;
}
}
// If we got to here then `pkgName` was not resolvable up to the root
// of the project. Try a couple symlink tricks, otherwise we'll bail.
// Attempt to find the package in `node_modules/.pnpm` (pnpm)
const pnpmDir = await walkParentDirs({
base,
start,
filename: 'node_modules/.pnpm',
});
if (pnpmDir) {
const prefix = `${pkgName.replace('/', '+')}@`;
const packages = await fs.readdir(pnpmDir);
const match = packages.find(p => p.startsWith(prefix));
if (match) {
const pkgDir = join(pnpmDir, match, 'node_modules', pkgName);
const symlinkPath = join(pnpmDir, '..', pkgName);
const symlinkDir = dirname(symlinkPath);
const symlinkTarget = relative(symlinkDir, pkgDir);
await fs.mkdir(symlinkDir, { recursive: true });
await fs.symlink(symlinkTarget, symlinkPath);
console.warn(
`WARN: Created symlink for "${pkgName}". To silence this warning, add "${pkgName}" to "dependencies" in your \`package.json\` file.`
);
return;
}
}
// Attempt to find the package in `node_modules/.store` (npm 9+ linked mode)
const npmDir = await walkParentDirs({
base,
start,
filename: 'node_modules/.store',
});
if (npmDir) {
const prefix = `${basename(pkgName)}@`;
const prefixDir = join(npmDir, dirname(pkgName));
const packages = await fs.readdir(prefixDir);
const match = packages.find(p => p.startsWith(prefix));
if (match) {
const pkgDir = join(prefixDir, match, 'node_modules', pkgName);
const symlinkPath = join(npmDir, '..', pkgName);
const symlinkDir = dirname(symlinkPath);
const symlinkTarget = relative(symlinkDir, pkgDir);
await fs.mkdir(symlinkDir, { recursive: true });
await fs.symlink(symlinkTarget, symlinkPath);
console.warn(
`WARN: Created symlink for "${pkgName}". To silence this warning, add "${pkgName}" to "dependencies" in your \`package.json\` file.`
);
return;
}
}
throw new Error(
`Failed to resolve "${pkgName}". To fix this error, add "${pkgName}" to "dependencies" in your \`package.json\` file.`
async function getSsrRoutes(entrypointDir: string): Promise<string[]> {
// Find the name of the manifest file
const buildDir = join(entrypointDir, 'public/build');
const manifestFileName = (await fs.readdir(buildDir)).find(n =>
n.startsWith('manifest-')
);
if (!manifestFileName) {
throw new Error(`Failed to find manifest file in "${buildDir}"`);
}
const context: { window: { __remixManifest?: RemixBuildManifest } } = {
window: {},
};
createContext(context);
const code = await fs.readFile(join(buildDir, manifestFileName), 'utf8');
runInContext(code, context);
const routes = context.window.__remixManifest?.routes || {};
return Object.keys(routes)
.filter(id => id !== 'root')
.map(id => {
return routes[id].path || 'index';
});
}

View File

@@ -1,23 +1,39 @@
import { glob } from '@vercel/build-utils';
import { dirname, join, relative } from 'path';
import { readConfig } from '@remix-run/dev/dist/config';
import { glob } from '@vercel/build-utils';
import type { PrepareCache } from '@vercel/build-utils';
import type { AppConfig } from './types';
import { findConfig } from './utils';
export const prepareCache: PrepareCache = async ({
entrypoint,
repoRootPath,
workPath,
}) => {
const root = repoRootPath || workPath;
let cacheDirectory = '.cache';
const mountpoint = dirname(entrypoint);
const entrypointFsDirname = join(workPath, mountpoint);
const remixConfig = await readConfig(entrypointFsDirname);
try {
const remixConfigFile = findConfig(entrypointFsDirname, 'remix.config');
if (remixConfigFile) {
const remixConfigModule = await eval('import(remixConfigFile)');
const remixConfig: AppConfig = remixConfigModule?.default || {};
if (remixConfig.cacheDirectory) {
cacheDirectory = remixConfig.cacheDirectory;
}
}
} catch (err: any) {
// Ignore error if `remix.config.js` does not exist
if (err.code !== 'MODULE_NOT_FOUND') throw err;
}
const root = repoRootPath || workPath;
const [nodeModulesFiles, cacheDirFiles] = await Promise.all([
// Cache `node_modules`
glob('**/node_modules/**', root),
// Cache the Remix "cacheDirectory" (typically `.cache`)
glob(relative(root, join(remixConfig.cacheDirectory, '**')), root),
glob(relative(root, join(entrypointFsDirname, cacheDirectory, '**')), root),
]);
return { ...nodeModulesFiles, ...cacheDirFiles };

View File

@@ -0,0 +1,15 @@
// Stripped down version of `@remix-run/dev` AppConfig
export interface AppConfig {
cacheDirectory?: string;
serverBuildDirectory?: string;
serverBuildPath?: string;
serverBuildTarget?: string;
}
export interface RemixBuildManifest {
routes: {
[id: string]: {
path: string;
};
};
}

View File

@@ -1,11 +0,0 @@
export const config = {
runtime: 'edge'
};
export default function Edge() {
return (
<div style={{ fontFamily: "system-ui, sans-serif", lineHeight: "1.4" }}>
<h1>Welcome to Remix@Edge</h1>
</div>
);
}

View File

@@ -13,8 +13,8 @@
"@remix-run/node": "^1.7.4",
"@remix-run/react": "^1.7.4",
"@remix-run/serve": "^1.7.4",
"react": "18.2.0",
"react-dom": "18.2.0"
"react": "^17.0.2",
"react-dom": "^17.0.2"
},
"devDependencies": {
"@remix-run/dev": "^1.7.4",

View File

@@ -11,7 +11,6 @@
],
"probes": [
{ "path": "/", "mustContain": "Welcome to Remix" },
{ "path": "/edge", "mustContain": "Welcome to Remix@Edge" },
{ "path": "/b", "mustContain": "B page" },
{ "path": "/nested", "mustContain": "Nested index page" },
{ "path": "/nested/another", "mustContain": "Nested another page" },

View File

@@ -4733,6 +4733,11 @@ normalize-url@^6.0.1:
resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a"
integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==
object-assign@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
object-copy@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c"
@@ -5120,13 +5125,14 @@ raw-body@2.5.1, raw-body@^2.2.0:
iconv-lite "0.4.24"
unpipe "1.0.0"
react-dom@18.2.0:
version "18.2.0"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d"
integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==
react-dom@^17.0.2:
version "17.0.2"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23"
integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==
dependencies:
loose-envify "^1.1.0"
scheduler "^0.23.0"
object-assign "^4.1.1"
scheduler "^0.20.2"
react-router-dom@6.3.0:
version "6.3.0"
@@ -5143,12 +5149,13 @@ react-router@6.3.0:
dependencies:
history "^5.2.0"
react@18.2.0:
version "18.2.0"
resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5"
integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==
react@^17.0.2:
version "17.0.2"
resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037"
integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"
readable-stream@1.1.x:
version "1.1.14"
@@ -5447,12 +5454,13 @@ safe-regex@^1.1.0:
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
scheduler@^0.23.0:
version "0.23.0"
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe"
integrity sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==
scheduler@^0.20.2:
version "0.20.2"
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91"
integrity sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"
semver@^5.6.0:
version "5.7.1"

View File

@@ -1,12 +0,0 @@
export const config = {
runtime: 'edge'
};
export default function Edge() {
return (
<div style={{ fontFamily: "system-ui, sans-serif", lineHeight: "1.4" }}>
<h1>Welcome to Remix@Edge</h1>
</div>
);
}

View File

@@ -13,8 +13,8 @@
"@remix-run/node": "^1.7.4",
"@remix-run/react": "^1.7.4",
"@remix-run/serve": "^1.7.4",
"react": "18.2.0",
"react-dom": "18.2.0"
"react": "^17.0.2",
"react-dom": "^17.0.2"
},
"devDependencies": {
"@remix-run/dev": "^1.7.4",

View File

@@ -9,8 +9,5 @@
}
}
],
"probes": [
{ "path": "/", "mustContain": "Welcome to Remix" },
{ "path": "/edge", "mustContain": "Welcome to Remix@Edge" }
]
"probes": [{ "path": "/", "mustContain": "Welcome to Remix" }]
}

View File

@@ -4733,6 +4733,11 @@ normalize-url@^6.0.1:
resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a"
integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==
object-assign@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
object-copy@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c"
@@ -5120,13 +5125,14 @@ raw-body@2.5.1, raw-body@^2.2.0:
iconv-lite "0.4.24"
unpipe "1.0.0"
react-dom@18.2.0:
version "18.2.0"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d"
integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==
react-dom@^17.0.2:
version "17.0.2"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23"
integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==
dependencies:
loose-envify "^1.1.0"
scheduler "^0.23.0"
object-assign "^4.1.1"
scheduler "^0.20.2"
react-router-dom@6.3.0:
version "6.3.0"
@@ -5143,12 +5149,13 @@ react-router@6.3.0:
dependencies:
history "^5.2.0"
react@18.2.0:
version "18.2.0"
resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5"
integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==
react@^17.0.2:
version "17.0.2"
resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037"
integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"
readable-stream@1.1.x:
version "1.1.14"
@@ -5447,12 +5454,13 @@ safe-regex@^1.1.0:
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
scheduler@^0.23.0:
version "0.23.0"
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe"
integrity sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==
scheduler@^0.20.2:
version "0.20.2"
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91"
integrity sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==
dependencies:
loose-envify "^1.1.0"
object-assign "^4.1.1"
semver@^5.6.0:
version "5.7.1"

View File

@@ -1,6 +0,0 @@
node_modules
/.cache
/build
/public/build
.env

View File

@@ -1,53 +0,0 @@
# Welcome to Remix!
- [Remix Docs](https://remix.run/docs)
## Development
From your terminal:
```sh
npm run dev
```
This starts your app in development mode, rebuilding assets on file changes.
## Deployment
First, build your app for production:
```sh
npm run build
```
Then run the app in production mode:
```sh
npm start
```
Now you'll need to pick a host to deploy it to.
### DIY
If you're familiar with deploying node applications, the built-in Remix app server is production-ready.
Make sure to deploy the output of `remix build`
- `build/`
- `public/build/`
### Using a Template
When you ran `npx create-remix@latest` there were a few choices for hosting. You can run that again to create a new project, then copy over your `app/` folder to the new project that's pre-configured for your target server.
```sh
cd ..
# create a new project, and pick a pre-configured host
npx create-remix@latest
cd my-new-remix-app
# remove the new project's app (not the old one!)
rm -rf app
# copy your app over
cp -R ../my-old-remix-app/app app
```

View File

@@ -1,4 +0,0 @@
import { RemixBrowser } from "@remix-run/react";
import { hydrate } from "react-dom";
hydrate(<RemixBrowser />, document);

View File

@@ -1,21 +0,0 @@
import type { EntryContext } from "@remix-run/node";
import { RemixServer } from "@remix-run/react";
import { renderToString } from "react-dom/server";
export default function handleRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext
) {
let markup = renderToString(
<RemixServer context={remixContext} url={request.url} />
);
responseHeaders.set("Content-Type", "text/html");
return new Response("<!DOCTYPE html>" + markup, {
status: responseStatusCode,
headers: responseHeaders,
});
}

View File

@@ -1,32 +0,0 @@
import type { MetaFunction } from "@remix-run/node";
import {
Links,
LiveReload,
Meta,
Outlet,
Scripts,
ScrollRestoration,
} from "@remix-run/react";
export const meta: MetaFunction = () => ({
charset: "utf-8",
title: "New Remix App",
viewport: "width=device-width,initial-scale=1",
});
export default function App() {
return (
<html lang="en">
<head>
<Meta />
<Links />
</head>
<body>
<Outlet />
<ScrollRestoration />
<Scripts />
<LiveReload />
</body>
</html>
);
}

View File

@@ -1,7 +0,0 @@
export default function B() {
return (
<div style={{ fontFamily: "system-ui, sans-serif", lineHeight: "1.4" }}>
<h1>B page</h1>
</div>
);
}

View File

@@ -1,11 +0,0 @@
export const config = {
runtime: 'edge'
};
export default function Edge() {
return (
<div style={{ fontFamily: "system-ui, sans-serif", lineHeight: "1.4" }}>
<h1>Welcome to Remix@Edge</h1>
</div>
);
}

View File

@@ -1,32 +0,0 @@
export default function Index() {
return (
<div style={{ fontFamily: "system-ui, sans-serif", lineHeight: "1.4" }}>
<h1>Welcome to Remix</h1>
<ul>
<li>
<a
target="_blank"
href="https://remix.run/tutorials/blog"
rel="noreferrer"
>
15m Quickstart Blog Tutorial
</a>
</li>
<li>
<a
target="_blank"
href="https://remix.run/tutorials/jokes"
rel="noreferrer"
>
Deep Dive Jokes App Tutorial
</a>
</li>
<li>
<a target="_blank" href="https://remix.run/docs" rel="noreferrer">
Remix Docs
</a>
</li>
</ul>
</div>
);
}

View File

@@ -1,7 +0,0 @@
export default function Another() {
return (
<div style={{ fontFamily: "system-ui, sans-serif", lineHeight: "1.4" }}>
<h1>Nested another page</h1>
</div>
);
}

View File

@@ -1,7 +0,0 @@
export default function Nested() {
return (
<div style={{ fontFamily: "system-ui, sans-serif", lineHeight: "1.4" }}>
<h1>Nested index page</h1>
</div>
);
}

View File

@@ -1,27 +0,0 @@
{
"name": "remix-template-remix",
"private": true,
"description": "",
"license": "",
"sideEffects": false,
"scripts": {
"build": "remix build",
"dev": "remix dev",
"start": "remix-serve build"
},
"dependencies": {
"@remix-run/react": "^1.7.4",
"@remix-run/serve": "^1.7.4",
"react": "18.2.0",
"react-dom": "18.2.0"
},
"devDependencies": {
"@remix-run/dev": "^1.7.4",
"@types/react": "^17.0.45",
"@types/react-dom": "^17.0.17",
"typescript": "^4.6.4"
},
"engines": {
"node": ">=14"
}
}

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -1,10 +0,0 @@
/**
* @type {import('@remix-run/dev').AppConfig}
*/
module.exports = {
ignoredRouteFiles: ['**/.*'],
// appDirectory: "app",
// assetsBuildDirectory: "public/build",
// serverBuildPath: "build/index.js",
// publicPath: "/build/",
};

View File

@@ -1,2 +0,0 @@
/// <reference types="@remix-run/dev" />
/// <reference types="@remix-run/node/globals" />

View File

@@ -1,22 +0,0 @@
{
"include": ["remix.env.d.ts", "**/*.ts", "**/*.tsx"],
"compilerOptions": {
"lib": ["DOM", "DOM.Iterable", "ES2019"],
"isolatedModules": true,
"esModuleInterop": true,
"jsx": "react-jsx",
"moduleResolution": "node",
"resolveJsonModule": true,
"target": "ES2019",
"strict": true,
"allowJs": true,
"forceConsistentCasingInFileNames": true,
"baseUrl": ".",
"paths": {
"~/*": ["./app/*"]
},
// Remix takes care of building everything in `remix build`.
"noEmit": true
}
}

View File

@@ -1,21 +0,0 @@
{
"version": 2,
"builds": [
{
"src": "package.json",
"use": "@vercel/remix",
"config": {
"zeroConfig": true
}
}
],
"probes": [
{ "path": "/", "mustContain": "Welcome to Remix" },
{ "path": "/edge", "mustContain": "Welcome to Remix@Edge" },
{ "path": "/b", "mustContain": "B page" },
{ "path": "/nested", "mustContain": "Nested index page" },
{ "path": "/nested/another", "mustContain": "Nested another page" },
{ "path": "/nested/index", "mustContain": "Not Found" },
{ "path": "/asdf", "mustContain": "Not Found" }
]
}

View File

@@ -1,6 +0,0 @@
node_modules
/.cache
/build
/public/build
.env

View File

@@ -1,53 +0,0 @@
# Welcome to Remix!
- [Remix Docs](https://remix.run/docs)
## Development
From your terminal:
```sh
npm run dev
```
This starts your app in development mode, rebuilding assets on file changes.
## Deployment
First, build your app for production:
```sh
npm run build
```
Then run the app in production mode:
```sh
npm start
```
Now you'll need to pick a host to deploy it to.
### DIY
If you're familiar with deploying node applications, the built-in Remix app server is production-ready.
Make sure to deploy the output of `remix build`
- `build/`
- `public/build/`
### Using a Template
When you ran `npx create-remix@latest` there were a few choices for hosting. You can run that again to create a new project, then copy over your `app/` folder to the new project that's pre-configured for your target server.
```sh
cd ..
# create a new project, and pick a pre-configured host
npx create-remix@latest
cd my-new-remix-app
# remove the new project's app (not the old one!)
rm -rf app
# copy your app over
cp -R ../my-old-remix-app/app app
```

View File

@@ -1,4 +0,0 @@
import { RemixBrowser } from "@remix-run/react";
import { hydrate } from "react-dom";
hydrate(<RemixBrowser />, document);

View File

@@ -1,21 +0,0 @@
import type { EntryContext } from "@remix-run/node";
import { RemixServer } from "@remix-run/react";
import { renderToString } from "react-dom/server";
export default function handleRequest(
request: Request,
responseStatusCode: number,
responseHeaders: Headers,
remixContext: EntryContext
) {
let markup = renderToString(
<RemixServer context={remixContext} url={request.url} />
);
responseHeaders.set("Content-Type", "text/html");
return new Response("<!DOCTYPE html>" + markup, {
status: responseStatusCode,
headers: responseHeaders,
});
}

View File

@@ -1,32 +0,0 @@
import type { MetaFunction } from "@remix-run/node";
import {
Links,
LiveReload,
Meta,
Outlet,
Scripts,
ScrollRestoration,
} from "@remix-run/react";
export const meta: MetaFunction = () => ({
charset: "utf-8",
title: "New Remix App",
viewport: "width=device-width,initial-scale=1",
});
export default function App() {
return (
<html lang="en">
<head>
<Meta />
<Links />
</head>
<body>
<Outlet />
<ScrollRestoration />
<Scripts />
<LiveReload />
</body>
</html>
);
}

View File

@@ -1,7 +0,0 @@
export default function B() {
return (
<div style={{ fontFamily: "system-ui, sans-serif", lineHeight: "1.4" }}>
<h1>B page</h1>
</div>
);
}

View File

@@ -1,11 +0,0 @@
export const config = {
runtime: 'edge'
};
export default function Edge() {
return (
<div style={{ fontFamily: "system-ui, sans-serif", lineHeight: "1.4" }}>
<h1>Welcome to Remix@Edge</h1>
</div>
);
}

View File

@@ -1,32 +0,0 @@
export default function Index() {
return (
<div style={{ fontFamily: "system-ui, sans-serif", lineHeight: "1.4" }}>
<h1>Welcome to Remix</h1>
<ul>
<li>
<a
target="_blank"
href="https://remix.run/tutorials/blog"
rel="noreferrer"
>
15m Quickstart Blog Tutorial
</a>
</li>
<li>
<a
target="_blank"
href="https://remix.run/tutorials/jokes"
rel="noreferrer"
>
Deep Dive Jokes App Tutorial
</a>
</li>
<li>
<a target="_blank" href="https://remix.run/docs" rel="noreferrer">
Remix Docs
</a>
</li>
</ul>
</div>
);
}

View File

@@ -1,7 +0,0 @@
export default function Another() {
return (
<div style={{ fontFamily: "system-ui, sans-serif", lineHeight: "1.4" }}>
<h1>Nested another page</h1>
</div>
);
}

View File

@@ -1,7 +0,0 @@
export default function Nested() {
return (
<div style={{ fontFamily: "system-ui, sans-serif", lineHeight: "1.4" }}>
<h1>Nested index page</h1>
</div>
);
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,28 +0,0 @@
{
"name": "remix-with-npm9",
"private": true,
"description": "",
"license": "",
"sideEffects": false,
"packageManager": "npm@9.4.1",
"scripts": {
"build": "remix build",
"dev": "remix dev",
"start": "remix-serve build"
},
"dependencies": {
"@remix-run/react": "^1.7.4",
"@remix-run/serve": "^1.7.4",
"react": "18.2.0",
"react-dom": "18.2.0"
},
"devDependencies": {
"@remix-run/dev": "^1.7.4",
"@types/react": "^17.0.45",
"@types/react-dom": "^17.0.17",
"typescript": "^4.6.4"
},
"engines": {
"node": ">=14"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -1,10 +0,0 @@
/**
* @type {import('@remix-run/dev').AppConfig}
*/
module.exports = {
ignoredRouteFiles: ['**/.*'],
// appDirectory: "app",
// assetsBuildDirectory: "public/build",
// serverBuildPath: "build/index.js",
// publicPath: "/build/",
};

View File

@@ -1,2 +0,0 @@
/// <reference types="@remix-run/dev" />
/// <reference types="@remix-run/node/globals" />

View File

@@ -1,22 +0,0 @@
{
"include": ["remix.env.d.ts", "**/*.ts", "**/*.tsx"],
"compilerOptions": {
"lib": ["DOM", "DOM.Iterable", "ES2019"],
"isolatedModules": true,
"esModuleInterop": true,
"jsx": "react-jsx",
"moduleResolution": "node",
"resolveJsonModule": true,
"target": "ES2019",
"strict": true,
"allowJs": true,
"forceConsistentCasingInFileNames": true,
"baseUrl": ".",
"paths": {
"~/*": ["./app/*"]
},
// Remix takes care of building everything in `remix build`.
"noEmit": true
}
}

View File

@@ -1,27 +0,0 @@
{
"version": 2,
"builds": [
{
"src": "package.json",
"use": "@vercel/remix",
"config": {
"installCommand": "env | sort && npm install --install-strategy=linked",
"zeroConfig": true
}
}
],
"build": {
"env": {
"ENABLE_EXPERIMENTAL_COREPACK": "1"
}
},
"probes": [
{ "path": "/", "mustContain": "Welcome to Remix" },
{ "path": "/edge", "mustContain": "Welcome to Remix@Edge" },
{ "path": "/b", "mustContain": "B page" },
{ "path": "/nested", "mustContain": "Nested index page" },
{ "path": "/nested/another", "mustContain": "Nested another page" },
{ "path": "/nested/index", "mustContain": "Not Found" },
{ "path": "/asdf", "mustContain": "Not Found" }
]
}

View File

@@ -1,7 +1,7 @@
{
"name": "@vercel/ruby",
"author": "Nathan Cahill <nathan@nathancahill.com>",
"version": "1.3.63",
"version": "1.3.62",
"license": "MIT",
"main": "./dist/index",
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/ruby",
@@ -17,12 +17,12 @@
"scripts": {
"build": "node build",
"test": "jest --env node --verbose --runInBand --bail",
"test-e2e": "pnpm test"
"test-integration-once": "pnpm test"
},
"devDependencies": {
"@types/fs-extra": "8.0.0",
"@types/semver": "6.0.0",
"@vercel/build-utils": "6.2.3",
"@vercel/build-utils": "6.2.2",
"@vercel/ncc": "0.24.0",
"execa": "2.0.4",
"fs-extra": "^7.0.1",

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/static-build",
"version": "1.3.7",
"version": "1.3.6",
"license": "MIT",
"main": "./dist/index",
"homepage": "https://vercel.com/docs/build-step",
@@ -16,7 +16,7 @@
"build": "node build",
"test": "jest --env node --verbose --bail --runInBand",
"test-unit": "pnpm test test/build.test.ts test/gatsby.test.ts test/prepare-cache.test.ts",
"test-e2e": "pnpm test test/integration-*.test.js"
"test-integration-once": "pnpm test test/integration-*.test.js"
},
"jest": {
"preset": "ts-jest/presets/default",
@@ -30,7 +30,7 @@
},
"dependencies": {
"@vercel/gatsby-plugin-vercel-analytics": "1.0.7",
"@vercel/gatsby-plugin-vercel-builder": "1.1.5"
"@vercel/gatsby-plugin-vercel-builder": "1.1.4"
},
"devDependencies": {
"@types/aws-lambda": "8.10.64",
@@ -42,9 +42,9 @@
"@types/node-fetch": "2.5.4",
"@types/promise-timeout": "1.3.0",
"@types/semver": "7.3.13",
"@vercel/build-utils": "6.2.3",
"@vercel/build-utils": "6.2.2",
"@vercel/frameworks": "1.3.0",
"@vercel/fs-detectors": "3.7.12",
"@vercel/fs-detectors": "3.7.11",
"@vercel/ncc": "0.24.0",
"@vercel/routing-utils": "2.1.8",
"@vercel/static-config": "2.0.12",

2301
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -238,7 +238,7 @@ async function runProbe(probe, deploymentId, deploymentUrl, ctx) {
.join('\n');
throw new Error(
`Page ${probeUrl} does not have expected response header ${header}.\n\nExpected: ${expected}.\n\nActual: ${headers}`
`Page ${probeUrl} does not have header ${header}.\n\nExpected: ${expected}.\nActual: ${headers}`
);
}
});
@@ -254,7 +254,7 @@ async function runProbe(probe, deploymentId, deploymentUrl, ctx) {
.join('\n');
throw new Error(
`Page ${probeUrl} has unexpected response header ${header}.\n\nDid not expect: ${header}=${expected}.\n\nAll: ${headers}`
`Page ${probeUrl} invalid page header ${header}.\n\n Did not expect: ${header}=${expected}.\nBut got ${headers}`
);
}
});

View File

@@ -35,15 +35,15 @@
"dependsOn": ["build"],
"outputMode": "new-only"
},
"test-dev": {
"test-integration-dev": {
"dependsOn": ["build"],
"outputMode": "new-only"
},
"test-cli": {
"test-integration-cli": {
"dependsOn": ["build"],
"outputMode": "new-only"
},
"test-e2e": {
"test-integration-once": {
"dependsOn": ["build"],
"outputMode": "new-only"
},

View File

@@ -4,9 +4,9 @@ const path = require('path');
const NUMBER_OF_CHUNKS = 5;
const MINIMUM_PER_CHUNK = 1;
const runnersMap = new Map([
['test-e2e', ['ubuntu-latest']],
['test-integration-once', ['ubuntu-latest']],
['test-next-local', ['ubuntu-latest']],
['test-dev', ['ubuntu-latest', 'macos-latest']],
['test-integration-dev', ['ubuntu-latest', 'macos-latest']],
]);
async function getChunkedTests() {