Compare commits

..

17 Commits

Author SHA1 Message Date
JJ Kasper
7470ff3724 Publish Stable
- @vercel/next@2.6.32
2020-10-27 09:30:43 -05:00
JJ Kasper
8340d9327c Publish Canary
- @vercel/next@2.6.32-canary.1
2020-10-27 09:11:04 -05:00
JJ Kasper
d278425810 Update tests for stabilized field (#5337) 2020-10-27 09:05:39 -05:00
JJ Kasper
8b26bbe643 [next] Add redirecting domain specific locales (#5333)
Co-authored-by: Joe Haddad <joe.haddad@zeit.co>
2020-10-27 11:32:08 +01:00
JJ Kasper
fa8e1e73c8 Ensure index GSP data is available at correct path (#5336) 2020-10-27 01:51:58 -05:00
JJ Kasper
f8abcbcd9f Remove unstable_ prefix from unstable_blocking (#5334) 2020-10-27 00:42:11 -05:00
Andy Bitz
e18ff683b2 Publish Canary
- @vercel/frameworks@0.1.2-canary.0
 - @vercel/build-utils@2.5.5-canary.0
 - vercel@20.1.3-canary.0
 - @vercel/client@9.0.4-canary.0
 - @vercel/redwood@0.1.2-canary.0
2020-10-26 16:22:53 +01:00
Andy
f28293a5a8 [frameworks] Add recommended integrations and related dependencies (#5330)
Adds the `recommendedIntegrations` property to the frameworks list with related dependencies.

Story https://app.clubhouse.io/vercel/story/13391
2020-10-26 15:10:40 +00:00
Steven
a4963a89c7 Publish Canary
- @vercel/next@2.6.32-canary.0
2020-10-25 16:58:01 -04:00
Steven
21df39fe8c [next] Image Optimization for default loader (#5321)
We currently pass through `images` whenever its defined, but this is enabling Image Optimization in the Proxy for every Next.js project.

Instead, we should check to see if the default loader is used (the same use for `next dev`) as a signal to enable this feature in the deployment.

Related to https://github.com/vercel/next.js/issues/18122
2020-10-24 12:55:53 +00:00
JJ Kasper
5ad9d61451 Publish Stable
- @vercel/next@2.6.31
2020-10-23 15:48:21 -05:00
JJ Kasper
8b5a2aa44f Publish Canary
- @vercel/next@2.6.31-canary.0
2020-10-23 15:17:30 -05:00
JJ Kasper
d0da1ce195 [next] Add handling for not found routes with i18n (#5313)
* Add handling for not found routes with i18n

* Update prerender lambda check
2020-10-23 14:34:17 -05:00
JJ Kasper
fd5d3b2921 Publish Stable
- @vercel/next@2.6.30
2020-10-20 13:11:20 -05:00
JJ Kasper
d22bdeb8d0 Publish Canary
- @vercel/next@2.6.30-canary.0
2020-10-20 12:59:12 -05:00
JJ Kasper
c120fd82f9 [next] Ensure root-most index GSP page is located correctly (#5309) 2020-10-20 19:58:18 +02:00
JJ Kasper
2474a80ff1 Correct i18n trailing slash redirect priority (#5306) 2020-10-20 11:01:31 -05:00
21 changed files with 415 additions and 36 deletions

View File

@@ -56,7 +56,13 @@
"outputDirectory": {
"placeholder": "Next.js default"
}
}
},
"recommendedIntegrations": [
{
"id": "oac_5lUsiANun1DEzgLg0NZx5Es3",
"dependencies": ["next-plugin-sentry", "next-sentry-source-maps"]
}
]
},
{
"name": "Gatsby.js",

View File

@@ -31,4 +31,8 @@ export interface Framework {
devCommand: Setting;
outputDirectory: Setting;
};
recommendedIntegrations?: {
id: string;
dependencies: string[];
}[];
}

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/frameworks",
"version": "0.1.1",
"version": "0.1.2-canary.0",
"main": "frameworks.json",
"license": "UNLICENSED",
"scripts": {

View File

@@ -97,6 +97,25 @@ const Schema = {
outputDirectory: SchemaSettings,
},
},
recommendedIntegrations: {
type: 'array',
items: {
type: 'object',
required: ['id', 'dependencies'],
additionalProperties: false,
properties: {
id: {
type: 'string',
},
dependencies: {
type: 'array',
items: {
type: 'string',
},
},
},
},
},
},
},
};

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/build-utils",
"version": "2.5.4",
"version": "2.5.5-canary.0",
"license": "MIT",
"main": "./dist/index.js",
"types": "./dist/index.d.js",
@@ -29,7 +29,7 @@
"@types/node-fetch": "^2.1.6",
"@types/semver": "6.0.0",
"@types/yazl": "^2.4.1",
"@vercel/frameworks": "0.1.1",
"@vercel/frameworks": "0.1.2-canary.0",
"@vercel/ncc": "0.24.0",
"aggregate-error": "3.0.1",
"async-retry": "1.2.3",

View File

@@ -1,6 +1,6 @@
{
"name": "vercel",
"version": "20.1.2",
"version": "20.1.3-canary.0",
"preferGlobal": true,
"license": "Apache-2.0",
"description": "The command-line interface for Vercel",
@@ -61,7 +61,7 @@
"node": ">= 10"
},
"dependencies": {
"@vercel/build-utils": "2.5.4",
"@vercel/build-utils": "2.5.5-canary.0",
"@vercel/go": "1.1.6",
"@vercel/node": "1.8.4",
"@vercel/python": "1.2.3",
@@ -100,7 +100,7 @@
"@types/universal-analytics": "0.4.2",
"@types/which": "1.3.2",
"@types/write-json-file": "2.2.1",
"@vercel/frameworks": "0.1.1",
"@vercel/frameworks": "0.1.2-canary.0",
"@vercel/ncc": "0.24.0",
"@zeit/fun": "0.11.2",
"@zeit/source-map-support": "0.6.2",

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/client",
"version": "9.0.3",
"version": "9.0.4-canary.0",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
"homepage": "https://vercel.com",
@@ -37,7 +37,7 @@
]
},
"dependencies": {
"@vercel/build-utils": "2.5.4",
"@vercel/build-utils": "2.5.5-canary.0",
"@zeit/fetch": "5.2.0",
"async-retry": "1.2.3",
"async-sema": "3.0.0",

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/next",
"version": "2.6.29",
"version": "2.6.32",
"license": "MIT",
"main": "./dist/index",
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/next-js",

View File

@@ -10,7 +10,7 @@ import {
PrepareCacheOptions,
Prerender,
} from '@vercel/build-utils';
import { Handler, Route } from '@vercel/routing-utils';
import { Handler, Route, Source } from '@vercel/routing-utils';
import {
convertHeaders,
convertRedirects,
@@ -655,12 +655,13 @@ export const build = async ({
return {
output,
images: imagesManifest?.images
? {
domains: imagesManifest.images.domains,
sizes: imagesManifest.images.sizes,
}
: undefined,
images:
imagesManifest?.images?.loader === 'default'
? {
domains: imagesManifest.images.domains,
sizes: imagesManifest.images.sizes,
}
: undefined,
routes: [
// User headers
...headers,
@@ -1651,12 +1652,17 @@ export const build = async ({
// if there isn't a srcRoute then it's a non-dynamic SSG page and
if (nonDynamicSsg || isFallback) {
routeFileNoExt = addLocaleOrDefault(
// root index files are located without folder/index.html
routeFileNoExt,
routesManifest,
locale
);
}
const isNotFound = prerenderManifest.notFoundRoutes.includes(
routeFileNoExt
);
const htmlFsRef = isBlocking
? // Blocking pages do not have an HTML fallback
null
@@ -1718,7 +1724,9 @@ export const build = async ({
if (nonDynamicSsg || isFallback) {
outputPathData = outputPathData.replace(
new RegExp(`${escapeStringRegexp(origRouteFileNoExt)}.json$`),
`${routeFileNoExt}.json`
`${routeFileNoExt}${
origRouteFileNoExt === '/index' ? '/index' : ''
}.json`
);
}
@@ -1744,7 +1752,7 @@ export const build = async ({
lambda = lambdas[outputSrcPathPage];
}
if (initialRevalidate === false) {
if (!isNotFound && initialRevalidate === false) {
if (htmlFsRef == null || jsonFsRef == null) {
throw new NowBuildError({
code: 'NEXT_HTMLFSREF_JSONFSREF',
@@ -1759,7 +1767,7 @@ export const build = async ({
}
}
if (prerenders[outputPathPage] == null) {
if (prerenders[outputPathPage] == null && !isNotFound) {
if (lambda == null) {
throw new NowBuildError({
code: 'NEXT_MISSING_LAMBDA',
@@ -1947,12 +1955,13 @@ export const build = async ({
};
})
: undefined,
images: imagesManifest?.images
? {
domains: imagesManifest.images.domains,
sizes: imagesManifest.images.sizes,
}
: undefined,
images:
imagesManifest?.images?.loader === 'default'
? {
domains: imagesManifest.images.domains,
sizes: imagesManifest.images.sizes,
}
: undefined,
/*
Desired routes order
- Runtime headers
@@ -1968,22 +1977,27 @@ export const build = async ({
...headers,
// redirects
...redirects.map(redir => {
...redirects.map(_redir => {
if (i18n) {
const redir = _redir as Source;
// detect the trailing slash redirect and make sure it's
// kept above the wildcard mapping to prevent erroneous redirects
// since non-continue routes come after continue the $wildcard
// route will come before the redirect otherwise and if the
// redirect is triggered it breaks locale mapping
const location =
redir.headers && (redir.headers.location || redir.headers.Location);
if (
redir.status === 308 &&
(redir.dest === '/$1' || redir.dest === '/$1/')
(location === '/$1' || location === '/$1/')
) {
// we set continue true
(redir as any).continue = true;
redir.continue = true;
}
}
return redir;
return _redir;
}),
...(i18n
@@ -2009,13 +2023,26 @@ export const build = async ({
{
// TODO: enable redirecting between domains, will require
// updating the src with the desired locales to redirect
src: '/',
src: `^${path.join(
'/',
entryDirectory
)}/?(?:${i18n.locales
.map(locale => escapeStringRegexp(locale))
.join('|')})?/?$`,
locale: {
redirect: i18n.domains.reduce(
(prev: Record<string, string>, item) => {
prev[item.defaultLocale] = `http${
item.http ? '' : 's'
}://${item.domain}/`;
if (item.locales) {
item.locales.map(locale => {
prev[locale] = `http${item.http ? '' : 's'}://${
item.domain
}/${locale}`;
});
}
return prev;
},
{}

View File

@@ -332,6 +332,7 @@ export type RoutesManifest = {
domains?: Array<{
http?: boolean;
domain: string;
locales?: string[];
defaultLocale: string;
}>;
};
@@ -511,9 +512,12 @@ export async function getDynamicRoutes(
return routes;
}
type LoaderKey = 'imgix' | 'cloudinary' | 'akamai' | 'default';
type ImagesManifest = {
version: number;
images: {
loader: LoaderKey;
sizes: number[];
domains: string[];
};
@@ -752,6 +756,8 @@ export type NextPrerenderedRoutes = {
};
omittedRoutes: string[];
notFoundRoutes: string[];
};
export async function getExportIntent(
@@ -842,6 +848,7 @@ export async function getPrerenderManifest(
fallbackRoutes: {},
bypassToken: null,
omittedRoutes: [],
notFoundRoutes: [],
};
}
@@ -887,6 +894,7 @@ export async function getPrerenderManifest(
preview: {
previewModeId: string;
};
notFoundRoutes?: string[];
} = JSON.parse(await fs.readFile(pathPrerenderManifest, 'utf8'));
switch (manifest.version) {
@@ -901,6 +909,7 @@ export async function getPrerenderManifest(
bypassToken:
(manifest.preview && manifest.preview.previewModeId) || null,
omittedRoutes: [],
notFoundRoutes: [],
};
routes.forEach(route => {
@@ -955,8 +964,13 @@ export async function getPrerenderManifest(
fallbackRoutes: {},
bypassToken: manifest.preview.previewModeId,
omittedRoutes: [],
notFoundRoutes: [],
};
if (manifest.notFoundRoutes) {
ret.notFoundRoutes.push(...manifest.notFoundRoutes);
}
routes.forEach(route => {
const {
initialRevalidateSeconds,
@@ -1010,6 +1024,7 @@ export async function getPrerenderManifest(
fallbackRoutes: {},
bypassToken: null,
omittedRoutes: [],
notFoundRoutes: [],
};
}
}
@@ -1110,7 +1125,9 @@ export function addLocaleOrDefault(
if (!routesManifest?.i18n) return pathname;
if (!locale) locale = routesManifest.i18n.defaultLocale;
return locale ? `/${locale}${pathname}` : pathname;
return locale
? `/${locale}${pathname === '/index' ? '' : pathname}`
: pathname;
}
export {

View File

@@ -1,4 +1,7 @@
module.exports = {
generateBuildId() {
return 'testing-build-id';
},
experimental: {
i18n: {
locales: ['nl-NL', 'nl-BE', 'nl', 'fr-BE', 'fr', 'en-US', 'en'],

View File

@@ -0,0 +1,50 @@
import Link from 'next/link';
import { useRouter } from 'next/router';
export default function Page(props) {
const router = useRouter();
if (router.isFallback) return 'Loading...';
return (
<>
<p id="gsp">gsp page</p>
<p id="props">{JSON.stringify(props)}</p>
<p id="router-locale">{router.locale}</p>
<p id="router-locales">{JSON.stringify(router.locales)}</p>
<p id="router-query">{JSON.stringify(router.query)}</p>
<p id="router-pathname">{router.pathname}</p>
<p id="router-as-path">{router.asPath}</p>
<Link href="/">
<a id="to-index">to /</a>
</Link>
<br />
</>
);
}
export const getStaticProps = ({ params, locale, locales }) => {
if (locale === 'en' || locale === 'nl') {
return {
notFound: true,
};
}
return {
props: {
params,
locale,
locales,
},
};
};
export const getStaticPaths = () => {
return {
// the default locale will be used since one isn't defined here
paths: ['first', 'second'].map(slug => ({
params: { slug },
})),
fallback: true,
};
};

View File

@@ -0,0 +1,37 @@
import Link from 'next/link';
import { useRouter } from 'next/router';
export default function Page(props) {
const router = useRouter();
return (
<>
<p id="gsp">gsp page</p>
<p id="props">{JSON.stringify(props)}</p>
<p id="router-locale">{router.locale}</p>
<p id="router-locales">{JSON.stringify(router.locales)}</p>
<p id="router-query">{JSON.stringify(router.query)}</p>
<p id="router-pathname">{router.pathname}</p>
<p id="router-as-path">{router.asPath}</p>
<Link href="/">
<a id="to-index">to /</a>
</Link>
<br />
</>
);
}
export const getStaticProps = ({ locale, locales }) => {
if (locale === 'en' || locale === 'nl') {
return {
notFound: true,
};
}
return {
props: {
locale,
locales,
},
};
};

View File

@@ -1,4 +1,7 @@
module.exports = {
generateBuildId() {
return 'testing-build-id';
},
experimental: {
i18n: {
locales: ['nl-NL', 'nl-BE', 'nl', 'fr-BE', 'fr', 'en-US', 'en'],

View File

@@ -310,6 +310,123 @@
"path": "/fr/gssp/first",
"status": 200,
"mustContain": "slug\":\"first\""
},
// TODO: update when directory listing is disabled
// and these are proper 404s
{
"path": "/en/not-found",
"status": 200,
"mustContain": "Index of"
},
{
"path": "/nl/not-found",
"status": 200,
"mustContain": "Index of"
},
{
"path": "/en-US/not-found",
"status": 200,
"mustContain": "lang=\"en-US\""
},
{
"path": "/nl-NL/not-found",
"status": 200,
"mustContain": "lang=\"nl-NL\""
},
{
"path": "/fr/not-found",
"status": 200,
"mustContain": "lang=\"fr\""
},
// this will always be a 200 unless fallback: blocking is used
// since the static fallback page is served before the 404
// page is rendered
{
"path": "/en/not-found/fallback/first",
"status": 200,
"mustContain": "lang=\"en\""
},
{
"path": "/en/not-found/fallback/first",
"status": 200,
"mustNotContain": "gsp page"
},
{
"path": "/_next/data/testing-build-id/en/not-found/fallback/first.json",
"status": 404
},
{
"path": "/en/not-found/fallback/first",
"status": 200,
"mustContain": "lang=\"en\""
},
{
"path": "/en/not-found/fallback/first",
"status": 200,
"mustNotContain": "gsp page"
},
{
"path": "/fr/not-found/fallback/first",
"status": 200,
"mustContain": "lang=\"fr\""
},
{
"path": "/_next/data/testing-build-id/fr/not-found/fallback/first.json",
"status": 200
},
{
"path": "/fr/not-found/fallback/first",
"status": 200,
"mustContain": "lang=\"fr\""
},
{
"path": "/fr/not-found/fallback/first",
"status": 200,
"mustContain": "gsp page"
},
{
"path": "/_next/data/testing-build-id/en-US/index.json",
"status": 200,
"mustContain": "\"locale\":\"en-US\""
},
{
"path": "/_next/data/testing-build-id/en/index.json",
"status": 200,
"mustContain": "\"locale\":\"en\""
},
{
"path": "/_next/data/testing-build-id/fr/index.json",
"status": 200,
"mustContain": "\"locale\":\"fr\""
},
{
"path": "/_next/data/testing-build-id/nl/index.json",
"status": 200,
"mustContain": "\"locale\":\"nl\""
},
{
"path": "/_next/data/testing-build-id/en-US/gsp.json",
"status": 200,
"mustContain": "\"locale\":\"en-US\""
},
{
"path": "/_next/data/testing-build-id/en/gsp.json",
"status": 200,
"mustContain": "\"locale\":\"en\""
},
{
"path": "/_next/data/testing-build-id/fr/gsp.json",
"status": 200,
"mustContain": "\"locale\":\"fr\""
},
{
"path": "/_next/data/testing-build-id/nl/gsp.json",
"status": 200,
"mustContain": "\"locale\":\"nl\""
}
]
}

View File

@@ -44,3 +44,12 @@ export default function Page(props) {
</>
);
}
export const getStaticProps = ({ locale, locales }) => {
return {
props: {
locale,
locales,
},
};
};

View File

@@ -0,0 +1,50 @@
import Link from 'next/link';
import { useRouter } from 'next/router';
export default function Page(props) {
const router = useRouter();
if (router.isFallback) return 'Loading...';
return (
<>
<p id="gsp">gsp page</p>
<p id="props">{JSON.stringify(props)}</p>
<p id="router-locale">{router.locale}</p>
<p id="router-locales">{JSON.stringify(router.locales)}</p>
<p id="router-query">{JSON.stringify(router.query)}</p>
<p id="router-pathname">{router.pathname}</p>
<p id="router-as-path">{router.asPath}</p>
<Link href="/">
<a id="to-index">to /</a>
</Link>
<br />
</>
);
}
export const getStaticProps = ({ params, locale, locales }) => {
if (locale === 'en' || locale === 'nl') {
return {
notFound: true,
};
}
return {
props: {
params,
locale,
locales,
},
};
};
export const getStaticPaths = () => {
return {
// the default locale will be used since one isn't defined here
paths: ['first', 'second'].map(slug => ({
params: { slug },
})),
fallback: true,
};
};

View File

@@ -0,0 +1,37 @@
import Link from 'next/link';
import { useRouter } from 'next/router';
export default function Page(props) {
const router = useRouter();
return (
<>
<p id="gsp">gsp page</p>
<p id="props">{JSON.stringify(props)}</p>
<p id="router-locale">{router.locale}</p>
<p id="router-locales">{JSON.stringify(router.locales)}</p>
<p id="router-query">{JSON.stringify(router.query)}</p>
<p id="router-pathname">{router.pathname}</p>
<p id="router-as-path">{router.asPath}</p>
<Link href="/">
<a id="to-index">to /</a>
</Link>
<br />
</>
);
}
export const getStaticProps = ({ locale, locales }) => {
if (locale === 'en' || locale === 'nl') {
return {
notFound: true,
};
}
return {
props: {
locale,
locales,
},
};
};

View File

@@ -19,5 +19,5 @@ export function getStaticProps({ params }) {
}
export function getStaticPaths() {
return { paths: [], fallback: 'unstable_blocking' };
return { paths: [], fallback: 'blocking' };
}

View File

@@ -19,5 +19,5 @@ export function getStaticProps({ params }) {
}
export function getStaticPaths() {
return { paths: [], fallback: 'unstable_blocking' };
return { paths: [], fallback: 'blocking' };
}

View File

@@ -1,6 +1,6 @@
{
"name": "@vercel/redwood",
"version": "0.1.1",
"version": "0.1.2-canary.0",
"main": "./dist/index.js",
"license": "MIT",
"homepage": "https://vercel.com/docs",
@@ -19,7 +19,7 @@
},
"dependencies": {
"@netlify/zip-it-and-ship-it": "1.2.0",
"@vercel/frameworks": "0.1.1"
"@vercel/frameworks": "0.1.2-canary.0"
},
"devDependencies": {
"@types/aws-lambda": "8.10.19",