mirror of
https://github.com/LukeHagar/vercel.git
synced 2025-12-06 04:22:01 +00:00
Follow-up to https://github.com/vercel/vercel/pull/10734 -- but considers that the static prefetch associated with `/` might be inside of a dir such as `index/index.prefetch.rsc`. To avoid any future matching conflicts, this PR updates to prefix all static prefetches
436 lines
12 KiB
TypeScript
436 lines
12 KiB
TypeScript
import path from 'path';
|
|
import os from 'os';
|
|
import {
|
|
excludeFiles,
|
|
validateEntrypoint,
|
|
normalizePackageJson,
|
|
getImagesConfig,
|
|
getNextConfig,
|
|
getServerlessPages,
|
|
normalizePrefetches,
|
|
} from '../../src/utils';
|
|
import { FileFsRef, FileRef } from '@vercel/build-utils';
|
|
import { genDir } from '../utils';
|
|
|
|
describe('getNextConfig', () => {
|
|
const workPath = path.join(__dirname, 'fixtures', '00-config');
|
|
const entryPath = path.join(workPath, 'entry');
|
|
|
|
it('should find entry file', async () => {
|
|
const file = await getNextConfig(workPath, entryPath);
|
|
expect(file).toMatchSnapshot();
|
|
});
|
|
|
|
it('should find work file second', async () => {
|
|
const file = await getNextConfig(workPath, '/');
|
|
expect(file).toMatchSnapshot();
|
|
});
|
|
|
|
it('return null on nothing', async () => {
|
|
const file = await getNextConfig('/', '/');
|
|
expect(file).toMatchSnapshot();
|
|
});
|
|
});
|
|
|
|
describe('getImagesConfig', () => {
|
|
it('should return undefined when undefined config', async () => {
|
|
const result = await getImagesConfig(undefined);
|
|
expect(result).toBeUndefined();
|
|
});
|
|
|
|
it('should return undefined when null config', async () => {
|
|
const result = await getImagesConfig(null);
|
|
expect(result).toBeUndefined();
|
|
});
|
|
|
|
it('should return undefined when empty object config', async () => {
|
|
const result = await getImagesConfig({ images: {} });
|
|
expect(result).toBeUndefined();
|
|
});
|
|
|
|
it('should return pass-through props when loader is default and unoptimized undefined', async () => {
|
|
const images = {
|
|
loader: 'default',
|
|
domains: ['example.com'],
|
|
sizes: [512, 1024],
|
|
remotePatterns: undefined,
|
|
formats: ['image/webp'],
|
|
minimumCacheTTL: 60,
|
|
dangerouslyAllowSVG: false,
|
|
contentSecurityPolicy: undefined,
|
|
contentDispositionType: undefined,
|
|
};
|
|
const result = await getImagesConfig({ images });
|
|
expect(result).toEqual({
|
|
domains: ['example.com'],
|
|
sizes: [512, 1024],
|
|
remotePatterns: undefined,
|
|
formats: ['image/webp'],
|
|
minimumCacheTTL: 60,
|
|
dangerouslyAllowSVG: false,
|
|
contentSecurityPolicy: undefined,
|
|
contentDispositionType: undefined,
|
|
});
|
|
});
|
|
|
|
it('should return pass-through props when loader is default and unoptimized false', async () => {
|
|
const images = {
|
|
unoptimized: false,
|
|
loader: 'default',
|
|
domains: ['example.com'],
|
|
sizes: [512, 1024],
|
|
remotePatterns: undefined,
|
|
formats: ['image/webp'],
|
|
minimumCacheTTL: 60,
|
|
dangerouslyAllowSVG: false,
|
|
contentSecurityPolicy: undefined,
|
|
contentDispositionType: 'attachment',
|
|
};
|
|
const result = await getImagesConfig({ images });
|
|
expect(result).toEqual({
|
|
domains: ['example.com'],
|
|
sizes: [512, 1024],
|
|
remotePatterns: undefined,
|
|
formats: ['image/webp'],
|
|
minimumCacheTTL: 60,
|
|
dangerouslyAllowSVG: false,
|
|
contentSecurityPolicy: undefined,
|
|
contentDispositionType: 'attachment',
|
|
});
|
|
});
|
|
|
|
it('return return undefined when loader is default and unoptimized true', async () => {
|
|
const images = {
|
|
unoptimized: true,
|
|
loader: 'default',
|
|
domains: ['example.com'],
|
|
sizes: [512, 1024],
|
|
remotePatterns: undefined,
|
|
formats: ['image/webp'],
|
|
minimumCacheTTL: 60,
|
|
dangerouslyAllowSVG: false,
|
|
contentSecurityPolicy: undefined,
|
|
contentDispositionType: undefined,
|
|
};
|
|
const result = await getImagesConfig({ images });
|
|
expect(result).toBeUndefined();
|
|
});
|
|
});
|
|
|
|
describe('excludeFiles', () => {
|
|
it('should exclude files', () => {
|
|
const files = {
|
|
'pages/index.js': new FileRef({ digest: 'index' }),
|
|
'package.json': new FileRef({ digest: 'package' }),
|
|
'package-lock.json': new FileRef({ digest: 'package-lock' }),
|
|
};
|
|
const result = excludeFiles(
|
|
files,
|
|
filePath => filePath === 'package-lock.json'
|
|
);
|
|
expect(result['pages/index.js']).toBeDefined();
|
|
expect(result['package.json']).toBeDefined();
|
|
expect(result['package-lock.json']).toBeUndefined();
|
|
});
|
|
});
|
|
|
|
describe('validateEntrypoint', () => {
|
|
it('should allow package.json', () => {
|
|
expect(validateEntrypoint('package.json')).toBeUndefined();
|
|
});
|
|
it('should allow nested package.json', () => {
|
|
expect(validateEntrypoint('frontend/package.json')).toBeUndefined();
|
|
});
|
|
it('should allow next.config.js', () => {
|
|
expect(validateEntrypoint('next.config.js')).toBeUndefined();
|
|
});
|
|
it('should allow nested next.config.js', () => {
|
|
expect(validateEntrypoint('frontend/next.config.js')).toBeUndefined();
|
|
});
|
|
it('should not allow pages/index.js', () => {
|
|
expect(() => validateEntrypoint('pages/index.js')).toThrow();
|
|
});
|
|
});
|
|
|
|
describe('normalizePackageJson', () => {
|
|
it('should work without a package.json being supplied', () => {
|
|
const result = normalizePackageJson();
|
|
expect(result).toEqual({
|
|
dependencies: {
|
|
'next-server': 'v7.0.2-canary.49',
|
|
react: 'latest',
|
|
'react-dom': 'latest',
|
|
},
|
|
devDependencies: {
|
|
next: 'v7.0.2-canary.49',
|
|
},
|
|
scripts: {
|
|
'now-build':
|
|
'NODE_OPTIONS=--max_old_space_size=3000 next build --lambdas',
|
|
},
|
|
});
|
|
});
|
|
|
|
it('should work with a package.json being supplied', () => {
|
|
const defaultPackage = {
|
|
dependencies: {
|
|
'next-server': 'v7.0.2-canary.49',
|
|
react: 'latest',
|
|
'react-dom': 'latest',
|
|
},
|
|
devDependencies: {
|
|
next: 'v7.0.2-canary.49',
|
|
},
|
|
scripts: {
|
|
'now-build': 'next build',
|
|
},
|
|
};
|
|
const result = normalizePackageJson(defaultPackage);
|
|
expect(result).toEqual({
|
|
dependencies: {
|
|
'next-server': 'v7.0.2-canary.49',
|
|
react: 'latest',
|
|
'react-dom': 'latest',
|
|
},
|
|
devDependencies: {
|
|
next: 'v7.0.2-canary.49',
|
|
},
|
|
scripts: {
|
|
'now-build':
|
|
'NODE_OPTIONS=--max_old_space_size=3000 next build --lambdas',
|
|
},
|
|
});
|
|
});
|
|
|
|
it('should force next@canary to be a devDependency', () => {
|
|
const defaultPackage = {
|
|
dependencies: {
|
|
react: 'latest',
|
|
'react-dom': 'latest',
|
|
next: 'latest',
|
|
},
|
|
};
|
|
const result = normalizePackageJson(defaultPackage);
|
|
expect(result).toEqual({
|
|
dependencies: {
|
|
'next-server': 'v7.0.2-canary.49',
|
|
react: 'latest',
|
|
'react-dom': 'latest',
|
|
},
|
|
devDependencies: {
|
|
next: 'v7.0.2-canary.49',
|
|
},
|
|
scripts: {
|
|
'now-build':
|
|
'NODE_OPTIONS=--max_old_space_size=3000 next build --lambdas',
|
|
},
|
|
});
|
|
});
|
|
|
|
it('should force next-server@canary to be a dependency', () => {
|
|
const defaultPackage = {
|
|
dependencies: {
|
|
react: 'latest',
|
|
'react-dom': 'latest',
|
|
next: 'latest',
|
|
},
|
|
};
|
|
const result = normalizePackageJson(defaultPackage);
|
|
expect(result).toEqual({
|
|
dependencies: {
|
|
'next-server': 'v7.0.2-canary.49',
|
|
react: 'latest',
|
|
'react-dom': 'latest',
|
|
},
|
|
devDependencies: {
|
|
next: 'v7.0.2-canary.49',
|
|
},
|
|
scripts: {
|
|
'now-build':
|
|
'NODE_OPTIONS=--max_old_space_size=3000 next build --lambdas',
|
|
},
|
|
});
|
|
});
|
|
|
|
it('should force now-build script', () => {
|
|
const defaultPackage = {
|
|
dependencies: {
|
|
react: 'latest',
|
|
'react-dom': 'latest',
|
|
next: 'latest',
|
|
},
|
|
};
|
|
const result = normalizePackageJson(defaultPackage);
|
|
expect(result).toEqual({
|
|
dependencies: {
|
|
'next-server': 'v7.0.2-canary.49',
|
|
react: 'latest',
|
|
'react-dom': 'latest',
|
|
},
|
|
devDependencies: {
|
|
next: 'v7.0.2-canary.49',
|
|
},
|
|
scripts: {
|
|
'now-build':
|
|
'NODE_OPTIONS=--max_old_space_size=3000 next build --lambdas',
|
|
},
|
|
});
|
|
});
|
|
|
|
// https://github.com/vercel/next.js/issues/5700
|
|
it('should normalize user report vercel/next.js#5700 correctly', () => {
|
|
const defaultPackage = {
|
|
version: '1.0.0',
|
|
scripts: {
|
|
dev: 'next',
|
|
build: 'next build',
|
|
start: 'next start',
|
|
test: "xo && stylelint './pages/**/*.js' && jest",
|
|
},
|
|
main: 'pages/index.js',
|
|
license: 'MIT',
|
|
devDependencies: {
|
|
'babel-plugin-styled-components': '^1.8.0',
|
|
'eslint-config-xo-react': '^0.17.0',
|
|
'eslint-plugin-react': '^7.11.1',
|
|
jest: '^23.6.0',
|
|
'jest-styled-components': '^6.3.1',
|
|
'react-test-renderer': '^16.6.3',
|
|
stylelint: '^9.8.0',
|
|
'stylelint-config-recommended': '^2.1.0',
|
|
'stylelint-config-styled-components': '^0.1.1',
|
|
'stylelint-processor-styled-components': '^1.5.1',
|
|
xo: '^0.23.0',
|
|
},
|
|
dependencies: {
|
|
consola: '^2.2.6',
|
|
fontfaceobserver: '^2.0.13',
|
|
next: '^7.0.2',
|
|
react: '^16.6.3',
|
|
'react-dom': '^16.6.3',
|
|
'styled-components': '^4.1.1',
|
|
},
|
|
xo: {
|
|
extends: 'xo-react',
|
|
envs: 'browser',
|
|
esnext: true,
|
|
ignores: [
|
|
'test',
|
|
'pages/_document.js',
|
|
'pages/index.js',
|
|
'pages/home.js',
|
|
],
|
|
rules: {
|
|
'react/no-unescaped-entities': null,
|
|
},
|
|
},
|
|
jest: {
|
|
testEnvironment: 'node',
|
|
},
|
|
};
|
|
const result = normalizePackageJson(defaultPackage);
|
|
expect(result).toEqual({
|
|
version: '1.0.0',
|
|
scripts: {
|
|
dev: 'next',
|
|
build: 'next build',
|
|
'now-build':
|
|
'NODE_OPTIONS=--max_old_space_size=3000 next build --lambdas',
|
|
start: 'next start',
|
|
test: "xo && stylelint './pages/**/*.js' && jest",
|
|
},
|
|
main: 'pages/index.js',
|
|
license: 'MIT',
|
|
devDependencies: {
|
|
'babel-plugin-styled-components': '^1.8.0',
|
|
'eslint-config-xo-react': '^0.17.0',
|
|
'eslint-plugin-react': '^7.11.1',
|
|
jest: '^23.6.0',
|
|
'jest-styled-components': '^6.3.1',
|
|
'react-test-renderer': '^16.6.3',
|
|
stylelint: '^9.8.0',
|
|
'stylelint-config-recommended': '^2.1.0',
|
|
'stylelint-config-styled-components': '^0.1.1',
|
|
'stylelint-processor-styled-components': '^1.5.1',
|
|
next: 'v7.0.2-canary.49',
|
|
'next-server': undefined,
|
|
xo: '^0.23.0',
|
|
consola: '^2.2.6',
|
|
fontfaceobserver: '^2.0.13',
|
|
'styled-components': '^4.1.1',
|
|
},
|
|
dependencies: {
|
|
'next-server': 'v7.0.2-canary.49',
|
|
react: '^16.6.3',
|
|
'react-dom': '^16.6.3',
|
|
},
|
|
xo: {
|
|
extends: 'xo-react',
|
|
envs: 'browser',
|
|
esnext: true,
|
|
ignores: [
|
|
'test',
|
|
'pages/_document.js',
|
|
'pages/index.js',
|
|
'pages/home.js',
|
|
],
|
|
rules: {
|
|
'react/no-unescaped-entities': null,
|
|
},
|
|
},
|
|
jest: {
|
|
testEnvironment: 'node',
|
|
},
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('getServerlessPages', () => {
|
|
it('should gather all pages correctly', async () => {
|
|
const dir = await genDir({
|
|
'.next/server/pages/_app.js': 'test',
|
|
'.next/server/pages/_error.js': 'test',
|
|
'.next/server/app/page.js': 'test',
|
|
'.next/server/app/favicon.ico/route.js': 'test',
|
|
});
|
|
|
|
const { pages, appPaths } = await getServerlessPages({
|
|
pagesDir: path.resolve(path.join(dir, '.next/server/pages')),
|
|
entryPath: os.tmpdir(),
|
|
outputDirectory: os.tmpdir(),
|
|
appPathRoutesManifest: {
|
|
'/_not-found': '/_not-found',
|
|
'/favicon.ico/route': '/favicon.ico',
|
|
'/page': '/',
|
|
},
|
|
});
|
|
|
|
expect(Object.keys(pages)).toEqual(['_app.js', '_error.js']);
|
|
expect(Object.keys(appPaths)).toEqual(['favicon.ico.js', 'index.js']);
|
|
});
|
|
});
|
|
|
|
describe('normalizePrefetches', () => {
|
|
it('should properly prefix prefetches with `__`', async () => {
|
|
const dummyFile = new FileFsRef({ fsPath: __dirname });
|
|
|
|
const appRscPrefetches = {
|
|
'index.prefetch.rsc': dummyFile,
|
|
'index/index.prefetch.rsc': dummyFile,
|
|
'foo.prefetch.rsc': dummyFile,
|
|
'foo/index.prefetch.rsc': dummyFile,
|
|
'foo/bar/baz.prefetch.rsc': dummyFile,
|
|
};
|
|
|
|
const updatedPrefetches = normalizePrefetches(appRscPrefetches);
|
|
|
|
expect(Object.keys(updatedPrefetches)).toEqual([
|
|
'__index.prefetch.rsc',
|
|
'index/__index.prefetch.rsc',
|
|
'__foo.prefetch.rsc',
|
|
'foo/__index.prefetch.rsc',
|
|
'foo/bar/__baz.prefetch.rsc',
|
|
]);
|
|
});
|
|
});
|