Files
vercel/packages/frameworks/src/frameworks.ts
Chris Swithinbank 8b036e97ea [frameworks] Add default immutable cache path for Astro v2 (#9305)
Astro v2 was released today. It includes [improved support for caching
all hashed build
assets](https://docs.astro.build/en/guides/upgrade-to/v2/#changed-_astro-folder-for-build-assets)
by gathering these all in a single `_astro` directory in build output
(previously these ended up in a number of different places).

This PR updates the Vercel frameworks config to provide out-of-the-box
immutable caching for these assets.

Co-authored-by: Steven <steven@ceriously.com>
2023-01-24 19:05:13 -05:00

1960 lines
53 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { join } from 'path';
import { promises } from 'fs';
import { Framework } from './types';
import { readConfigFile } from './read-config-file';
export * from './types';
const { readdir, readFile, unlink } = promises;
/**
* Please note that is extremely important that the `dependency` property needs
* to reference a CLI. This is needed because you might want (for example) a
* Gatsby site that is powered by Preact, so you can't look for the `preact`
* dependency. Instead, you need to look for `preact-cli` when optimizing Preact
* CLI projects.
*/
export const frameworks = [
{
name: 'Blitz.js (Legacy)',
slug: 'blitzjs',
demo: 'https://blitz-template.vercel.app',
logo: 'https://api-frameworks.vercel.sh/framework-logos/blitz.svg',
tagline: 'Blitz.js: The Fullstack React Framework',
description:
'A brand new Blitz.js app - the result of running `npx blitz@0.45.4 new`.',
website: 'https://blitzjs.com',
envPrefix: 'NEXT_PUBLIC_',
useRuntime: { src: 'package.json', use: '@vercel/next' },
detectors: {
some: [
// Intentionally does not detect a package name
// https://github.com/vercel/vercel/pull/8432
{
path: 'blitz.config.js',
},
{
path: 'blitz.config.ts',
},
],
},
settings: {
installCommand: {
placeholder: '`yarn install`, `pnpm install`, or `npm install`',
},
buildCommand: {
placeholder: '`npm run build` or `blitz build`',
value: 'blitz build',
},
devCommand: {
value: 'blitz start',
},
outputDirectory: {
placeholder: 'Next.js default',
},
},
getOutputDirName: async () => 'public',
},
{
name: 'Next.js',
slug: 'nextjs',
demo: 'https://nextjs-template.vercel.app',
logo: 'https://api-frameworks.vercel.sh/framework-logos/next.svg',
darkModeLogo:
'https://api-frameworks.vercel.sh/framework-logos/next-dark.svg',
screenshot:
'https://assets.vercel.com/image/upload/v1673027027/front/import/nextjs.png',
tagline:
'Next.js makes you productive with React instantly — whether you want to build static or dynamic sites.',
description: 'A Next.js app and a Serverless Function API.',
website: 'https://nextjs.org',
sort: 1,
envPrefix: 'NEXT_PUBLIC_',
useRuntime: { src: 'package.json', use: '@vercel/next' },
detectors: {
every: [
{
matchPackage: 'next',
},
],
},
settings: {
installCommand: {
placeholder: '`yarn install`, `pnpm install`, or `npm install`',
},
buildCommand: {
placeholder: '`npm run build` or `next build`',
value: 'next build',
},
devCommand: {
value: 'next dev --port $PORT',
placeholder: 'next',
},
outputDirectory: {
placeholder: 'Next.js default',
},
},
recommendedIntegrations: [
{
id: 'oac_5lUsiANun1DEzgLg0NZx5Es3',
dependencies: ['next-plugin-sentry', 'next-sentry-source-maps'],
},
],
getOutputDirName: async () => 'public',
cachePattern: '.next/cache/**',
},
{
name: 'Gatsby.js',
slug: 'gatsby',
demo: 'https://gatsby.vercel.app',
logo: 'https://api-frameworks.vercel.sh/framework-logos/gatsby.svg',
tagline:
'Gatsby helps developers build blazing fast websites and apps with React.',
description: 'A Gatsby starter app with an API Route.',
website: 'https://gatsbyjs.org',
sort: 5,
envPrefix: 'GATSBY_',
detectors: {
every: [
{
matchPackage: 'gatsby',
},
],
},
settings: {
installCommand: {
placeholder: '`yarn install`, `pnpm install`, or `npm install`',
},
buildCommand: {
placeholder: '`npm run build` or `gatsby build`',
value: 'gatsby build',
},
devCommand: {
value: 'gatsby develop --port $PORT',
placeholder: 'gatsby develop',
},
outputDirectory: {
value: 'public',
},
},
dependency: 'gatsby',
getOutputDirName: async () => 'public',
defaultRoutes: async (dirPrefix: string) => {
// This file could be generated by gatsby-plugin-now or gatsby-plugin-zeit-now
try {
const nowRoutesPath = join(
dirPrefix,
'public',
'__now_routes_g4t5bY.json'
);
const content = await readFile(nowRoutesPath, 'utf8');
const nowRoutes = JSON.parse(content);
try {
await unlink(nowRoutesPath);
} catch (err) {
// do nothing if deleting the file fails
}
return nowRoutes;
} catch (err) {
// if the file doesn't exist, we implement gatsby's recommendations
// https://www.gatsbyjs.org/docs/caching
return [
{
src: '^/static/(.*)$',
headers: { 'cache-control': 'public,max-age=31536000,immutable' },
continue: true,
},
{
src: '^/.*\\.(js|css)$',
headers: { 'cache-control': 'public,max-age=31536000,immutable' },
continue: true,
},
{
src: '^/(sw\\.js|app-data\\.json|.*\\.html|page-data/.*)$',
headers: { 'cache-control': 'public,max-age=0,must-revalidate' },
continue: true,
},
{
handle: 'filesystem',
},
{
src: '.*',
status: 404,
dest: '404.html',
},
];
}
},
cachePattern: '{.cache,public}/**',
},
{
name: 'Remix',
slug: 'remix',
demo: 'https://remix-run-template.vercel.app',
logo: 'https://api-frameworks.vercel.sh/framework-logos/remix-no-shadow.svg',
tagline: 'Build Better Websites',
description: 'A new Remix app — the result of running `npx create-remix`.',
website: 'https://remix.run',
sort: 6,
useRuntime: { src: 'package.json', use: '@vercel/remix' },
ignoreRuntimes: ['@vercel/node'],
detectors: {
every: [
// Intentionally does not detect a package name
// https://github.com/vercel/vercel/pull/7761
{
path: 'remix.config.js',
},
],
},
settings: {
installCommand: {
placeholder: '`yarn install`, `pnpm install`, or `npm install`',
},
buildCommand: {
value: 'remix build',
placeholder: '`npm run build` or `remix build`',
},
devCommand: {
value: 'remix dev',
placeholder: 'remix dev',
},
outputDirectory: {
value: 'public',
},
},
dependency: 'remix',
getOutputDirName: async () => 'public',
},
{
name: 'Astro',
slug: 'astro',
demo: 'https://astro-template.vercel.app',
logo: 'https://api-frameworks.vercel.sh/framework-logos/astro.svg',
darkModeLogo:
'https://api-frameworks.vercel.sh/framework-logos/astro-dark.svg',
tagline:
'Astro is a new kind of static site builder for the modern web. Powerful developer experience meets lightweight output.',
description: 'An Astro site, using the basics starter kit.',
website: 'https://astro.build',
envPrefix: 'PUBLIC_',
detectors: {
every: [
{
matchPackage: 'astro',
},
],
},
settings: {
installCommand: {
placeholder: '`yarn install` or `npm install`',
},
buildCommand: {
value: 'astro build',
placeholder: '`npm run build` or `astro build`',
},
devCommand: {
value: 'astro dev --port $PORT',
placeholder: 'astro dev',
},
outputDirectory: {
value: 'dist',
},
},
dependency: 'astro',
getOutputDirName: async () => 'dist',
defaultRoutes: [
{
src: '^/assets/(.*)$',
headers: { 'cache-control': 'public, max-age=31536000, immutable' },
continue: true,
},
{
src: '^/_astro/(.*)$',
headers: { 'cache-control': 'public, max-age=31536000, immutable' },
continue: true,
},
],
},
{
name: 'Hexo',
slug: 'hexo',
demo: 'https://hexo-template.vercel.app',
logo: 'https://api-frameworks.vercel.sh/framework-logos/hexo.svg',
tagline:
'Hexo is a fast, simple & powerful blog framework powered by Node.js.',
description: 'A Hexo site, created with the Hexo CLI.',
website: 'https://hexo.io',
detectors: {
every: [
{
matchPackage: 'hexo',
},
],
},
settings: {
installCommand: {
placeholder: '`yarn install`, `pnpm install`, or `npm install`',
},
buildCommand: {
placeholder: '`npm run build` or `hexo generate`',
value: 'hexo generate',
},
devCommand: {
value: 'hexo server --port $PORT',
placeholder: 'hexo server',
},
outputDirectory: {
value: 'public',
},
},
dependency: 'hexo',
getOutputDirName: async () => 'public',
},
{
name: 'Eleventy',
slug: 'eleventy',
demo: 'https://eleventy-template.vercel.app',
logo: 'https://api-frameworks.vercel.sh/framework-logos/eleventy.svg',
tagline:
'11ty is a simpler static site generator written in JavaScript, created to be an alternative to Jekyll.',
description: 'An Eleventy site, created with npm init.',
website: 'https://www.11ty.dev',
detectors: {
every: [
{
matchPackage: '@11ty/eleventy',
},
],
},
settings: {
installCommand: {
placeholder: '`yarn install`, `pnpm install`, or `npm install`',
},
buildCommand: {
placeholder: '`npm run build` or `npx @11ty/eleventy`',
value: 'npx @11ty/eleventy',
},
devCommand: {
value: 'npx @11ty/eleventy --serve --watch --port $PORT',
placeholder: 'npx @11ty/eleventy --serve',
},
outputDirectory: {
value: '_site',
},
},
dependency: '@11ty/eleventy',
getOutputDirName: async () => '_site',
cachePattern: '.cache/**',
},
{
name: 'Docusaurus 2',
slug: 'docusaurus-2',
demo: 'https://docusaurus-2-template.vercel.app',
logo: 'https://api-frameworks.vercel.sh/framework-logos/docusaurus.svg',
tagline:
'Docusaurus makes it easy to maintain Open Source documentation websites.',
description:
'A static Docusaurus site that makes it easy to maintain OSS documentation.',
website: 'https://v2.docusaurus.io',
detectors: {
some: [
{
matchPackage: '@docusaurus/core',
},
],
},
settings: {
installCommand: {
placeholder: '`yarn install`, `pnpm install`, or `npm install`',
},
buildCommand: {
placeholder: '`npm run build` or `docusaurus build`',
value: 'docusaurus build',
},
devCommand: {
value: 'docusaurus start --port $PORT',
placeholder: 'docusaurus start',
},
outputDirectory: {
value: 'build',
},
},
dependency: '@docusaurus/core',
getOutputDirName: async (dirPrefix: string) => {
const base = 'build';
try {
const location = join(dirPrefix, base);
const content = await readdir(location, { withFileTypes: true });
// If there is only one file in it that is a dir we'll use it as dist dir
if (content.length === 1 && content[0].isDirectory()) {
return join(base, content[0].name);
}
} catch (error) {
console.error(`Error detecting output directory: `, error);
}
return base;
},
defaultRoutes: [
{
src: '^/[^./]+\\.[0-9a-f]{8}\\.(css|js)$',
headers: { 'cache-control': 'max-age=31536000, immutable' },
continue: true,
},
{
src: '^/assets/images/[^/]+-[0-9a-f]{32}\\.(ico|svg|jpg|jpeg|png|gif|webp)$',
headers: { 'cache-control': 'max-age=31536000, immutable' },
continue: true,
},
{
src: '^/assets/medias/[^/]+-[0-9a-f]{32}\\.(ogv|wav|mp3|m4a|aac|oga|flac)$',
headers: { 'cache-control': 'max-age=31536000, immutable' },
continue: true,
},
{
src: '^/assets/files/[^/]+-[0-9a-f]{32}\\.(pdf|doc|docx|xls|xlsx|zip|rar)$',
headers: { 'cache-control': 'max-age=31536000, immutable' },
continue: true,
},
{
src: '^/ideal-img/[^/]+\\.[0-9a-f]{7}\\.\\d+\\.(png|jpe?g|gif)$',
headers: { 'cache-control': 'max-age=31536000, immutable' },
continue: true,
},
{
handle: 'filesystem',
},
{
src: '.*',
status: 404,
dest: '404.html',
},
],
},
{
name: 'Docusaurus 1',
slug: 'docusaurus',
demo: 'https://docusaurus-template.vercel.app',
logo: 'https://api-frameworks.vercel.sh/framework-logos/docusaurus.svg',
tagline:
'Docusaurus makes it easy to maintain Open Source documentation websites.',
description:
'A static Docusaurus site that makes it easy to maintain OSS documentation.',
website: 'https://docusaurus.io/',
detectors: {
some: [
{
matchPackage: 'docusaurus',
},
],
},
settings: {
installCommand: {
placeholder: '`yarn install`, `pnpm install`, or `npm install`',
},
buildCommand: {
placeholder: '`npm run build` or `docusaurus-build`',
value: 'docusaurus-build',
},
devCommand: {
value: 'docusaurus-start --port $PORT',
placeholder: 'docusaurus-start',
},
outputDirectory: {
value: 'build',
},
},
dependency: 'docusaurus',
getOutputDirName: async (dirPrefix: string) => {
const base = 'build';
try {
const location = join(dirPrefix, base);
const content = await readdir(location, { withFileTypes: true });
// If there is only one file in it that is a dir we'll use it as dist dir
if (content.length === 1 && content[0].isDirectory()) {
return join(base, content[0].name);
}
} catch (error) {
console.error(`Error detecting output directory: `, error);
}
return base;
},
},
{
name: 'Preact',
slug: 'preact',
demo: 'https://preact-template.vercel.app',
logo: 'https://api-frameworks.vercel.sh/framework-logos/preact.svg',
tagline:
'Preact is a fast 3kB alternative to React with the same modern API.',
description: 'A Preact app, created with the Preact CLI.',
website: 'https://preactjs.com',
detectors: {
every: [
// Intentionally does not detect "preact" package because that can be
// used to power other frameworks.
{
matchPackage: 'preact-cli',
},
],
},
settings: {
installCommand: {
placeholder: '`yarn install`, `pnpm install`, or `npm install`',
},
buildCommand: {
placeholder: '`npm run build` or `preact build`',
value: 'preact build',
},
devCommand: {
value: 'preact watch --port $PORT',
placeholder: 'preact watch',
},
outputDirectory: {
value: 'build',
},
},
dependency: 'preact-cli',
getOutputDirName: async () => 'build',
defaultRoutes: [
{
handle: 'filesystem',
},
{
src: '/(.*)',
dest: '/index.html',
},
],
},
{
name: 'SolidStart',
slug: 'solidstart',
demo: 'https://solid-start-template.vercel.app',
logo: 'https://api-frameworks.vercel.sh/framework-logos/solid.svg',
tagline: 'Simple and performant reactivity for building user interfaces.',
description: 'A Solid app, created with SolidStart.',
website: 'https://solidjs.com',
envPrefix: 'VITE_',
detectors: {
every: [
{
matchPackage: 'solid-js',
},
{
matchPackage: 'solid-start',
},
],
},
settings: {
installCommand: {
placeholder: '`yarn install`, `pnpm install`, or `npm install`',
},
buildCommand: {
placeholder: '`npm run build` or `solid-start build`',
value: 'solid-start build',
},
devCommand: {
value: 'solid-start dev',
},
outputDirectory: {
value: '.output',
},
},
getOutputDirName: async () => '.output',
},
{
name: 'Dojo',
slug: 'dojo',
demo: 'https://dojo-template.vercel.app',
logo: 'https://api-frameworks.vercel.sh/framework-logos/dojo.png',
tagline: 'Dojo is a modern progressive, TypeScript first framework.',
description:
"A Dojo app, created with the Dojo CLI's cli-create-app command.",
website: 'https://dojo.io',
detectors: {
some: [
{
matchPackage: '@dojo/framework',
},
{
path: '.dojorc',
},
],
},
settings: {
installCommand: {
placeholder: '`yarn install`, `pnpm install`, or `npm install`',
},
buildCommand: {
placeholder: '`npm run build` or `dojo build`',
value: 'dojo build',
},
devCommand: {
value: 'dojo build -m dev -w -s -p $PORT',
placeholder: 'dojo build -m dev -w -s',
},
outputDirectory: {
value: 'output/dist',
},
},
dependency: '@dojo/cli',
getOutputDirName: async () => join('output', 'dist'),
defaultRoutes: [
{
handle: 'filesystem',
},
{
src: '/service-worker.js',
headers: { 'cache-control': 's-maxage=0' },
continue: true,
},
{
src: '/(.*)',
dest: '/index.html',
},
],
defaulHeaders: [
{
source: '/service-worker.js',
regex: '/service-worker.js',
headers: { 'cache-control': 's-maxage=0' },
continue: true,
},
],
},
{
name: 'Ember.js',
slug: 'ember',
demo: 'https://ember-template.vercel.app',
logo: 'https://api-frameworks.vercel.sh/framework-logos/ember.svg',
tagline:
'Ember.js helps webapp developers be more productive out of the box.',
description: 'An Ember app, created with the Ember CLI.',
website: 'https://emberjs.com/',
detectors: {
some: [
{
matchPackage: 'ember-source',
},
{
matchPackage: 'ember-cli',
},
],
},
settings: {
installCommand: {
placeholder: '`yarn install`, `pnpm install`, or `npm install`',
},
buildCommand: {
placeholder: '`npm run build` or `ember build`',
value: 'ember build',
},
devCommand: {
value: 'ember serve --port $PORT',
placeholder: 'ember serve',
},
outputDirectory: {
value: 'dist',
},
},
dependency: 'ember-cli',
getOutputDirName: async () => 'dist',
defaultRoutes: [
{
handle: 'filesystem',
},
{
src: '/(.*)',
dest: '/index.html',
},
],
},
{
name: 'Vue.js',
slug: 'vue',
demo: 'https://vue-template.vercel.app',
logo: 'https://api-frameworks.vercel.sh/framework-logos/vue.svg',
tagline:
'Vue.js is a versatile JavaScript framework that is as approachable as it is performant.',
description: 'A Vue.js app, created with the Vue CLI.',
website: 'https://vuejs.org',
envPrefix: 'VUE_APP_',
detectors: {
every: [
{
matchPackage: '@vue/cli-service',
},
],
},
settings: {
installCommand: {
placeholder: '`yarn install`, `pnpm install`, or `npm install`',
},
buildCommand: {
placeholder: '`npm run build` or `vue-cli-service build`',
value: 'vue-cli-service build',
},
devCommand: {
value: 'vue-cli-service serve --port $PORT',
placeholder: 'vue-cli-service serve',
},
outputDirectory: {
value: 'dist',
},
},
dependency: '@vue/cli-service',
getOutputDirName: async () => 'dist',
defaultRoutes: [
{
src: '^/[^/]*\\.(js|txt|ico|json)',
headers: { 'cache-control': 'max-age=300' },
continue: true,
},
{
src: '^/(img|js|css|fonts|media)/[^/]+\\.[0-9a-f]{8}\\.*',
headers: { 'cache-control': 'max-age=31536000, immutable' },
continue: true,
},
{
handle: 'filesystem',
},
{
src: '^.*',
dest: '/index.html',
},
],
},
{
name: 'Scully',
slug: 'scully',
demo: 'https://scully-template.vercel.app',
logo: 'https://api-frameworks.vercel.sh/framework-logos/scullyio-logo.png',
tagline: 'Scully is a static site generator for Angular.',
description: 'The Static Site Generator for Angular apps.',
website: 'https://github.com/scullyio/scully',
detectors: {
every: [
{
matchPackage: '@scullyio/init',
},
],
},
settings: {
installCommand: {
placeholder: '`yarn install`, `pnpm install`, or `npm install`',
},
buildCommand: {
placeholder: '`npm run build` or `ng build && scully`',
value: 'ng build && scully',
},
devCommand: {
value: 'ng serve --port $PORT',
placeholder: 'ng serve',
},
outputDirectory: {
value: 'dist',
},
},
dependency: '@scullyio/init',
getOutputDirName: async () => 'dist/static',
},
{
name: 'Ionic Angular',
slug: 'ionic-angular',
demo: 'https://ionic-angular-template.vercel.app',
logo: 'https://api-frameworks.vercel.sh/framework-logos/ionic.svg',
tagline:
'Ionic Angular allows you to build mobile PWAs with Angular and the Ionic Framework.',
description: 'An Ionic Angular site, created with the Ionic CLI.',
website: 'https://ionicframework.com',
detectors: {
every: [
{
matchPackage: '@ionic/angular',
},
],
},
settings: {
installCommand: {
placeholder: '`yarn install`, `pnpm install`, or `npm install`',
},
buildCommand: {
placeholder: '`npm run build` or `ng build`',
value: 'ng build',
},
devCommand: {
value: 'ng serve --port $PORT',
},
outputDirectory: {
value: 'www',
},
},
dependency: '@ionic/angular',
getOutputDirName: async () => 'www',
defaultRoutes: [
{
handle: 'filesystem',
},
{
src: '/(.*)',
dest: '/index.html',
},
],
},
{
name: 'Angular',
slug: 'angular',
demo: 'https://angular-template.vercel.app',
logo: 'https://api-frameworks.vercel.sh/framework-logos/angular.svg',
tagline:
'Angular is a TypeScript-based cross-platform framework from Google.',
description: 'An Angular app, created with the Angular CLI.',
website: 'https://angular.io',
detectors: {
every: [
{
matchPackage: '@angular/cli',
},
],
},
settings: {
installCommand: {
placeholder: '`yarn install`, `pnpm install`, or `npm install`',
},
buildCommand: {
placeholder: '`npm run build` or `ng build`',
value: 'ng build',
},
devCommand: {
value: 'ng serve --port $PORT',
placeholder: 'ng serve',
},
outputDirectory: {
value: 'dist',
},
},
dependency: '@angular/cli',
getOutputDirName: async (dirPrefix: string) => {
const base = 'dist';
try {
const location = join(dirPrefix, base);
const content = await readdir(location, { withFileTypes: true });
// If there is only one file in it that is a dir we'll use it as dist dir
if (content.length === 1 && content[0].isDirectory()) {
return join(base, content[0].name);
}
} catch (error) {
console.error(`Error detecting output directory: `, error);
}
return base;
},
defaultRoutes: [
{
handle: 'filesystem',
},
{
src: '/(.*)',
dest: '/index.html',
},
],
},
{
name: 'Polymer',
slug: 'polymer',
demo: 'https://polymer-template.vercel.app',
logo: 'https://api-frameworks.vercel.sh/framework-logos/polymer.svg',
tagline:
'Polymer is an open-source webapps library from Google, for building using Web Components.',
description: 'A Polymer app, created with the Polymer CLI.',
website: 'https://www.polymer-project.org/',
detectors: {
every: [
{
matchPackage: 'polymer-cli',
},
],
},
settings: {
installCommand: {
placeholder: '`yarn install`, `pnpm install`, or `npm install`',
},
buildCommand: {
placeholder: '`npm run build` or `polymer build`',
value: 'polymer build',
},
devCommand: {
value: 'polymer serve --port $PORT',
placeholder: 'polymer serve',
},
outputDirectory: {
value: 'build',
},
},
dependency: 'polymer-cli',
getOutputDirName: async (dirPrefix: string) => {
const base = 'build';
try {
const location = join(dirPrefix, base);
const content = await readdir(location);
const paths = content.filter(item => !item.includes('.'));
return join(base, paths[0]);
} catch (error) {
console.error(`Error detecting output directory: `, error);
}
return base;
},
defaultRoutes: [
{
handle: 'filesystem',
},
{
src: '/(.*)',
dest: '/index.html',
},
],
},
{
name: 'Svelte',
slug: 'svelte',
demo: 'https://svelte.vercel.app',
logo: 'https://api-frameworks.vercel.sh/framework-logos/svelte.svg',
tagline:
'Svelte lets you write high performance reactive apps with significantly less boilerplate.',
description: 'A basic Svelte app using the default template.',
website: 'https://svelte.dev',
sort: 3,
detectors: {
every: [
{
matchPackage: 'svelte',
},
{
matchPackage: 'sirv-cli',
},
],
},
settings: {
installCommand: {
placeholder: '`yarn install`, `pnpm install`, or `npm install`',
},
buildCommand: {
placeholder: '`npm run build` or `rollup -c`',
value: 'rollup -c',
},
devCommand: {
value: 'rollup -c -w',
},
outputDirectory: {
value: 'public',
},
},
dependency: 'sirv-cli',
getOutputDirName: async () => 'public',
defaultRoutes: [
{
handle: 'filesystem',
},
{
src: '/(.*)',
dest: '/index.html',
},
],
},
{
// TODO: fix detected as "sveltekit-1"
name: 'SvelteKit (Legacy Beta)',
slug: 'sveltekit',
demo: 'https://sveltekit-template.vercel.app',
logo: 'https://api-frameworks.vercel.sh/framework-logos/svelte.svg',
screenshot:
'https://assets.vercel.com/image/upload/v1647366075/front/import/sveltekit.png',
tagline:
'SvelteKit is a framework for building web applications of all sizes.',
description: 'A SvelteKit legacy app optimized Edge-first.',
website: 'https://kit.svelte.dev',
sort: 99,
envPrefix: 'VITE_',
detectors: {
every: [
{
path: 'package.json',
matchContent:
'"(dev)?(d|D)ependencies":\\s*{[^}]*"@sveltejs\\/kit":\\s*"1\\.0\\.0-next\\.(\\d+)"[^}]*}',
},
],
},
settings: {
installCommand: {
placeholder: '`yarn install`, `pnpm install`, or `npm install`',
},
buildCommand: {
placeholder: '`npm run build` or `svelte-kit build`',
value: 'svelte-kit build',
},
devCommand: {
value: 'svelte-kit dev --port $PORT',
placeholder: 'svelte-kit dev',
},
outputDirectory: {
value: 'public',
},
},
getOutputDirName: async () => 'public',
},
{
name: 'SvelteKit',
slug: 'sveltekit-1',
demo: 'https://sveltekit-1-template.vercel.app',
logo: 'https://api-frameworks.vercel.sh/framework-logos/svelte.svg',
screenshot:
'https://assets.vercel.com/image/upload/v1647366075/front/import/sveltekit.png',
tagline:
'SvelteKit is a framework for building web applications of all sizes.',
description: 'A SvelteKit app optimized Edge-first.',
website: 'https://kit.svelte.dev',
detectors: {
every: [
{
path: 'package.json',
matchContent:
'"(dev)?(d|D)ependencies":\\s*{[^}]*"@sveltejs\\/kit":\\s*".+?"[^}]*}',
},
],
},
settings: {
installCommand: {
placeholder: '`yarn install`, `pnpm install`, or `npm install`',
},
buildCommand: {
placeholder: 'vite build',
value: 'vite build',
},
devCommand: {
placeholder: 'vite dev',
value: 'vite dev --port $PORT',
},
outputDirectory: {
value: 'public',
},
},
getOutputDirName: async () => 'public',
},
{
name: 'Ionic React',
slug: 'ionic-react',
demo: 'https://ionic-react-template.vercel.app',
logo: 'https://api-frameworks.vercel.sh/framework-logos/ionic.svg',
tagline:
'Ionic React allows you to build mobile PWAs with React and the Ionic Framework.',
description: 'An Ionic React site, created with the Ionic CLI.',
website: 'https://ionicframework.com',
detectors: {
every: [
{
matchPackage: '@ionic/react',
},
],
},
settings: {
installCommand: {
placeholder: '`yarn install`, `pnpm install`, or `npm install`',
},
buildCommand: {
placeholder: '`npm run build` or `react-scripts build`',
value: 'react-scripts build',
},
devCommand: {
value: 'react-scripts start',
},
outputDirectory: {
value: 'build',
},
},
dependency: '@ionic/react',
getOutputDirName: async () => 'build',
defaultRoutes: [
{
src: '/static/(.*)',
headers: { 'cache-control': 's-maxage=31536000, immutable' },
continue: true,
},
{
src: '/service-worker.js',
headers: { 'cache-control': 's-maxage=0' },
continue: true,
},
{
src: '/sockjs-node/(.*)',
dest: '/sockjs-node/$1',
},
{
handle: 'filesystem',
},
{ src: '/static/(.*)', status: 404, dest: '/404.html' },
{
src: '/(.*)',
headers: { 'cache-control': 's-maxage=0' },
dest: '/index.html',
},
],
},
{
name: 'Create React App',
slug: 'create-react-app',
demo: 'https://create-react-template.vercel.app',
logo: 'https://api-frameworks.vercel.sh/framework-logos/react.svg',
tagline: 'Create React App allows you to get going with React in no time.',
description: 'A client-side React app created with create-react-app.',
website: 'https://create-react-app.dev',
sort: 4,
envPrefix: 'REACT_APP_',
detectors: {
some: [
{
matchPackage: 'react-scripts',
},
{
matchPackage: 'react-dev-utils',
},
],
},
settings: {
installCommand: {
placeholder: '`yarn install`, `pnpm install`, or `npm install`',
},
buildCommand: {
placeholder: '`npm run build` or `react-scripts build`',
value: 'react-scripts build',
},
devCommand: {
value: 'react-scripts start',
},
outputDirectory: {
value: 'build',
},
},
dependency: 'react-scripts',
getOutputDirName: async () => 'build',
defaultRoutes: [
{
src: '/static/(.*)',
headers: { 'cache-control': 's-maxage=31536000, immutable' },
continue: true,
},
{
src: '/service-worker.js',
headers: { 'cache-control': 's-maxage=0' },
continue: true,
},
{
src: '/sockjs-node/(.*)',
dest: '/sockjs-node/$1',
},
{
handle: 'filesystem',
},
{ src: '/static/(.*)', status: 404, dest: '/404.html' },
{
src: '/(.*)',
headers: { 'cache-control': 's-maxage=0' },
dest: '/index.html',
},
],
},
{
name: 'Gridsome',
slug: 'gridsome',
demo: 'https://gridsome-template.vercel.app',
logo: 'https://api-frameworks.vercel.sh/framework-logos/gridsome.svg',
tagline:
'Gridsome is a Vue.js-powered framework for building websites & apps that are fast by default.',
description: 'A Gridsome app, created with the Gridsome CLI.',
website: 'https://gridsome.org/',
detectors: {
every: [
{
matchPackage: 'gridsome',
},
],
},
settings: {
installCommand: {
placeholder: '`yarn install`, `pnpm install`, or `npm install`',
},
buildCommand: {
placeholder: '`npm run build` or `gridsome build`',
value: 'gridsome build',
},
devCommand: {
value: 'gridsome develop -p $PORT',
placeholder: 'gridsome develop',
},
outputDirectory: {
value: 'dist',
},
},
dependency: 'gridsome',
getOutputDirName: async () => 'dist',
},
{
name: 'UmiJS',
slug: 'umijs',
demo: 'https://umijs-template.vercel.app',
logo: 'https://api-frameworks.vercel.sh/framework-logos/umi.svg',
tagline:
'UmiJS is an extensible enterprise-level React application framework.',
description: 'An UmiJS app, created using the Umi CLI.',
website: 'https://umijs.org',
detectors: {
every: [
{
matchPackage: 'umi',
},
],
},
settings: {
installCommand: {
placeholder: '`yarn install`, `pnpm install`, or `npm install`',
},
buildCommand: {
placeholder: '`npm run build` or `umi build`',
value: 'umi build',
},
devCommand: {
value: 'umi dev --port $PORT',
placeholder: 'umi dev',
},
outputDirectory: {
value: 'dist',
},
},
dependency: 'umi',
getOutputDirName: async () => 'dist',
defaultRoutes: [
{
handle: 'filesystem',
},
{
src: '/(.*)',
dest: '/index.html',
},
],
},
{
name: 'Sapper',
slug: 'sapper',
demo: 'https://sapper-template.vercel.app',
logo: 'https://api-frameworks.vercel.sh/framework-logos/svelte.svg',
tagline:
'Sapper is a framework for building high-performance universal web apps with Svelte.',
description: 'A Sapper app, using the Sapper template.',
website: 'https://sapper.svelte.dev',
detectors: {
every: [
{
matchPackage: 'sapper',
},
],
},
settings: {
installCommand: {
placeholder: '`yarn install`, `pnpm install`, or `npm install`',
},
buildCommand: {
placeholder: '`npm run build` or `sapper export`',
value: 'sapper export',
},
devCommand: {
value: 'sapper dev --port $PORT',
placeholder: 'sapper dev',
},
outputDirectory: {
value: '__sapper__/export',
},
},
dependency: 'sapper',
getOutputDirName: async () => '__sapper__/export',
},
{
name: 'Saber',
slug: 'saber',
demo: 'https://saber-template.vercel.app',
logo: 'https://api-frameworks.vercel.sh/framework-logos/saber.svg',
tagline:
'Saber is a framework for building static sites in Vue.js that supports data from any source.',
description: 'A Saber site, created with npm init.',
website: 'https://saber.land/',
detectors: {
every: [
{
matchPackage: 'saber',
},
],
},
settings: {
installCommand: {
placeholder: '`yarn install`, `pnpm install`, or `npm install`',
},
buildCommand: {
placeholder: '`npm run build` or `saber build`',
value: 'saber build',
},
devCommand: {
value: 'saber --port $PORT',
placeholder: 'saber',
},
outputDirectory: {
value: 'public',
},
},
dependency: 'saber',
getOutputDirName: async () => 'public',
defaultRoutes: [
{
src: '/_saber/.*',
headers: { 'cache-control': 'max-age=31536000, immutable' },
},
{
handle: 'filesystem',
},
{
src: '.*',
status: 404,
dest: '404.html',
},
],
},
{
name: 'Stencil',
slug: 'stencil',
demo: 'https://stencil.vercel.app',
logo: 'https://api-frameworks.vercel.sh/framework-logos/stencil.svg',
tagline:
'Stencil is a powerful toolchain for building Progressive Web Apps and Design Systems.',
description: 'A Stencil site, created with the Stencil CLI.',
website: 'https://stenciljs.com/',
detectors: {
every: [
{
matchPackage: '@stencil/core',
},
],
},
settings: {
installCommand: {
placeholder: '`yarn install`, `pnpm install`, or `npm install`',
},
buildCommand: {
placeholder: '`npm run build` or `stencil build`',
value: 'stencil build',
},
devCommand: {
value: 'stencil build --dev --watch --serve --port $PORT',
placeholder: 'stencil build --dev --watch --serve',
},
outputDirectory: {
value: 'www',
},
},
dependency: '@stencil/core',
getOutputDirName: async () => 'www',
defaultRoutes: [
{
src: '/assets/(.*)',
headers: { 'cache-control': 'max-age=2592000' },
continue: true,
},
{
src: '/build/p-.*',
headers: { 'cache-control': 'max-age=31536000, immutable' },
continue: true,
},
{
src: '/sw.js',
headers: { 'cache-control': 'no-cache' },
continue: true,
},
{
handle: 'filesystem',
},
{
src: '/(.*)',
dest: '/index.html',
},
],
},
{
name: 'Nuxt.js',
slug: 'nuxtjs',
demo: 'https://nuxtjs-template.vercel.app',
logo: 'https://api-frameworks.vercel.sh/framework-logos/nuxt.svg',
screenshot:
'https://assets.vercel.com/image/upload/v1647366075/front/import/nuxtjs.png',
tagline:
'Nuxt.js is the web comprehensive framework that lets you dream big with Vue.js.',
description: 'A Nuxt.js app, bootstrapped with create-nuxt-app.',
website: 'https://nuxtjs.org',
sort: 2,
envPrefix: 'NUXT_ENV_',
detectors: {
some: [
{
matchPackage: 'nuxt',
},
{
matchPackage: 'nuxt3',
},
{
matchPackage: 'nuxt-edge',
},
],
},
settings: {
installCommand: {
placeholder: '`yarn install`, `pnpm install`, or `npm install`',
},
buildCommand: {
placeholder: '`npm run build` or `nuxt generate`',
value: 'nuxt generate',
},
devCommand: {
value: 'nuxt',
},
outputDirectory: {
value: 'dist',
},
},
dependency: 'nuxt',
getOutputDirName: async () => 'dist',
cachePattern: '.nuxt/**',
defaultRoutes: [
{
src: '/sw.js',
headers: { 'cache-control': 'no-cache' },
continue: true,
},
{
src: '/_nuxt/(.*)',
headers: { 'cache-control': 'public,max-age=31536000,immutable' },
continue: true,
},
{
handle: 'filesystem',
},
{
src: '/(.*)',
dest: '/200.html',
},
],
},
{
name: 'RedwoodJS',
slug: 'redwoodjs',
demo: 'https://redwood-template.vercel.app',
logo: 'https://api-frameworks.vercel.sh/framework-logos/redwoodjs.svg',
tagline: 'RedwoodJS is a full-stack framework for the Jamstack.',
description: 'A RedwoodJS app, bootstraped with create-redwood-app.',
website: 'https://redwoodjs.com',
envPrefix: 'REDWOOD_ENV_',
useRuntime: { src: 'package.json', use: '@vercel/redwood' },
ignoreRuntimes: ['@vercel/node'],
detectors: {
every: [
{
matchPackage: '@redwoodjs/core',
},
],
},
settings: {
installCommand: {
placeholder: '`yarn install`, `pnpm install`, or `npm install`',
},
buildCommand: {
value: 'yarn rw deploy vercel',
},
devCommand: {
value: 'yarn rw dev --fwd="--port=$PORT --open=false"',
placeholder: 'yarn rw dev',
},
outputDirectory: {
placeholder: 'RedwoodJS default',
},
},
getOutputDirName: async () => 'public',
},
{
name: 'Hugo',
slug: 'hugo',
demo: 'https://hugo-template.vercel.app',
logo: 'https://api-frameworks.vercel.sh/framework-logos/hugo.svg',
tagline:
'Hugo is the worlds fastest framework for building websites, written in Go.',
description: 'A Hugo site, created with the Hugo CLI.',
website: 'https://gohugo.io',
detectors: {
some: [
{
path: 'config.yaml',
matchContent: 'baseURL',
},
{
path: 'config.toml',
matchContent: 'baseURL',
},
{
path: 'config.json',
matchContent: 'baseURL',
},
],
},
settings: {
installCommand: {
placeholder: 'None',
},
buildCommand: {
placeholder: '`npm run build` or `hugo -D --gc`',
value: 'hugo -D --gc',
},
devCommand: {
value: 'hugo server -D -w -p $PORT',
placeholder: 'hugo server -D',
},
outputDirectory: {
placeholder: '`public` or `publishDir` from the `config` file',
},
},
getOutputDirName: async (dirPrefix: string): Promise<string> => {
type HugoConfig = { publishDir?: string };
const config = await readConfigFile<HugoConfig>(
['config.json', 'config.yaml', 'config.toml'].map(fileName => {
return join(dirPrefix, fileName);
})
);
return (config && config.publishDir) || 'public';
},
defaultVersion: '0.58.2', // Must match the build image
},
{
name: 'Jekyll',
slug: 'jekyll',
demo: 'https://jekyll-template.vercel.app',
logo: 'https://api-frameworks.vercel.sh/framework-logos/jekyll.svg',
tagline:
'Jekyll makes it super easy to transform your plain text into static websites and blogs.',
description: 'A Jekyll site, created with the Jekyll CLI.',
website: 'https://jekyllrb.com/',
detectors: {
every: [
{
path: '_config.yml',
},
],
},
settings: {
installCommand: {
value: 'bundle install',
},
buildCommand: {
placeholder: '`npm run build` or `jekyll build`',
value: 'jekyll build',
},
devCommand: {
value: 'bundle exec jekyll serve --watch --port $PORT',
placeholder: 'bundle exec jekyll serve',
},
outputDirectory: {
placeholder: '`_site` or `destination` from `_config.yml`',
},
},
getOutputDirName: async (dirPrefix: string): Promise<string> => {
type JekyllConfig = { destination?: string };
const config = await readConfigFile<JekyllConfig>(
join(dirPrefix, '_config.yml')
);
return (config && config.destination) || '_site';
},
cachePattern: '{vendor/bin,vendor/cache,vendor/bundle}/**',
},
{
name: 'Brunch',
slug: 'brunch',
demo: 'https://brunch-template.vercel.app',
logo: 'https://api-frameworks.vercel.sh/framework-logos/brunch.svg',
tagline:
'Brunch is a fast and simple webapp build tool with seamless incremental compilation for rapid development.',
description: 'A Brunch app, created with the Brunch CLI.',
website: 'https://brunch.io/',
detectors: {
some: [
{
matchPackage: 'brunch',
},
{
path: 'brunch-config.js',
},
],
},
settings: {
installCommand: {
placeholder: '`yarn install`, `pnpm install`, or `npm install`',
},
buildCommand: {
placeholder: '`npm run build` or `brunch build --production`',
value: 'brunch build --production',
},
devCommand: {
value: 'brunch watch --server --port $PORT',
placeholder: 'brunch watch --server',
},
outputDirectory: {
value: 'public',
},
},
getOutputDirName: async () => 'public',
},
{
name: 'Middleman',
slug: 'middleman',
demo: 'https://middleman-template.vercel.app',
logo: 'https://api-frameworks.vercel.sh/framework-logos/middleman.svg',
tagline:
'Middleman is a static site generator that uses all the shortcuts and tools in modern web development.',
description: 'A Middleman app, created with the Middleman CLI.',
website: 'https://middlemanapp.com/',
detectors: {
every: [
{
path: 'config.rb',
},
],
},
settings: {
installCommand: {
value: 'bundle install',
},
buildCommand: {
placeholder: '`npm run build` or `bundle exec middleman build`',
value: 'bundle exec middleman build',
},
devCommand: {
placeholder: 'bundle exec middleman server',
value: 'bundle exec middleman server -p $PORT',
},
outputDirectory: {
value: 'build',
},
},
getOutputDirName: async () => 'build',
cachePattern: '{vendor/bin,vendor/cache,vendor/bundle}/**',
},
{
name: 'Zola',
slug: 'zola',
demo: 'https://zola-template.vercel.app',
logo: 'https://api-frameworks.vercel.sh/framework-logos/zola.png',
tagline: 'Everything you need to make a static site engine in one binary.',
description: 'A Zola app, created with the "Getting Started" tutorial.',
website: 'https://www.getzola.org',
detectors: {
every: [
{
path: 'config.toml',
matchContent: 'base_url',
},
],
},
settings: {
installCommand: {
placeholder: 'None',
},
buildCommand: {
value: 'zola build',
},
devCommand: {
placeholder: 'zola serve',
value: 'zola serve --port $PORT',
},
outputDirectory: {
value: 'public',
},
},
getOutputDirName: async () => 'public',
defaultVersion: '0.13.0', // Must match the build image
},
{
name: 'Hydrogen',
slug: 'hydrogen',
demo: 'https://hydrogen-template.vercel.app',
logo: 'https://api-frameworks.vercel.sh/framework-logos/hydrogen.svg',
tagline: 'React framework for headless commerce',
description: 'React framework for headless commerce',
website: 'https://hydrogen.shopify.dev',
useRuntime: { src: 'package.json', use: '@vercel/hydrogen' },
detectors: {
some: [
{
matchPackage: '@shopify/hydrogen',
},
{
path: 'hydrogen.config.js',
},
{
path: 'hydrogen.config.ts',
},
],
},
settings: {
installCommand: {
placeholder: '`yarn install`, `pnpm install`, or `npm install`',
},
buildCommand: {
value: 'shopify hydrogen build',
placeholder: '`npm run build` or `shopify hydrogen build`',
},
devCommand: {
value: 'shopify hydrogen dev',
placeholder: 'shopify hydrogen dev',
},
outputDirectory: {
value: 'dist',
},
},
dependency: '@shopify/hydrogen',
getOutputDirName: async () => 'dist',
},
{
name: 'Vite',
slug: 'vite',
demo: 'https://vite-vue-template.vercel.app',
logo: 'https://api-frameworks.vercel.sh/framework-logos/vite.svg',
tagline:
'Vite is a new breed of frontend build tool that significantly improves the frontend development experience.',
description: 'A Vue.js app, created with Vite.',
website: 'https://vitejs.dev',
envPrefix: 'VITE_',
detectors: {
every: [
{
matchPackage: 'vite',
},
],
},
settings: {
installCommand: {
placeholder: '`yarn install`, `pnpm install`, or `npm install`',
},
buildCommand: {
placeholder: '`npm run build` or `vite build`',
value: 'vite build',
},
devCommand: {
placeholder: 'vite',
value: 'vite --port $PORT',
},
outputDirectory: {
value: 'dist',
},
},
dependency: 'vite',
getOutputDirName: async () => 'dist',
},
{
name: 'VitePress',
slug: 'vitepress',
demo: 'https://vitepress-starter-template.vercel.app',
logo: 'https://api-frameworks.vercel.sh/framework-logos/vite.svg',
tagline: "VitePress is VuePress' little brother, built on top of Vite.",
description: 'VuePress on top of Vite',
website: 'https://vitepress.vuejs.org/',
detectors: {
every: [
{
matchPackage: 'vitepress',
},
],
},
settings: {
installCommand: {
placeholder: '`yarn install`, `pnpm install`, or `npm install`',
},
buildCommand: {
placeholder: '`npm run build` or `vitepress build docs`',
value: 'vitepress build docs',
},
devCommand: {
value: 'vitepress dev docs --port $PORT',
},
outputDirectory: {
value: 'docs/.vitepress/dist',
},
},
getOutputDirName: async () => 'docs/.vitepress/dist',
},
{
name: 'VuePress',
slug: 'vuepress',
demo: 'https://vuepress-starter-template.vercel.app',
logo: 'https://api-frameworks.vercel.sh/framework-logos/vuepress.png',
tagline: 'Vue-powered Static Site Generator',
description: 'Vue-powered Static Site Generator',
website: 'https://vuepress.vuejs.org/',
detectors: {
every: [
{
matchPackage: 'vuepress',
},
],
},
settings: {
installCommand: {
placeholder: '`yarn install`, `pnpm install`, or `npm install`',
},
buildCommand: {
placeholder: '`npm run build` or `vuepress build src`',
value: 'vuepress build src',
},
devCommand: {
value: 'vuepress dev src --port $PORT',
},
outputDirectory: {
value: 'src/.vuepress/dist',
},
},
getOutputDirName: async () => 'src/.vuepress/dist',
},
{
name: 'Parcel',
slug: 'parcel',
demo: 'https://parcel-template.vercel.app',
logo: 'https://api-frameworks.vercel.sh/framework-logos/parcel.png',
tagline:
'Parcel is a zero configuration build tool for the web that scales to projects of any size and complexity.',
description: 'A vanilla web app built with Parcel.',
website: 'https://parceljs.org',
detectors: {
every: [
{
matchPackage: 'parcel',
},
],
},
settings: {
installCommand: {
placeholder: '`yarn install`, `pnpm install`, or `npm install`',
},
buildCommand: {
placeholder: '`npm run build` or `parcel build`',
value: 'parcel build',
},
devCommand: {
placeholder: 'parcel',
value: 'parcel',
},
outputDirectory: {
value: 'dist',
},
},
dependency: 'parcel',
getOutputDirName: async () => 'dist',
defaultRoutes: [
{
src: '^/[^./]+\\.[0-9a-f]{8}\\.(css|js|png|jpg|webp|avif|svg)$',
headers: { 'cache-control': 's-maxage=31536000, immutable' },
continue: true,
},
{
handle: 'filesystem',
},
],
},
{
name: 'Sanity',
slug: 'sanity',
demo: 'https://sanity-studio-template.vercel.app',
logo: 'https://api-frameworks.vercel.sh/framework-logos/sanity.svg',
tagline: 'The structured content platform.',
description: 'A Sanity Studio',
website: 'https://www.sanity.io',
envPrefix: 'SANITY_STUDIO_',
detectors: {
some: [
{
path: 'sanity.json',
},
{
path: 'sanity.config.js',
},
{
path: 'sanity.config.jsx',
},
{
path: 'sanity.config.ts',
},
{
path: 'sanity.config.tsx',
},
],
},
settings: {
installCommand: {
placeholder: '`yarn install`, `pnpm install`, or `npm install`',
},
buildCommand: {
placeholder: '`npm run build` or `sanity build`',
value: 'sanity build',
},
devCommand: {
value: 'sanity start --port $PORT',
},
outputDirectory: {
value: 'dist',
},
},
dependency: '@sanity/cli',
getOutputDirName: async () => 'dist',
defaultRoutes: [
{
handle: 'filesystem',
},
{
src: '/(.*)',
dest: '/index.html',
},
],
},
{
name: 'Other',
slug: null,
logo: 'https://api-frameworks.vercel.sh/framework-logos/other.svg',
description: 'No framework or an unoptimized framework.',
settings: {
installCommand: {
placeholder: '`yarn install`, `pnpm install`, or `npm install`',
},
buildCommand: {
placeholder: '`npm run vercel-build` or `npm run build`',
value: null,
},
devCommand: {
placeholder: 'None',
value: null,
},
outputDirectory: {
placeholder: '`public` if it exists, or `.`',
},
},
getOutputDirName: async () => 'public',
},
] as const;
const def = frameworks as readonly Framework[];
export default def;