mirror of
https://github.com/LukeHagar/vercel.git
synced 2025-12-11 04:22:13 +00:00
Compare commits
9 Commits
@vercel/py
...
vercel@24.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c4ab0ebe9c | ||
|
|
321f1232a1 | ||
|
|
8a8203e149 | ||
|
|
33527165e7 | ||
|
|
db10383bc8 | ||
|
|
56960e506e | ||
|
|
a17f3a96ec | ||
|
|
9ff86a896c | ||
|
|
6ccb4354f9 |
670
examples/sveltekit/package-lock.json
generated
670
examples/sveltekit/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,7 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "sveltekit",
|
||||
"version": "0.0.1",
|
||||
"scripts": {
|
||||
"dev": "svelte-kit dev",
|
||||
"build": "svelte-kit build",
|
||||
@@ -9,7 +11,7 @@
|
||||
"devDependencies": {
|
||||
"@sveltejs/adapter-auto": "next",
|
||||
"@sveltejs/kit": "next",
|
||||
"svelte": "^3.44.0"
|
||||
"svelte": "^3.46.0"
|
||||
},
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
|
||||
@@ -8,6 +8,6 @@
|
||||
%svelte.head%
|
||||
</head>
|
||||
<body>
|
||||
<div id="svelte">%svelte.body%</div>
|
||||
<div>%svelte.body%</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
1
examples/sveltekit/src/global.d.ts
vendored
1
examples/sveltekit/src/global.d.ts
vendored
@@ -1 +0,0 @@
|
||||
/// <reference types="@sveltejs/kit" />
|
||||
@@ -1,19 +1,22 @@
|
||||
import cookie from 'cookie';
|
||||
import { v4 as uuid } from '@lukeed/uuid';
|
||||
|
||||
export const handle = async ({ request, resolve }) => {
|
||||
const cookies = cookie.parse(request.headers.cookie || '');
|
||||
request.locals.userid = cookies.userid || uuid();
|
||||
export const handle = async ({ event, resolve }) => {
|
||||
const cookies = cookie.parse(event.request.headers.get('cookie') || '');
|
||||
event.locals.userid = cookies.userid || uuid();
|
||||
|
||||
const response = await resolve(request);
|
||||
const response = await resolve(event);
|
||||
|
||||
if (!cookies.userid) {
|
||||
// if this is the first time the user has visited this app,
|
||||
// set a cookie so that we recognise them when they return
|
||||
response.headers['set-cookie'] = cookie.serialize('userid', request.locals.userid, {
|
||||
path: '/',
|
||||
httpOnly: true
|
||||
});
|
||||
response.headers.set(
|
||||
'set-cookie',
|
||||
cookie.serialize('userid', event.locals.userid, {
|
||||
path: '/',
|
||||
httpOnly: true
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
return response;
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
<div class="counter-viewport">
|
||||
<div class="counter-digits" style="transform: translate(0, {100 * offset}%)">
|
||||
<strong style="top: -100%" aria-hidden="true">{Math.floor($displayed_count + 1)}</strong>
|
||||
<strong class="hidden" aria-hidden="true">{Math.floor($displayed_count + 1)}</strong>
|
||||
<strong>{Math.floor($displayed_count)}</strong>
|
||||
</div>
|
||||
</div>
|
||||
@@ -94,4 +94,9 @@
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
top: -100%;
|
||||
user-select: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { invalidate } from '$app/navigation';
|
||||
|
||||
// this action (https://svelte.dev/tutorial/actions) allows us to
|
||||
// progressively enhance a <form> that already works without JS
|
||||
export function enhance(form, { pending, error, result }) {
|
||||
export function enhance(form, { pending, error, result } = {}) {
|
||||
let current_token;
|
||||
|
||||
async function handle_submit(e) {
|
||||
@@ -8,31 +10,35 @@ export function enhance(form, { pending, error, result }) {
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
const body = new FormData(form);
|
||||
const data = new FormData(form);
|
||||
|
||||
if (pending) pending(body, form);
|
||||
if (pending) pending({ data, form });
|
||||
|
||||
try {
|
||||
const res = await fetch(form.action, {
|
||||
const response = await fetch(form.action, {
|
||||
method: form.method,
|
||||
headers: {
|
||||
accept: 'application/json'
|
||||
},
|
||||
body
|
||||
body: data
|
||||
});
|
||||
|
||||
if (token !== current_token) return;
|
||||
|
||||
if (res.ok) {
|
||||
result(res, form);
|
||||
if (response.ok) {
|
||||
if (result) result({ data, form, response });
|
||||
|
||||
const url = new URL(form.action);
|
||||
url.search = url.hash = '';
|
||||
invalidate(url.href);
|
||||
} else if (error) {
|
||||
error(res, null, form);
|
||||
error({ data, form, error: null, response });
|
||||
} else {
|
||||
console.error(await res.text());
|
||||
console.error(await response.text());
|
||||
}
|
||||
} catch (e) {
|
||||
if (error) {
|
||||
error(null, e, form);
|
||||
error({ data, form, error: e, response: null });
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
import { api } from './_api';
|
||||
|
||||
// PATCH /todos/:uid.json
|
||||
export const patch = async (request) => {
|
||||
return api(request, `todos/${request.locals.userid}/${request.params.uid}`, {
|
||||
text: request.body.get('text'),
|
||||
done: request.body.has('done') ? !!request.body.get('done') : undefined
|
||||
});
|
||||
};
|
||||
|
||||
// DELETE /todos/:uid.json
|
||||
export const del = async (request) => {
|
||||
return api(request, `todos/${request.locals.userid}/${request.params.uid}`);
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
This module is used by the /todos.json and /todos/[uid].json
|
||||
endpoints to make calls to api.svelte.dev, which stores todos
|
||||
This module is used by the /todos endpoint to
|
||||
make calls to api.svelte.dev, which stores todos
|
||||
for each user. The leading underscore indicates that this is
|
||||
a private module, _not_ an endpoint — visiting /todos/_api
|
||||
will net you a 404 response.
|
||||
@@ -11,35 +11,12 @@
|
||||
|
||||
const base = 'https://api.svelte.dev';
|
||||
|
||||
export async function api(request, resource, data) {
|
||||
// user must have a cookie set
|
||||
if (!request.locals.userid) {
|
||||
return { status: 401 };
|
||||
}
|
||||
|
||||
const res = await fetch(`${base}/${resource}`, {
|
||||
method: request.method,
|
||||
export function api(method, resource, data) {
|
||||
return fetch(`${base}/${resource}`, {
|
||||
method,
|
||||
headers: {
|
||||
'content-type': 'application/json'
|
||||
},
|
||||
body: data && JSON.stringify(data)
|
||||
});
|
||||
|
||||
// if the request came from a <form> submission, the browser's default
|
||||
// behaviour is to show the URL corresponding to the form's "action"
|
||||
// attribute. in those cases, we want to redirect them back to the
|
||||
// /todos page, rather than showing the response
|
||||
if (res.ok && request.method !== 'GET' && request.headers.accept !== 'application/json') {
|
||||
return {
|
||||
status: 303,
|
||||
headers: {
|
||||
location: '/todos'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
status: res.status,
|
||||
body: await res.json()
|
||||
};
|
||||
}
|
||||
|
||||
66
examples/sveltekit/src/routes/todos/index.js
Normal file
66
examples/sveltekit/src/routes/todos/index.js
Normal file
@@ -0,0 +1,66 @@
|
||||
import { api } from './_api';
|
||||
|
||||
export const get = async ({ locals }) => {
|
||||
// locals.userid comes from src/hooks.js
|
||||
const response = await api('get', `todos/${locals.userid}`);
|
||||
|
||||
if (response.status === 404) {
|
||||
// user hasn't created a todo list.
|
||||
// start with an empty array
|
||||
return {
|
||||
body: {
|
||||
todos: []
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (response.status === 200) {
|
||||
return {
|
||||
body: {
|
||||
todos: await response.json()
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
status: response.status
|
||||
};
|
||||
};
|
||||
|
||||
export const post = async ({ request, locals }) => {
|
||||
const form = await request.formData();
|
||||
|
||||
await api('post', `todos/${locals.userid}`, {
|
||||
text: form.get('text')
|
||||
});
|
||||
|
||||
return {};
|
||||
};
|
||||
|
||||
// If the user has JavaScript disabled, the URL will change to
|
||||
// include the method override unless we redirect back to /todos
|
||||
const redirect = {
|
||||
status: 303,
|
||||
headers: {
|
||||
location: '/todos'
|
||||
}
|
||||
};
|
||||
|
||||
export const patch = async ({ request, locals }) => {
|
||||
const form = await request.formData();
|
||||
|
||||
await api('patch', `todos/${locals.userid}/${form.get('uid')}`, {
|
||||
text: form.has('text') ? form.get('text') : undefined,
|
||||
done: form.has('done') ? !!form.get('done') : undefined
|
||||
});
|
||||
|
||||
return redirect;
|
||||
};
|
||||
|
||||
export const del = async ({ request, locals }) => {
|
||||
const form = await request.formData();
|
||||
|
||||
await api('delete', `todos/${locals.userid}/${form.get('uid')}`);
|
||||
|
||||
return redirect;
|
||||
};
|
||||
@@ -1,28 +0,0 @@
|
||||
import { api } from './_api';
|
||||
|
||||
// GET /todos.json
|
||||
export const get = async (request) => {
|
||||
// request.locals.userid comes from src/hooks.js
|
||||
const response = await api(request, `todos/${request.locals.userid}`);
|
||||
|
||||
if (response.status === 404) {
|
||||
// user hasn't created a todo list.
|
||||
// start with an empty array
|
||||
return { body: [] };
|
||||
}
|
||||
|
||||
return response;
|
||||
};
|
||||
|
||||
// POST /todos.json
|
||||
export const post = async (request) => {
|
||||
const response = await api(request, `todos/${request.locals.userid}`, {
|
||||
// because index.svelte posts a FormData object,
|
||||
// request.body is _also_ a (readonly) FormData
|
||||
// object, which allows us to get form data
|
||||
// with the `body.get(key)` method
|
||||
text: request.body.get('text')
|
||||
});
|
||||
|
||||
return response;
|
||||
};
|
||||
@@ -1,40 +1,9 @@
|
||||
<script context="module">
|
||||
import { enhance } from '$lib/form';
|
||||
|
||||
// see https://kit.svelte.dev/docs#loading
|
||||
export const load = async ({ fetch }) => {
|
||||
const res = await fetch('/todos.json');
|
||||
|
||||
if (res.ok) {
|
||||
const todos = await res.json();
|
||||
|
||||
return {
|
||||
props: { todos }
|
||||
};
|
||||
}
|
||||
|
||||
const { message } = await res.json();
|
||||
|
||||
return {
|
||||
error: new Error(message)
|
||||
};
|
||||
};
|
||||
</script>
|
||||
|
||||
<script>
|
||||
import { enhance } from '$lib/form';
|
||||
import { scale } from 'svelte/transition';
|
||||
import { flip } from 'svelte/animate';
|
||||
|
||||
export let todos;
|
||||
|
||||
async function patch(res) {
|
||||
const todo = await res.json();
|
||||
|
||||
todos = todos.map((t) => {
|
||||
if (t.uid === todo.uid) return todo;
|
||||
return t;
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
@@ -46,13 +15,10 @@
|
||||
|
||||
<form
|
||||
class="new"
|
||||
action="/todos.json"
|
||||
action="/todos"
|
||||
method="post"
|
||||
use:enhance={{
|
||||
result: async (res, form) => {
|
||||
const created = await res.json();
|
||||
todos = [...todos, created];
|
||||
|
||||
result: async ({ form }) => {
|
||||
form.reset();
|
||||
}
|
||||
}}
|
||||
@@ -68,41 +34,33 @@
|
||||
animate:flip={{ duration: 200 }}
|
||||
>
|
||||
<form
|
||||
action="/todos/{todo.uid}.json?_method=PATCH"
|
||||
action="/todos?_method=PATCH"
|
||||
method="post"
|
||||
use:enhance={{
|
||||
pending: (data) => {
|
||||
pending: ({ data }) => {
|
||||
todo.done = !!data.get('done');
|
||||
},
|
||||
result: patch
|
||||
}
|
||||
}}
|
||||
>
|
||||
<input type="hidden" name="uid" value={todo.uid} />
|
||||
<input type="hidden" name="done" value={todo.done ? '' : 'true'} />
|
||||
<button class="toggle" aria-label="Mark todo as {todo.done ? 'not done' : 'done'}" />
|
||||
</form>
|
||||
|
||||
<form
|
||||
class="text"
|
||||
action="/todos/{todo.uid}.json?_method=PATCH"
|
||||
method="post"
|
||||
use:enhance={{
|
||||
result: patch
|
||||
}}
|
||||
>
|
||||
<form class="text" action="/todos?_method=PATCH" method="post" use:enhance>
|
||||
<input type="hidden" name="uid" value={todo.uid} />
|
||||
<input aria-label="Edit todo" type="text" name="text" value={todo.text} />
|
||||
<button class="save" aria-label="Save todo" />
|
||||
</form>
|
||||
|
||||
<form
|
||||
action="/todos/{todo.uid}.json?_method=DELETE"
|
||||
action="/todos?_method=DELETE"
|
||||
method="post"
|
||||
use:enhance={{
|
||||
pending: () => (todo.pending_delete = true),
|
||||
result: () => {
|
||||
todos = todos.filter((t) => t.uid !== todo.uid);
|
||||
}
|
||||
pending: () => (todo.pending_delete = true)
|
||||
}}
|
||||
>
|
||||
<input type="hidden" name="uid" value={todo.uid} />
|
||||
<button class="delete" aria-label="Delete todo" disabled={todo.pending_delete} />
|
||||
</form>
|
||||
</div>
|
||||
@@ -158,7 +116,7 @@
|
||||
.done {
|
||||
transform: none;
|
||||
opacity: 0.4;
|
||||
filter: drop-shadow(0px 0px 1px rgba(0, 0, 0, 0.1));
|
||||
filter: drop-shadow(0 0 1px rgba(0, 0, 0, 0.1));
|
||||
}
|
||||
|
||||
form.text {
|
||||
|
||||
@@ -5,8 +5,10 @@ const config = {
|
||||
kit: {
|
||||
adapter: adapter(),
|
||||
|
||||
// hydrate the <div id="svelte"> element in src/app.html
|
||||
target: '#svelte'
|
||||
// Override http methods in the Todo forms
|
||||
methodOverride: {
|
||||
allowed: ['PATCH', 'DELETE']
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -56,7 +56,8 @@
|
||||
"build": "turbo run build",
|
||||
"vercel-build": "mkdir -p public && echo '<a href=\"https://vercel.com/import\">Import</a>' > public/output.html",
|
||||
"pre-commit": "lint-staged",
|
||||
"test-unit": "node utils/run.js test-unit",
|
||||
"test": "jest --rootDir=\"test\" --testPathPattern=\"\\.test.js\"",
|
||||
"test-unit": "yarn test && node utils/run.js test-unit",
|
||||
"test-integration-cli": "node utils/run.js test-integration-cli",
|
||||
"test-integration-once": "node utils/run.js test-integration-once",
|
||||
"test-integration-dev": "node utils/run.js test-integration-dev",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/build-utils",
|
||||
"version": "2.14.1-canary.2",
|
||||
"version": "2.14.1-canary.3",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.js",
|
||||
|
||||
@@ -8,12 +8,13 @@ import { deprecate } from 'util';
|
||||
import { NowBuildError } from '../errors';
|
||||
import { Meta, PackageJson, NodeVersion, Config } from '../types';
|
||||
import { getSupportedNodeVersion, getLatestNodeVersion } from './node-version';
|
||||
import { readConfigFile } from './read-config-file';
|
||||
|
||||
export type CliType = 'yarn' | 'npm';
|
||||
export type CliType = 'yarn' | 'npm' | 'pnpm';
|
||||
|
||||
export interface ScanParentDirsResult {
|
||||
/**
|
||||
* "yarn" or "npm", depending on the presence of lockfiles.
|
||||
* "yarn", "npm", or "pnpm" depending on the presence of lockfiles.
|
||||
*/
|
||||
cliType: CliType;
|
||||
/**
|
||||
@@ -252,7 +253,7 @@ export async function scanParentDirs(
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
const [packageLockJson, hasYarnLock] = await Promise.all([
|
||||
const [packageLockJson, hasYarnLock, pnpmLockYaml] = await Promise.all([
|
||||
fs
|
||||
.readJson(path.join(currentDestPath, 'package-lock.json'))
|
||||
.catch(error => {
|
||||
@@ -263,17 +264,26 @@ export async function scanParentDirs(
|
||||
throw error;
|
||||
}),
|
||||
fs.pathExists(path.join(currentDestPath, 'yarn.lock')),
|
||||
readConfigFile<{ lockfileVersion: number }>(
|
||||
path.join(currentDestPath, 'pnpm-lock.yaml')
|
||||
),
|
||||
]);
|
||||
|
||||
if (packageLockJson && !hasYarnLock) {
|
||||
if (packageLockJson && !hasYarnLock && !pnpmLockYaml) {
|
||||
cliType = 'npm';
|
||||
lockfileVersion = packageLockJson.lockfileVersion;
|
||||
}
|
||||
|
||||
if (!packageLockJson && !hasYarnLock && pnpmLockYaml) {
|
||||
cliType = 'pnpm';
|
||||
// just ensure that it is read as a number and not a string
|
||||
lockfileVersion = Number(pnpmLockYaml.lockfileVersion);
|
||||
}
|
||||
|
||||
// Only stop iterating if a lockfile was found, because it's possible
|
||||
// that the lockfile is in a higher path than where the `package.json`
|
||||
// file was found.
|
||||
if (packageLockJson || hasYarnLock) {
|
||||
if (packageLockJson || hasYarnLock || pnpmLockYaml) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -341,6 +351,13 @@ export async function runNpmInstall(
|
||||
commandArgs = args
|
||||
.filter(a => a !== '--prefer-offline')
|
||||
.concat(['install', '--no-audit', '--unsafe-perm']);
|
||||
} else if (cliType === 'pnpm') {
|
||||
// PNPM's install command is similar to NPM's but without the audit nonsense
|
||||
// @see options https://pnpm.io/cli/install
|
||||
opts.prettyCommand = 'pnpm install';
|
||||
commandArgs = args
|
||||
.filter(a => a !== '--prefer-offline')
|
||||
.concat(['install', '--unsafe-perm']);
|
||||
} else {
|
||||
opts.prettyCommand = 'yarn install';
|
||||
commandArgs = ['install', ...args];
|
||||
|
||||
15
packages/build-utils/test/fixtures/22-pnpm/package.json
vendored
Normal file
15
packages/build-utils/test/fixtures/22-pnpm/package.json
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "22-pnpm",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"build": "mkdir -p public && (printf \"pnpm version: \" && pnpm -v) > public/index.txt"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"once": "^1.4.0"
|
||||
}
|
||||
}
|
||||
19
packages/build-utils/test/fixtures/22-pnpm/pnpm-lock.yaml
generated
vendored
Normal file
19
packages/build-utils/test/fixtures/22-pnpm/pnpm-lock.yaml
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
lockfileVersion: 5.3
|
||||
|
||||
specifiers:
|
||||
once: ^1.4.0
|
||||
|
||||
dependencies:
|
||||
once: 1.4.0
|
||||
|
||||
packages:
|
||||
|
||||
/once/1.4.0:
|
||||
resolution: {integrity: sha1-WDsap3WWHUsROsF9nFC6753Xa9E=}
|
||||
dependencies:
|
||||
wrappy: 1.0.2
|
||||
dev: false
|
||||
|
||||
/wrappy/1.0.2:
|
||||
resolution: {integrity: sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=}
|
||||
dev: false
|
||||
5
packages/build-utils/test/fixtures/22-pnpm/vercel.json
vendored
Normal file
5
packages/build-utils/test/fixtures/22-pnpm/vercel.json
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"version": 2,
|
||||
"builds": [{ "src": "package.json", "use": "@vercel/static-build" }],
|
||||
"probes": [{ "path": "/", "mustContain": "pnpm version: 6" }]
|
||||
}
|
||||
5
packages/build-utils/test/fixtures/23-pnpm-workspaces/c/package.json
vendored
Normal file
5
packages/build-utils/test/fixtures/23-pnpm-workspaces/c/package.json
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"name": "c",
|
||||
"license": "MIT",
|
||||
"version": "0.1.0"
|
||||
}
|
||||
8
packages/build-utils/test/fixtures/23-pnpm-workspaces/d/package.json
vendored
Normal file
8
packages/build-utils/test/fixtures/23-pnpm-workspaces/d/package.json
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "d",
|
||||
"license": "MIT",
|
||||
"version": "0.1.0",
|
||||
"devDependencies": {
|
||||
"once": "1.4.0"
|
||||
}
|
||||
}
|
||||
6
packages/build-utils/test/fixtures/23-pnpm-workspaces/package.json
vendored
Normal file
6
packages/build-utils/test/fixtures/23-pnpm-workspaces/package.json
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"private": true,
|
||||
"name": "23-pnpm-workspaces",
|
||||
"license": "MIT",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
27
packages/build-utils/test/fixtures/23-pnpm-workspaces/pnpm-lock.yaml
generated
vendored
Normal file
27
packages/build-utils/test/fixtures/23-pnpm-workspaces/pnpm-lock.yaml
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
lockfileVersion: 5.3
|
||||
|
||||
importers:
|
||||
|
||||
.:
|
||||
specifiers: {}
|
||||
|
||||
c:
|
||||
specifiers: {}
|
||||
|
||||
d:
|
||||
specifiers:
|
||||
once: 1.4.0
|
||||
devDependencies:
|
||||
once: 1.4.0
|
||||
|
||||
packages:
|
||||
|
||||
/once/1.4.0:
|
||||
resolution: {integrity: sha1-WDsap3WWHUsROsF9nFC6753Xa9E=}
|
||||
dependencies:
|
||||
wrappy: 1.0.2
|
||||
dev: true
|
||||
|
||||
/wrappy/1.0.2:
|
||||
resolution: {integrity: sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=}
|
||||
dev: true
|
||||
3
packages/build-utils/test/fixtures/23-pnpm-workspaces/pnpm-workspace.yaml
vendored
Normal file
3
packages/build-utils/test/fixtures/23-pnpm-workspaces/pnpm-workspace.yaml
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
packages:
|
||||
- 'c'
|
||||
- 'd'
|
||||
@@ -31,6 +31,7 @@ const skipFixtures: string[] = [
|
||||
'07-zero-config-jekyll',
|
||||
'08-zero-config-middleman',
|
||||
'21-npm-workspaces',
|
||||
'23-pnpm-workspaces',
|
||||
];
|
||||
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
|
||||
14
packages/build-utils/test/unit.test.ts
vendored
14
packages/build-utils/test/unit.test.ts
vendored
@@ -332,3 +332,17 @@ it('should detect npm Workspaces', async () => {
|
||||
expect(result.cliType).toEqual('npm');
|
||||
expect(result.lockfileVersion).toEqual(2);
|
||||
});
|
||||
|
||||
it('should detect pnpm', async () => {
|
||||
const fixture = path.join(__dirname, 'fixtures', '22-pnpm');
|
||||
const result = await scanParentDirs(fixture);
|
||||
expect(result.cliType).toEqual('pnpm');
|
||||
expect(result.lockfileVersion).toEqual(5.3);
|
||||
});
|
||||
|
||||
it('should detect pnpm Workspaces', async () => {
|
||||
const fixture = path.join(__dirname, 'fixtures', '23-pnpm-workspaces/a');
|
||||
const result = await scanParentDirs(fixture);
|
||||
expect(result.cliType).toEqual('pnpm');
|
||||
expect(result.lockfileVersion).toEqual(5.3);
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vercel",
|
||||
"version": "24.0.1-canary.2",
|
||||
"version": "24.0.1-canary.4",
|
||||
"preferGlobal": true,
|
||||
"license": "Apache-2.0",
|
||||
"description": "The command-line interface for Vercel",
|
||||
@@ -43,11 +43,11 @@
|
||||
"node": ">= 12"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vercel/build-utils": "2.14.1-canary.2",
|
||||
"@vercel/go": "1.3.1-canary.2",
|
||||
"@vercel/node": "1.13.1-canary.2",
|
||||
"@vercel/python": "2.2.1-canary.2",
|
||||
"@vercel/ruby": "1.3.1-canary.2",
|
||||
"@vercel/build-utils": "2.14.1-canary.3",
|
||||
"@vercel/go": "1.3.1-canary.3",
|
||||
"@vercel/node": "1.13.1-canary.4",
|
||||
"@vercel/python": "2.2.1-canary.3",
|
||||
"@vercel/ruby": "1.3.1-canary.3",
|
||||
"update-notifier": "4.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -88,7 +88,7 @@
|
||||
"@types/update-notifier": "5.1.0",
|
||||
"@types/which": "1.3.2",
|
||||
"@types/write-json-file": "2.2.1",
|
||||
"@vercel/client": "10.3.1-canary.2",
|
||||
"@vercel/client": "10.3.1-canary.3",
|
||||
"@vercel/fetch-retry": "5.0.3",
|
||||
"@vercel/frameworks": "0.6.1-canary.2",
|
||||
"@vercel/ncc": "0.24.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/client",
|
||||
"version": "10.3.1-canary.2",
|
||||
"version": "10.3.1-canary.3",
|
||||
"main": "dist/index.js",
|
||||
"typings": "dist/index.d.ts",
|
||||
"homepage": "https://vercel.com",
|
||||
@@ -40,7 +40,7 @@
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"@vercel/build-utils": "2.14.1-canary.2",
|
||||
"@vercel/build-utils": "2.14.1-canary.3",
|
||||
"@zeit/fetch": "5.2.0",
|
||||
"async-retry": "1.2.3",
|
||||
"async-sema": "3.0.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/go",
|
||||
"version": "1.3.1-canary.2",
|
||||
"version": "1.3.1-canary.3",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index",
|
||||
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/go",
|
||||
@@ -24,7 +24,7 @@
|
||||
"@types/fs-extra": "^5.0.5",
|
||||
"@types/node-fetch": "^2.3.0",
|
||||
"@types/tar": "^4.0.0",
|
||||
"@vercel/build-utils": "2.14.1-canary.2",
|
||||
"@vercel/build-utils": "2.14.1-canary.3",
|
||||
"@vercel/ncc": "0.24.0",
|
||||
"async-retry": "1.3.1",
|
||||
"execa": "^1.0.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/node",
|
||||
"version": "1.13.1-canary.2",
|
||||
"version": "1.13.1-canary.4",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index",
|
||||
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/node-js",
|
||||
@@ -19,6 +19,7 @@
|
||||
],
|
||||
"dependencies": {
|
||||
"@types/node": "*",
|
||||
"@vercel/node-bridge": "2.1.2-canary.0",
|
||||
"ts-node": "8.9.1",
|
||||
"typescript": "4.3.4"
|
||||
},
|
||||
@@ -31,10 +32,9 @@
|
||||
"@types/cookie": "0.3.3",
|
||||
"@types/etag": "1.8.0",
|
||||
"@types/test-listen": "1.1.0",
|
||||
"@vercel/build-utils": "2.14.1-canary.2",
|
||||
"@vercel/build-utils": "2.14.1-canary.3",
|
||||
"@vercel/ncc": "0.24.0",
|
||||
"@vercel/nft": "0.17.5",
|
||||
"@vercel/node-bridge": "2.1.2-canary.0",
|
||||
"content-type": "1.0.4",
|
||||
"cookie": "0.4.0",
|
||||
"etag": "1.8.1",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vercel/python",
|
||||
"version": "2.2.1-canary.2",
|
||||
"version": "2.2.1-canary.3",
|
||||
"main": "./dist/index.js",
|
||||
"license": "MIT",
|
||||
"homepage": "https://vercel.com/docs/runtimes#official-runtimes/python",
|
||||
@@ -20,7 +20,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/execa": "^0.9.0",
|
||||
"@vercel/build-utils": "2.14.1-canary.2",
|
||||
"@vercel/build-utils": "2.14.1-canary.3",
|
||||
"@vercel/ncc": "0.24.0",
|
||||
"execa": "^1.0.0",
|
||||
"typescript": "4.3.4"
|
||||
|
||||
12
packages/redwood/build.js
Normal file
12
packages/redwood/build.js
Normal file
@@ -0,0 +1,12 @@
|
||||
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);
|
||||
});
|
||||
30
packages/redwood/package.json
Normal file
30
packages/redwood/package.json
Normal file
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"name": "@vercel/redwood",
|
||||
"version": "0.5.2-canary.1",
|
||||
"main": "./dist/index.js",
|
||||
"license": "MIT",
|
||||
"homepage": "https://vercel.com/docs",
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/vercel/vercel.git",
|
||||
"directory": "packages/redwood"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "node build.js",
|
||||
"test-integration-once": "jest --env node --verbose --runInBand --bail",
|
||||
"prepublishOnly": "node build.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vercel/nft": "0.17.5",
|
||||
"semver": "6.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/aws-lambda": "8.10.19",
|
||||
"@types/node": "*",
|
||||
"@types/semver": "6.0.0",
|
||||
"@vercel/build-utils": "2.14.1-canary.3"
|
||||
}
|
||||
}
|
||||
259
packages/redwood/src/index.ts
Normal file
259
packages/redwood/src/index.ts
Normal file
@@ -0,0 +1,259 @@
|
||||
import { join, dirname, relative, parse as parsePath, sep } from 'path';
|
||||
import { readFileSync, lstatSync } from 'fs';
|
||||
import { intersects, validRange } from 'semver';
|
||||
import {
|
||||
Lambda,
|
||||
Files,
|
||||
download,
|
||||
glob,
|
||||
debug,
|
||||
getNodeVersion,
|
||||
getSpawnOptions,
|
||||
runNpmInstall,
|
||||
runPackageJsonScript,
|
||||
execCommand,
|
||||
File,
|
||||
FileBlob,
|
||||
FileFsRef,
|
||||
PackageJson,
|
||||
getLambdaOptionsFromFunction,
|
||||
readConfigFile,
|
||||
isSymbolicLink,
|
||||
scanParentDirs,
|
||||
NodejsLambda,
|
||||
BuildV2,
|
||||
PrepareCache,
|
||||
} from '@vercel/build-utils';
|
||||
import { nodeFileTrace } from '@vercel/nft';
|
||||
|
||||
interface RedwoodToml {
|
||||
web: { port?: number; apiProxyPath?: string };
|
||||
api: { port?: number };
|
||||
browser: { open?: boolean };
|
||||
}
|
||||
|
||||
export const version = 2;
|
||||
|
||||
export const build: BuildV2 = async ({
|
||||
workPath,
|
||||
files,
|
||||
entrypoint,
|
||||
meta = {},
|
||||
config = {},
|
||||
}) => {
|
||||
await download(files, workPath, meta);
|
||||
|
||||
Object.keys(process.env)
|
||||
.filter(key => key.startsWith('VERCEL_'))
|
||||
.forEach(key => {
|
||||
const newKey = `REDWOOD_ENV_${key}`;
|
||||
if (!(newKey in process.env)) {
|
||||
process.env[newKey] = process.env[key];
|
||||
}
|
||||
});
|
||||
|
||||
const { installCommand, buildCommand } = config;
|
||||
const mountpoint = dirname(entrypoint);
|
||||
const entrypointFsDirname = join(workPath, mountpoint);
|
||||
const nodeVersion = await getNodeVersion(
|
||||
entrypointFsDirname,
|
||||
undefined,
|
||||
config,
|
||||
meta
|
||||
);
|
||||
|
||||
const spawnOpts = getSpawnOptions(meta, nodeVersion);
|
||||
if (typeof installCommand === 'string') {
|
||||
if (installCommand.trim()) {
|
||||
console.log(`Running "install" command: \`${installCommand}\`...`);
|
||||
const { cliType, lockfileVersion } = await scanParentDirs(
|
||||
entrypointFsDirname
|
||||
);
|
||||
const env: Record<string, string> = {
|
||||
YARN_NODE_LINKER: 'node-modules',
|
||||
...spawnOpts.env,
|
||||
};
|
||||
|
||||
if (cliType === 'npm') {
|
||||
if (
|
||||
typeof lockfileVersion === 'number' &&
|
||||
lockfileVersion >= 2 &&
|
||||
(nodeVersion?.major || 0) < 16
|
||||
) {
|
||||
// Ensure that npm 7 is at the beginning of the `$PATH`
|
||||
env.PATH = `/node16/bin-npm7:${env.PATH}`;
|
||||
console.log('Detected `package-lock.json` generated by npm 7...');
|
||||
}
|
||||
}
|
||||
|
||||
await execCommand(installCommand, {
|
||||
...spawnOpts,
|
||||
env,
|
||||
cwd: entrypointFsDirname,
|
||||
});
|
||||
} else {
|
||||
console.log(`Skipping "install" command...`);
|
||||
}
|
||||
} else {
|
||||
console.log('Installing dependencies...');
|
||||
const installTime = Date.now();
|
||||
await runNpmInstall(entrypointFsDirname, [], spawnOpts, meta, nodeVersion);
|
||||
debug(`Install complete [${Date.now() - installTime}ms]`);
|
||||
}
|
||||
|
||||
if (meta.isDev) {
|
||||
throw new Error('Detected `@vercel/redwood` dev but this is not supported');
|
||||
}
|
||||
|
||||
const pkg = await readConfigFile<PackageJson>(join(workPath, 'package.json'));
|
||||
|
||||
const toml = await readConfigFile<RedwoodToml>(
|
||||
join(workPath, 'redwood.toml')
|
||||
);
|
||||
|
||||
if (buildCommand) {
|
||||
debug(`Executing build command "${buildCommand}"`);
|
||||
await execCommand(buildCommand, {
|
||||
...spawnOpts,
|
||||
cwd: workPath,
|
||||
});
|
||||
} else if (hasScript('vercel-build', pkg)) {
|
||||
debug(`Executing "yarn vercel-build"`);
|
||||
await runPackageJsonScript(workPath, 'vercel-build', spawnOpts);
|
||||
} else if (hasScript('build', pkg)) {
|
||||
debug(`Executing "yarn build"`);
|
||||
await runPackageJsonScript(workPath, 'build', spawnOpts);
|
||||
} else {
|
||||
const { devDependencies = {} } = pkg || {};
|
||||
const versionRange = devDependencies['@redwoodjs/core'];
|
||||
let cmd: string;
|
||||
if (!versionRange || !validRange(versionRange)) {
|
||||
console.log(
|
||||
'WARNING: Unable to detect RedwoodJS version in package.json devDependencies'
|
||||
);
|
||||
cmd = 'yarn rw deploy vercel'; // Assume 0.25.0 and newer
|
||||
} else if (intersects(versionRange, '<0.25.0')) {
|
||||
// older than 0.25.0
|
||||
cmd =
|
||||
'yarn rw build && yarn rw db up --no-db-client --auto-approve && yarn rw dataMigrate up';
|
||||
} else {
|
||||
// 0.25.0 and newer
|
||||
cmd = 'yarn rw deploy vercel';
|
||||
}
|
||||
await execCommand(cmd, {
|
||||
...spawnOpts,
|
||||
cwd: workPath,
|
||||
});
|
||||
}
|
||||
|
||||
const apiDir = toml?.web?.apiProxyPath?.replace(/^\//, '') ?? 'api';
|
||||
const apiDistPath = join(workPath, 'api', 'dist', 'functions');
|
||||
const webDistPath = join(workPath, 'web', 'dist');
|
||||
const lambdaOutputs: { [filePath: string]: Lambda } = {};
|
||||
const staticOutputs = await glob('**', webDistPath);
|
||||
|
||||
// Each file in the `functions` dir will become a lambda
|
||||
const functionFiles = await glob('*.js', apiDistPath);
|
||||
|
||||
const sourceCache = new Map<string, string | Buffer | null>();
|
||||
const fsCache = new Map<string, File>();
|
||||
|
||||
for (const [funcName, fileFsRef] of Object.entries(functionFiles)) {
|
||||
const outputName = join(apiDir, parsePath(funcName).name); // remove `.js` extension
|
||||
const absEntrypoint = fileFsRef.fsPath;
|
||||
const relativeEntrypoint = relative(workPath, absEntrypoint);
|
||||
const awsLambdaHandler = getAWSLambdaHandler(relativeEntrypoint, 'handler');
|
||||
const sourceFile = relativeEntrypoint.replace('/dist/', '/src/');
|
||||
|
||||
const { fileList, esmFileList, warnings } = await nodeFileTrace(
|
||||
[absEntrypoint],
|
||||
{
|
||||
base: workPath,
|
||||
processCwd: workPath,
|
||||
ts: true,
|
||||
mixedModules: true,
|
||||
ignore: config.excludeFiles,
|
||||
async readFile(fsPath: string): Promise<Buffer | string | null> {
|
||||
const relPath = relative(workPath, fsPath);
|
||||
const cached = sourceCache.get(relPath);
|
||||
if (cached) return cached.toString();
|
||||
// null represents a not found
|
||||
if (cached === null) return null;
|
||||
try {
|
||||
const source = readFileSync(fsPath);
|
||||
const { mode } = lstatSync(fsPath);
|
||||
let entry: File;
|
||||
if (isSymbolicLink(mode)) {
|
||||
entry = new FileFsRef({ fsPath, mode });
|
||||
} else {
|
||||
entry = new FileBlob({ data: source, mode });
|
||||
}
|
||||
fsCache.set(relPath, entry);
|
||||
sourceCache.set(relPath, source);
|
||||
return source.toString();
|
||||
} catch (e: any) {
|
||||
if (e.code === 'ENOENT' || e.code === 'EISDIR') {
|
||||
sourceCache.set(relPath, null);
|
||||
return null;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
for (const warning of warnings) {
|
||||
if (warning?.stack) {
|
||||
debug(warning.stack.replace('Error: ', 'Warning: '));
|
||||
}
|
||||
}
|
||||
|
||||
const lambdaFiles: Files = {};
|
||||
|
||||
const allFiles = [...fileList, ...esmFileList];
|
||||
for (const filePath of allFiles) {
|
||||
lambdaFiles[filePath] = await FileFsRef.fromFsPath({
|
||||
fsPath: join(workPath, filePath),
|
||||
});
|
||||
}
|
||||
|
||||
lambdaFiles[relative(workPath, fileFsRef.fsPath)] = fileFsRef;
|
||||
|
||||
const { memory, maxDuration } = await getLambdaOptionsFromFunction({
|
||||
sourceFile,
|
||||
config,
|
||||
});
|
||||
|
||||
const lambda = new NodejsLambda({
|
||||
files: lambdaFiles,
|
||||
handler: relativeEntrypoint,
|
||||
runtime: nodeVersion.runtime,
|
||||
memory,
|
||||
maxDuration,
|
||||
shouldAddHelpers: false,
|
||||
shouldAddSourcemapSupport: false,
|
||||
awsLambdaHandler,
|
||||
});
|
||||
lambdaOutputs[outputName] = lambda;
|
||||
}
|
||||
|
||||
return {
|
||||
output: { ...staticOutputs, ...lambdaOutputs },
|
||||
routes: [{ handle: 'filesystem' }, { src: '/.*', dest: '/index.html' }],
|
||||
};
|
||||
};
|
||||
|
||||
function getAWSLambdaHandler(filePath: string, handlerName: string) {
|
||||
const { dir, name } = parsePath(filePath);
|
||||
return `${dir}${dir ? sep : ''}${name}.${handlerName}`;
|
||||
}
|
||||
|
||||
function hasScript(scriptName: string, pkg: PackageJson | null) {
|
||||
const scripts = (pkg && pkg.scripts) || {};
|
||||
return typeof scripts[scriptName] === 'string';
|
||||
}
|
||||
|
||||
export const prepareCache: PrepareCache = async ({ workPath }) => {
|
||||
const cache = await glob('**/node_modules/**', workPath);
|
||||
return cache;
|
||||
};
|
||||
7
packages/redwood/test/fixtures/01-create-redwood-app/.env.defaults
vendored
Normal file
7
packages/redwood/test/fixtures/01-create-redwood-app/.env.defaults
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
# These environment variables will be used by default if you do not create any
|
||||
# yourself in .env. This file should be safe to check into your version control
|
||||
# system. Any custom values should go in .env and .env should *not* be checked
|
||||
# into version control.
|
||||
|
||||
DATABASE_URL=file:./dev.db
|
||||
BINARY_TARGET=native
|
||||
10
packages/redwood/test/fixtures/01-create-redwood-app/.gitignore
vendored
Normal file
10
packages/redwood/test/fixtures/01-create-redwood-app/.gitignore
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
.DS_Store
|
||||
.env
|
||||
.netlify
|
||||
dev.db
|
||||
dist
|
||||
dist-babel
|
||||
node_modules
|
||||
yarn-error.log
|
||||
|
||||
.vercel
|
||||
1
packages/redwood/test/fixtures/01-create-redwood-app/.nvmrc
vendored
Normal file
1
packages/redwood/test/fixtures/01-create-redwood-app/.nvmrc
vendored
Normal file
@@ -0,0 +1 @@
|
||||
lts/*
|
||||
21
packages/redwood/test/fixtures/01-create-redwood-app/LICENSE
vendored
Normal file
21
packages/redwood/test/fixtures/01-create-redwood-app/LICENSE
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 Redwood
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
44
packages/redwood/test/fixtures/01-create-redwood-app/README.md
vendored
Normal file
44
packages/redwood/test/fixtures/01-create-redwood-app/README.md
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
# Redwood
|
||||
|
||||
> **HEADS UP:** RedwoodJS is _NOT_ ready for use in Production. It relies heavily on Prisma2, which is currently in testing with an expected production release coming soon. See status at ["Is Prisma2 Ready?"](https://isprisma2ready.com)
|
||||
|
||||
## Getting Started
|
||||
|
||||
- [Redwoodjs.com](https://redwoodjs.com): home to all things RedwoodJS.
|
||||
- [Tutorial](https://redwoodjs.com/tutorial/welcome-to-redwood): getting started and complete overview guide.
|
||||
- [Docs](https://redwoodjs.com/docs/introduction): using the Redwood Router, handling assets and files, list of command-line tools, and more.
|
||||
- [Redwood Community](https://community.redwoodjs.com): get help, share tips and tricks, and collaborate on everything about RedwoodJS.
|
||||
|
||||
### Setup
|
||||
|
||||
We use Yarn as our package manager. To get the dependencies installed, just do this in the root directory:
|
||||
|
||||
```terminal
|
||||
yarn install
|
||||
```
|
||||
|
||||
### Fire it up
|
||||
|
||||
```terminal
|
||||
yarn redwood dev
|
||||
```
|
||||
|
||||
Your browser should open automatically to `http://localhost:8910` to see the web app. Lambda functions run on `http://localhost:8911` and are also proxied to `http://localhost:8910/api/functions/*`.
|
||||
|
||||
## Development
|
||||
|
||||
### Database
|
||||
|
||||
We're using [Prisma2](https://github.com/prisma/prisma2), a modern DB toolkit to query, migrate and model your database.
|
||||
|
||||
Prisma2 is [not ready for production](https://isprisma2ready.com) at the moment.
|
||||
|
||||
To create a development database:
|
||||
|
||||
```terminal
|
||||
yarn redwood db up
|
||||
```
|
||||
|
||||
This will read the schema definition in `api/prisma/schema.prisma` and generate a sqlite database in `api/prisma/dev.db`
|
||||
|
||||
If you've made changes to the schema run `yarn redwood db save` to generate a migration, and `yarn redwood db up` to apply the migration/ generate a new ORM client.
|
||||
1
packages/redwood/test/fixtures/01-create-redwood-app/api/.babelrc.js
vendored
Normal file
1
packages/redwood/test/fixtures/01-create-redwood-app/api/.babelrc.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = { extends: '../babel.config.js' }
|
||||
9
packages/redwood/test/fixtures/01-create-redwood-app/api/jsconfig.json
vendored
Normal file
9
packages/redwood/test/fixtures/01-create-redwood-app/api/jsconfig.json
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"src/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"include": ["src/**/*"]
|
||||
}
|
||||
8
packages/redwood/test/fixtures/01-create-redwood-app/api/package.json
vendored
Normal file
8
packages/redwood/test/fixtures/01-create-redwood-app/api/package.json
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "api",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@redwoodjs/api": "0.15.0"
|
||||
}
|
||||
}
|
||||
18
packages/redwood/test/fixtures/01-create-redwood-app/api/prisma/schema.prisma
vendored
Normal file
18
packages/redwood/test/fixtures/01-create-redwood-app/api/prisma/schema.prisma
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
datasource DS {
|
||||
provider = "sqlite"
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
binaryTargets = env("BINARY_TARGET")
|
||||
}
|
||||
|
||||
// Define your own datamodels here and run `yarn redwood db save` to create
|
||||
// migrations for them.
|
||||
// TODO: Please remove the following example:
|
||||
model UserExample {
|
||||
id Int @id @default(autoincrement())
|
||||
email String @unique
|
||||
name String?
|
||||
}
|
||||
26
packages/redwood/test/fixtures/01-create-redwood-app/api/prisma/seeds.js
vendored
Normal file
26
packages/redwood/test/fixtures/01-create-redwood-app/api/prisma/seeds.js
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
/* eslint-disable no-console */
|
||||
const { PrismaClient } = require('@prisma/client')
|
||||
const dotenv = require('dotenv')
|
||||
|
||||
dotenv.config()
|
||||
const db = new PrismaClient()
|
||||
|
||||
async function main() {
|
||||
// Seed data is database data that needs to exist for your app to run.
|
||||
// Ideally this file should be idempotent: running it multiple times
|
||||
// will result in the same database state (usually by checking for the
|
||||
// existence of a record before trying to create it). For example:
|
||||
//
|
||||
// const existing = await db.user.findMany({ where: { email: 'admin@email.com' }})
|
||||
// if (!existing.length) {
|
||||
// await db.user.create({ data: { name: 'Admin', email: 'admin@email.com' }})
|
||||
// }
|
||||
|
||||
console.info('No data to seed. See api/prisma/seeds.js for info.')
|
||||
}
|
||||
|
||||
main()
|
||||
.catch((e) => console.error(e))
|
||||
.finally(async () => {
|
||||
await db.disconnect()
|
||||
})
|
||||
19
packages/redwood/test/fixtures/01-create-redwood-app/api/src/functions/graphql.js
vendored
Normal file
19
packages/redwood/test/fixtures/01-create-redwood-app/api/src/functions/graphql.js
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
import {
|
||||
createGraphQLHandler,
|
||||
makeMergedSchema,
|
||||
makeServices,
|
||||
} from '@redwoodjs/api'
|
||||
import importAll from '@redwoodjs/api/importAll.macro'
|
||||
|
||||
import { db } from 'src/lib/db'
|
||||
|
||||
const schemas = importAll('api', 'graphql')
|
||||
const services = importAll('api', 'services')
|
||||
|
||||
export const handler = createGraphQLHandler({
|
||||
schema: makeMergedSchema({
|
||||
schemas,
|
||||
services: makeServices({ services }),
|
||||
}),
|
||||
db,
|
||||
})
|
||||
9
packages/redwood/test/fixtures/01-create-redwood-app/api/src/functions/memory.js
vendored
Normal file
9
packages/redwood/test/fixtures/01-create-redwood-app/api/src/functions/memory.js
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
async function handler() {
|
||||
return {
|
||||
statusCode: 200,
|
||||
headers: {},
|
||||
body: `Memory is: ${process.env.AWS_LAMBDA_FUNCTION_MEMORY_SIZE}`,
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { handler }
|
||||
26
packages/redwood/test/fixtures/01-create-redwood-app/api/src/functions/permission.js
vendored
Executable file
26
packages/redwood/test/fixtures/01-create-redwood-app/api/src/functions/permission.js
vendored
Executable file
@@ -0,0 +1,26 @@
|
||||
const {
|
||||
promises: { access },
|
||||
constants: { X_OK },
|
||||
} = require('fs')
|
||||
|
||||
async function isExecutable(fsPath) {
|
||||
console.log(`Testing is file is executable: ${fsPath}`)
|
||||
try {
|
||||
await access(fsPath, X_OK)
|
||||
return true
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
return e.message
|
||||
}
|
||||
}
|
||||
|
||||
async function handler() {
|
||||
const isExec = await isExecutable(module.id)
|
||||
return {
|
||||
statusCode: 200,
|
||||
headers: {},
|
||||
body: `File is executable: ${isExec}`,
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { handler }
|
||||
0
packages/redwood/test/fixtures/01-create-redwood-app/api/src/graphql/.keep
vendored
Normal file
0
packages/redwood/test/fixtures/01-create-redwood-app/api/src/graphql/.keep
vendored
Normal file
6
packages/redwood/test/fixtures/01-create-redwood-app/api/src/lib/db.js
vendored
Normal file
6
packages/redwood/test/fixtures/01-create-redwood-app/api/src/lib/db.js
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
// See https://github.com/prisma/prisma2/blob/master/docs/prisma-client-js/api.md#constructor
|
||||
// for options.
|
||||
|
||||
import { PrismaClient } from '@prisma/client'
|
||||
|
||||
export const db = new PrismaClient()
|
||||
0
packages/redwood/test/fixtures/01-create-redwood-app/api/src/services/.keep
vendored
Normal file
0
packages/redwood/test/fixtures/01-create-redwood-app/api/src/services/.keep
vendored
Normal file
3
packages/redwood/test/fixtures/01-create-redwood-app/babel.config.js
vendored
Normal file
3
packages/redwood/test/fixtures/01-create-redwood-app/babel.config.js
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
presets: ['@redwoodjs/core/config/babel-preset'],
|
||||
}
|
||||
19
packages/redwood/test/fixtures/01-create-redwood-app/package.json
vendored
Normal file
19
packages/redwood/test/fixtures/01-create-redwood-app/package.json
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"private": true,
|
||||
"workspaces": {
|
||||
"packages": [
|
||||
"api",
|
||||
"web"
|
||||
]
|
||||
},
|
||||
"scripts": {
|
||||
"build": "rw db up --no-db-client --auto-approve && rw build"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@redwoodjs/core": "0.15.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12",
|
||||
"yarn": ">=1.15"
|
||||
}
|
||||
}
|
||||
9
packages/redwood/test/fixtures/01-create-redwood-app/prettier.config.js
vendored
Normal file
9
packages/redwood/test/fixtures/01-create-redwood-app/prettier.config.js
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
// https://prettier.io/docs/en/options.html
|
||||
module.exports = {
|
||||
trailingComma: 'es5',
|
||||
bracketSpacing: true,
|
||||
tabWidth: 2,
|
||||
semi: false,
|
||||
singleQuote: true,
|
||||
arrowParens: 'always',
|
||||
}
|
||||
7
packages/redwood/test/fixtures/01-create-redwood-app/redwood.toml
vendored
Normal file
7
packages/redwood/test/fixtures/01-create-redwood-app/redwood.toml
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
[web]
|
||||
port = 8910
|
||||
apiProxyPath = "/api"
|
||||
[api]
|
||||
port = 8911
|
||||
[browser]
|
||||
open = false
|
||||
41
packages/redwood/test/fixtures/01-create-redwood-app/vercel.json
vendored
Normal file
41
packages/redwood/test/fixtures/01-create-redwood-app/vercel.json
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
{
|
||||
"version": 2,
|
||||
"builds": [
|
||||
{
|
||||
"src": "package.json",
|
||||
"use": "@vercel/redwood",
|
||||
"config": {
|
||||
"zeroConfig": true,
|
||||
"functions": {
|
||||
"api/src/functions/memory.js": {
|
||||
"memory": 128
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"probes": [
|
||||
{ "path": "/", "mustContain": "<div id=\"redwood-app\">" },
|
||||
{ "path": "/about", "mustContain": "<div id=\"redwood-app\">" },
|
||||
{
|
||||
"path": "/api/graphql",
|
||||
"headers": { "Accept": "text/html" },
|
||||
"mustContain": "<title>GraphQL Playground</title>"
|
||||
},
|
||||
{
|
||||
"path": "/api/graphql",
|
||||
"method": "POST",
|
||||
"headers": { "Accept": "application/json" },
|
||||
"body": { "query": "{ redwood { version } }" },
|
||||
"mustContain": "0.15.0"
|
||||
},
|
||||
{
|
||||
"path": "/api/permission",
|
||||
"mustContain": "File is executable: true"
|
||||
},
|
||||
{
|
||||
"path": "/api/memory",
|
||||
"mustContain": "Memory is: 128"
|
||||
}
|
||||
]
|
||||
}
|
||||
1
packages/redwood/test/fixtures/01-create-redwood-app/web/.babelrc.js
vendored
Normal file
1
packages/redwood/test/fixtures/01-create-redwood-app/web/.babelrc.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = { extends: '../babel.config.js' }
|
||||
10
packages/redwood/test/fixtures/01-create-redwood-app/web/jsconfig.json
vendored
Normal file
10
packages/redwood/test/fixtures/01-create-redwood-app/web/jsconfig.json
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"src/*": ["./src/*"]
|
||||
},
|
||||
"jsx": "preserve"
|
||||
},
|
||||
"include": ["src/**/*"]
|
||||
}
|
||||
15
packages/redwood/test/fixtures/01-create-redwood-app/web/package.json
vendored
Normal file
15
packages/redwood/test/fixtures/01-create-redwood-app/web/package.json
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "web",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"browserslist": [
|
||||
"defaults"
|
||||
],
|
||||
"dependencies": {
|
||||
"@redwoodjs/router": "0.15.0",
|
||||
"@redwoodjs/web": "0.15.0",
|
||||
"prop-types": "^15.7.2",
|
||||
"react": "^16.13.1",
|
||||
"react-dom": "^16.13.1"
|
||||
}
|
||||
}
|
||||
45
packages/redwood/test/fixtures/01-create-redwood-app/web/public/README.md
vendored
Normal file
45
packages/redwood/test/fixtures/01-create-redwood-app/web/public/README.md
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
# Static Assets
|
||||
|
||||
Use this folder to add static files directly to your app. All included files and folders will be copied directly into the `/dist` folder (created when Webpack builds for production). They will also be available during development when you run `yarn rw dev`.
|
||||
|
||||
> Note: files will _not_ hot reload while the development server is running. You'll need to manually stop/start to access file changes.
|
||||
|
||||
### Example Use
|
||||
|
||||
A file like `favicon.png` will be copied to `/dist/favicon.png`. A folder containing a file such as `static-files/my-logo.jpg` will be copied to `/dist/static-files/my-logo.jpg`. These can be referenced in your code directly without any special handling, e.g.
|
||||
|
||||
```
|
||||
<link rel="icon" type="image/png" href="/favicon.png" />
|
||||
```
|
||||
|
||||
and
|
||||
|
||||
```
|
||||
<img src="/static-files/my-logo.jpg"> alt="Logo" />
|
||||
```
|
||||
|
||||
Behind the scenes, we are using Webpack's ["copy-webpack-plugin"](https://github.com/webpack-contrib/copy-webpack-plugin).
|
||||
|
||||
## Best Practices
|
||||
|
||||
Because assets in this folder are bypassing the javascript module system, **this folder should be used sparingly** for assets such as favicons, robots.txt, manifests, libraries incompatible with Webpack, etc.
|
||||
|
||||
In general, it's best to import files directly into a template, page, or component. This allows Webpack to include that file in the bundle, which ensures Webpack will correctly process and move assets into the distribution folder, providing error checks and correct paths along the way.
|
||||
|
||||
### Example Asset Import with Webpack
|
||||
|
||||
Instead of handling our logo image as a static file per the example above, we can do the following:
|
||||
|
||||
```
|
||||
import React from "react"
|
||||
import logo from "./my-logo.jpg"
|
||||
|
||||
|
||||
function Header() {
|
||||
return <img src={logo} alt="Logo" />
|
||||
}
|
||||
|
||||
export default Header
|
||||
```
|
||||
|
||||
Behind the scenes, we are using Webpack's ["file-loader"](https://webpack.js.org/loaders/file-loader/) and ["url-loader](https://webpack.js.org/loaders/url-loader/) (for files smaller than 10kb).
|
||||
BIN
packages/redwood/test/fixtures/01-create-redwood-app/web/public/favicon.png
vendored
Normal file
BIN
packages/redwood/test/fixtures/01-create-redwood-app/web/public/favicon.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
2
packages/redwood/test/fixtures/01-create-redwood-app/web/public/robots.txt
vendored
Normal file
2
packages/redwood/test/fixtures/01-create-redwood-app/web/public/robots.txt
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
User-agent: *
|
||||
Disallow:
|
||||
22
packages/redwood/test/fixtures/01-create-redwood-app/web/src/Routes.js
vendored
Normal file
22
packages/redwood/test/fixtures/01-create-redwood-app/web/src/Routes.js
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
// In this file, all Page components from 'src/pages` are auto-imported. Nested
|
||||
// directories are supported, and should be uppercase. Each subdirectory will be
|
||||
// prepended onto the component name.
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// 'src/pages/HomePage/HomePage.js' -> HomePage
|
||||
// 'src/pages/Admin/BooksPage/BooksPage.js' -> AdminBooksPage
|
||||
|
||||
import { Router, Route } from '@redwoodjs/router'
|
||||
|
||||
const Routes = () => {
|
||||
return (
|
||||
<Router>
|
||||
<Route path="/" page={HomePage} name="home" />
|
||||
<Route path="/about" page={AboutPage} name="about" />
|
||||
<Route notfound page={NotFoundPage} />
|
||||
</Router>
|
||||
)
|
||||
}
|
||||
|
||||
export default Routes
|
||||
0
packages/redwood/test/fixtures/01-create-redwood-app/web/src/components/.keep
vendored
Normal file
0
packages/redwood/test/fixtures/01-create-redwood-app/web/src/components/.keep
vendored
Normal file
0
packages/redwood/test/fixtures/01-create-redwood-app/web/src/index.css
vendored
Normal file
0
packages/redwood/test/fixtures/01-create-redwood-app/web/src/index.css
vendored
Normal file
12
packages/redwood/test/fixtures/01-create-redwood-app/web/src/index.html
vendored
Normal file
12
packages/redwood/test/fixtures/01-create-redwood-app/web/src/index.html
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="icon" type="image/png" href="/favicon.png" />
|
||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="redwood-app"></div>
|
||||
</body>
|
||||
</html>
|
||||
16
packages/redwood/test/fixtures/01-create-redwood-app/web/src/index.js
vendored
Normal file
16
packages/redwood/test/fixtures/01-create-redwood-app/web/src/index.js
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
import ReactDOM from 'react-dom'
|
||||
import { RedwoodProvider, FatalErrorBoundary } from '@redwoodjs/web'
|
||||
import FatalErrorPage from 'src/pages/FatalErrorPage'
|
||||
|
||||
import Routes from 'src/Routes'
|
||||
|
||||
import './index.css'
|
||||
|
||||
ReactDOM.render(
|
||||
<FatalErrorBoundary page={FatalErrorPage}>
|
||||
<RedwoodProvider>
|
||||
<Routes />
|
||||
</RedwoodProvider>
|
||||
</FatalErrorBoundary>,
|
||||
document.getElementById('redwood-app')
|
||||
)
|
||||
0
packages/redwood/test/fixtures/01-create-redwood-app/web/src/layouts/.keep
vendored
Normal file
0
packages/redwood/test/fixtures/01-create-redwood-app/web/src/layouts/.keep
vendored
Normal file
45
packages/redwood/test/fixtures/01-create-redwood-app/web/src/pages/AboutPage/AboutPage.js
vendored
Normal file
45
packages/redwood/test/fixtures/01-create-redwood-app/web/src/pages/AboutPage/AboutPage.js
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
export default () => (
|
||||
<main>
|
||||
<style
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: `
|
||||
html, body {
|
||||
margin: 0;
|
||||
}
|
||||
html * {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
main {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif;
|
||||
text-align: center;
|
||||
background-color: #E2E8F0;
|
||||
height: 100vh;
|
||||
}
|
||||
section {
|
||||
background-color: white;
|
||||
border-radius: 0.25rem;
|
||||
width: 32rem;
|
||||
padding: 1rem;
|
||||
margin: 0 auto;
|
||||
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
h1 {
|
||||
font-size: 2rem;
|
||||
margin: 0;
|
||||
font-weight: 500;
|
||||
line-height: 1;
|
||||
color: #2D3748;
|
||||
}
|
||||
`,
|
||||
}}
|
||||
/>
|
||||
<section>
|
||||
<h1>
|
||||
<span>About RedwoodJS</span>
|
||||
</h1>
|
||||
<p>{process.env.REDWOOD_ENV_VERCEL_URL}</p>
|
||||
</section>
|
||||
</main>
|
||||
)
|
||||
@@ -0,0 +1,53 @@
|
||||
// This page will be rendered when an error makes it all the way to the top of the
|
||||
// application without being handled by a Javascript catch statement or React error
|
||||
// boundary.
|
||||
//
|
||||
// You can modify this page as you wish, but it is important to keep things simple to
|
||||
// avoid the possibility that it will cause its own error. If it does, Redwood will
|
||||
// still render a generic error page, but your users will prefer something a bit more
|
||||
// thoughtful. =)
|
||||
|
||||
export default () => (
|
||||
<main>
|
||||
<style
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: `
|
||||
html, body {
|
||||
margin: 0;
|
||||
}
|
||||
html * {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
main {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif;
|
||||
text-align: center;
|
||||
background-color: #E2E8F0;
|
||||
height: 100vh;
|
||||
}
|
||||
section {
|
||||
background-color: white;
|
||||
border-radius: 0.25rem;
|
||||
width: 32rem;
|
||||
padding: 1rem;
|
||||
margin: 0 auto;
|
||||
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
h1 {
|
||||
font-size: 2rem;
|
||||
margin: 0;
|
||||
font-weight: 500;
|
||||
line-height: 1;
|
||||
color: #2D3748;
|
||||
}
|
||||
`,
|
||||
}}
|
||||
/>
|
||||
<section>
|
||||
<h1>
|
||||
<span>Something went wrong</span>
|
||||
</h1>
|
||||
</section>
|
||||
</main>
|
||||
)
|
||||
44
packages/redwood/test/fixtures/01-create-redwood-app/web/src/pages/HomePage/HomePage.js
vendored
Normal file
44
packages/redwood/test/fixtures/01-create-redwood-app/web/src/pages/HomePage/HomePage.js
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
export default () => (
|
||||
<main>
|
||||
<style
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: `
|
||||
html, body {
|
||||
margin: 0;
|
||||
}
|
||||
html * {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
main {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif;
|
||||
text-align: center;
|
||||
background-color: #E2E8F0;
|
||||
height: 100vh;
|
||||
}
|
||||
section {
|
||||
background-color: white;
|
||||
border-radius: 0.25rem;
|
||||
width: 32rem;
|
||||
padding: 1rem;
|
||||
margin: 0 auto;
|
||||
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
h1 {
|
||||
font-size: 2rem;
|
||||
margin: 0;
|
||||
font-weight: 500;
|
||||
line-height: 1;
|
||||
color: #2D3748;
|
||||
}
|
||||
`,
|
||||
}}
|
||||
/>
|
||||
<section>
|
||||
<h1>
|
||||
<span>Welcome to RedwoodJS!</span>
|
||||
</h1>
|
||||
</section>
|
||||
</main>
|
||||
)
|
||||
44
packages/redwood/test/fixtures/01-create-redwood-app/web/src/pages/NotFoundPage/NotFoundPage.js
vendored
Normal file
44
packages/redwood/test/fixtures/01-create-redwood-app/web/src/pages/NotFoundPage/NotFoundPage.js
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
export default () => (
|
||||
<main>
|
||||
<style
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: `
|
||||
html, body {
|
||||
margin: 0;
|
||||
}
|
||||
html * {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
main {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif;
|
||||
text-align: center;
|
||||
background-color: #E2E8F0;
|
||||
height: 100vh;
|
||||
}
|
||||
section {
|
||||
background-color: white;
|
||||
border-radius: 0.25rem;
|
||||
width: 32rem;
|
||||
padding: 1rem;
|
||||
margin: 0 auto;
|
||||
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
h1 {
|
||||
font-size: 2rem;
|
||||
margin: 0;
|
||||
font-weight: 500;
|
||||
line-height: 1;
|
||||
color: #2D3748;
|
||||
}
|
||||
`,
|
||||
}}
|
||||
/>
|
||||
<section>
|
||||
<h1>
|
||||
<span>404 Page Not Found</span>
|
||||
</h1>
|
||||
</section>
|
||||
</main>
|
||||
)
|
||||
14339
packages/redwood/test/fixtures/01-create-redwood-app/yarn.lock
vendored
Normal file
14339
packages/redwood/test/fixtures/01-create-redwood-app/yarn.lock
vendored
Normal file
File diff suppressed because it is too large
Load Diff
7
packages/redwood/test/fixtures/02-create-redwood-app/.env.defaults
vendored
Normal file
7
packages/redwood/test/fixtures/02-create-redwood-app/.env.defaults
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
# These environment variables will be used by default if you do not create any
|
||||
# yourself in .env. This file should be safe to check into your version control
|
||||
# system. Any custom values should go in .env and .env should *not* be checked
|
||||
# into version control.
|
||||
|
||||
DATABASE_URL=file:./dev.db
|
||||
BINARY_TARGET=native
|
||||
10
packages/redwood/test/fixtures/02-create-redwood-app/.gitignore
vendored
Normal file
10
packages/redwood/test/fixtures/02-create-redwood-app/.gitignore
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
.idea
|
||||
.DS_Store
|
||||
.env
|
||||
.netlify
|
||||
dev.db
|
||||
dist
|
||||
dist-babel
|
||||
node_modules
|
||||
yarn-error.log
|
||||
web/public/mockServiceWorker.js
|
||||
21
packages/redwood/test/fixtures/02-create-redwood-app/LICENSE
vendored
Normal file
21
packages/redwood/test/fixtures/02-create-redwood-app/LICENSE
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 Redwood
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
54
packages/redwood/test/fixtures/02-create-redwood-app/README.md
vendored
Normal file
54
packages/redwood/test/fixtures/02-create-redwood-app/README.md
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
# Redwood
|
||||
|
||||
> **HEADS UP:** RedwoodJS is _NOT_ ready for use in Production. It relies heavily on Prisma2, which is currently in testing with an expected production release coming soon. See status at ["Is Prisma2 Ready?"](https://isprisma2ready.com)
|
||||
|
||||
## Getting Started
|
||||
|
||||
- [Redwoodjs.com](https://redwoodjs.com): home to all things RedwoodJS.
|
||||
- [Tutorial](https://redwoodjs.com/tutorial/welcome-to-redwood): getting started and complete overview guide.
|
||||
- [Docs](https://redwoodjs.com/docs/introduction): using the Redwood Router, handling assets and files, list of command-line tools, and more.
|
||||
- [Redwood Community](https://community.redwoodjs.com): get help, share tips and tricks, and collaborate on everything about RedwoodJS.
|
||||
|
||||
### Setup
|
||||
|
||||
We use Yarn as our package manager. To get the dependencies installed, just do this in the root directory:
|
||||
|
||||
```terminal
|
||||
yarn install
|
||||
```
|
||||
|
||||
### Fire it up
|
||||
|
||||
```terminal
|
||||
yarn redwood dev
|
||||
```
|
||||
|
||||
Your browser should open automatically to `http://localhost:8910` to see the web app. Lambda functions run on `http://localhost:8911` and are also proxied to `http://localhost:8910/api/functions/*`.
|
||||
|
||||
### Updating Redwood
|
||||
|
||||
Redwood comes with a helpful command to update itself and its dependencies. Why not try a new and improved version today?
|
||||
|
||||
> :point_right: IMPORTANT: Skipping versions when upgrading is not recommended and will likely cause problems. Do read through all [Release Notes](https://github.com/redwoodjs/redwood/releases) between your current version and the latest version. Each minor release will likely require you to implement breaking change fixes and apply manual code modifications.
|
||||
|
||||
```terminal
|
||||
yarn rw upgrade
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
### Database
|
||||
|
||||
We're using [Prisma2](https://github.com/prisma/prisma2), a modern DB toolkit to query, migrate and model your database.
|
||||
|
||||
Prisma2 is [not ready for production](https://isprisma2ready.com) at the moment.
|
||||
|
||||
To create a development database:
|
||||
|
||||
```terminal
|
||||
yarn redwood db up
|
||||
```
|
||||
|
||||
This will read the schema definition in `api/prisma/schema.prisma` and generate a sqlite database in `api/prisma/dev.db`
|
||||
|
||||
If you've made changes to the schema run `yarn redwood db save` to generate a migration, and `yarn redwood db up` to apply the migration/ generate a new ORM client.
|
||||
1
packages/redwood/test/fixtures/02-create-redwood-app/api/.babelrc.js
vendored
Normal file
1
packages/redwood/test/fixtures/02-create-redwood-app/api/.babelrc.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = { extends: '../babel.config.js' }
|
||||
6
packages/redwood/test/fixtures/02-create-redwood-app/api/jest.config.js
vendored
Normal file
6
packages/redwood/test/fixtures/02-create-redwood-app/api/jest.config.js
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
const { getConfig } = require('@redwoodjs/core')
|
||||
|
||||
const config = getConfig({ type: 'jest', target: 'node' })
|
||||
config.displayName.name = 'api'
|
||||
|
||||
module.exports = config
|
||||
9
packages/redwood/test/fixtures/02-create-redwood-app/api/jsconfig.json
vendored
Normal file
9
packages/redwood/test/fixtures/02-create-redwood-app/api/jsconfig.json
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"src/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"include": ["src/**/*"]
|
||||
}
|
||||
8
packages/redwood/test/fixtures/02-create-redwood-app/api/package.json
vendored
Normal file
8
packages/redwood/test/fixtures/02-create-redwood-app/api/package.json
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "api",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@redwoodjs/api": "^0.15.3"
|
||||
}
|
||||
}
|
||||
18
packages/redwood/test/fixtures/02-create-redwood-app/api/prisma/schema.prisma
vendored
Normal file
18
packages/redwood/test/fixtures/02-create-redwood-app/api/prisma/schema.prisma
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
datasource DS {
|
||||
provider = "sqlite"
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
binaryTargets = "native"
|
||||
}
|
||||
|
||||
// Define your own datamodels here and run `yarn redwood db save` to create
|
||||
// migrations for them.
|
||||
// TODO: Please remove the following example:
|
||||
model UserExample {
|
||||
id Int @id @default(autoincrement())
|
||||
email String @unique
|
||||
name String?
|
||||
}
|
||||
26
packages/redwood/test/fixtures/02-create-redwood-app/api/prisma/seeds.js
vendored
Normal file
26
packages/redwood/test/fixtures/02-create-redwood-app/api/prisma/seeds.js
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
/* eslint-disable no-console */
|
||||
const { PrismaClient } = require('@prisma/client')
|
||||
const dotenv = require('dotenv')
|
||||
|
||||
dotenv.config()
|
||||
const db = new PrismaClient()
|
||||
|
||||
async function main() {
|
||||
// Seed data is database data that needs to exist for your app to run.
|
||||
// Ideally this file should be idempotent: running it multiple times
|
||||
// will result in the same database state (usually by checking for the
|
||||
// existence of a record before trying to create it). For example:
|
||||
//
|
||||
// const existing = await db.user.findMany({ where: { email: 'admin@email.com' }})
|
||||
// if (!existing.length) {
|
||||
// await db.user.create({ data: { name: 'Admin', email: 'admin@email.com' }})
|
||||
// }
|
||||
|
||||
console.info('No data to seed. See api/prisma/seeds.js for info.')
|
||||
}
|
||||
|
||||
main()
|
||||
.catch((e) => console.error(e))
|
||||
.finally(async () => {
|
||||
await db.disconnect()
|
||||
})
|
||||
17
packages/redwood/test/fixtures/02-create-redwood-app/api/src/functions/graphql.js
vendored
Normal file
17
packages/redwood/test/fixtures/02-create-redwood-app/api/src/functions/graphql.js
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
import {
|
||||
createGraphQLHandler,
|
||||
makeMergedSchema,
|
||||
makeServices,
|
||||
} from '@redwoodjs/api'
|
||||
import schemas from 'src/graphql/**/*.{js,ts}'
|
||||
import services from 'src/services/**/*.{js,ts}'
|
||||
|
||||
import { db } from 'src/lib/db'
|
||||
|
||||
export const handler = createGraphQLHandler({
|
||||
schema: makeMergedSchema({
|
||||
schemas,
|
||||
services: makeServices({ services }),
|
||||
}),
|
||||
db,
|
||||
})
|
||||
0
packages/redwood/test/fixtures/02-create-redwood-app/api/src/graphql/.keep
vendored
Normal file
0
packages/redwood/test/fixtures/02-create-redwood-app/api/src/graphql/.keep
vendored
Normal file
6
packages/redwood/test/fixtures/02-create-redwood-app/api/src/lib/db.js
vendored
Normal file
6
packages/redwood/test/fixtures/02-create-redwood-app/api/src/lib/db.js
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
// See https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-client/constructor
|
||||
// for options.
|
||||
|
||||
import { PrismaClient } from '@prisma/client'
|
||||
|
||||
export const db = new PrismaClient()
|
||||
0
packages/redwood/test/fixtures/02-create-redwood-app/api/src/services/.keep
vendored
Normal file
0
packages/redwood/test/fixtures/02-create-redwood-app/api/src/services/.keep
vendored
Normal file
3
packages/redwood/test/fixtures/02-create-redwood-app/babel.config.js
vendored
Normal file
3
packages/redwood/test/fixtures/02-create-redwood-app/babel.config.js
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
presets: ['@redwoodjs/core/config/babel-preset'],
|
||||
}
|
||||
17
packages/redwood/test/fixtures/02-create-redwood-app/package.json
vendored
Normal file
17
packages/redwood/test/fixtures/02-create-redwood-app/package.json
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"private": true,
|
||||
"workspaces": {
|
||||
"packages": [
|
||||
"api",
|
||||
"web"
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@redwoodjs/core": "^0.15.3",
|
||||
"netlify-plugin-prisma-provider": "^0.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12",
|
||||
"yarn": ">=1.15"
|
||||
}
|
||||
}
|
||||
9
packages/redwood/test/fixtures/02-create-redwood-app/prettier.config.js
vendored
Normal file
9
packages/redwood/test/fixtures/02-create-redwood-app/prettier.config.js
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
// https://prettier.io/docs/en/options.html
|
||||
module.exports = {
|
||||
trailingComma: 'es5',
|
||||
bracketSpacing: true,
|
||||
tabWidth: 2,
|
||||
semi: false,
|
||||
singleQuote: true,
|
||||
arrowParens: 'always',
|
||||
}
|
||||
7
packages/redwood/test/fixtures/02-create-redwood-app/redwood.toml
vendored
Normal file
7
packages/redwood/test/fixtures/02-create-redwood-app/redwood.toml
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
[web]
|
||||
port = 8910
|
||||
apiProxyPath = "/api"
|
||||
[api]
|
||||
port = 8911
|
||||
[browser]
|
||||
open = false
|
||||
20
packages/redwood/test/fixtures/02-create-redwood-app/vercel.json
vendored
Normal file
20
packages/redwood/test/fixtures/02-create-redwood-app/vercel.json
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"version": 2,
|
||||
"builds": [{ "src": "package.json", "use": "@vercel/redwood" }],
|
||||
"probes": [
|
||||
{ "path": "/", "mustContain": "<div id=\"redwood-app\">" },
|
||||
{ "path": "/about", "mustContain": "<div id=\"redwood-app\">" },
|
||||
{
|
||||
"path": "/api/graphql",
|
||||
"headers": { "Accept": "text/html" },
|
||||
"mustContain": "<title>GraphQL Playground</title>"
|
||||
},
|
||||
{
|
||||
"path": "/api/graphql",
|
||||
"method": "POST",
|
||||
"headers": { "Accept": "application/json" },
|
||||
"body": { "query": "{ redwood { version } }" },
|
||||
"mustContain": "0.15.3"
|
||||
}
|
||||
]
|
||||
}
|
||||
1
packages/redwood/test/fixtures/02-create-redwood-app/web/.babelrc.js
vendored
Normal file
1
packages/redwood/test/fixtures/02-create-redwood-app/web/.babelrc.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = { extends: '../babel.config.js' }
|
||||
6
packages/redwood/test/fixtures/02-create-redwood-app/web/jest.config.js
vendored
Normal file
6
packages/redwood/test/fixtures/02-create-redwood-app/web/jest.config.js
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
const { getConfig } = require('@redwoodjs/core')
|
||||
|
||||
const config = getConfig({ type: 'jest', target: 'browser' })
|
||||
config.displayName.name = 'web'
|
||||
|
||||
module.exports = config
|
||||
10
packages/redwood/test/fixtures/02-create-redwood-app/web/jsconfig.json
vendored
Normal file
10
packages/redwood/test/fixtures/02-create-redwood-app/web/jsconfig.json
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"src/*": ["./src/*"]
|
||||
},
|
||||
"jsx": "preserve"
|
||||
},
|
||||
"include": ["src/**/*"]
|
||||
}
|
||||
15
packages/redwood/test/fixtures/02-create-redwood-app/web/package.json
vendored
Normal file
15
packages/redwood/test/fixtures/02-create-redwood-app/web/package.json
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "web",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"browserslist": [
|
||||
"defaults"
|
||||
],
|
||||
"dependencies": {
|
||||
"@redwoodjs/router": "^0.15.3",
|
||||
"@redwoodjs/web": "^0.15.3",
|
||||
"prop-types": "^15.7.2",
|
||||
"react": "^16.13.1",
|
||||
"react-dom": "^16.13.1"
|
||||
}
|
||||
}
|
||||
45
packages/redwood/test/fixtures/02-create-redwood-app/web/public/README.md
vendored
Normal file
45
packages/redwood/test/fixtures/02-create-redwood-app/web/public/README.md
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
# Static Assets
|
||||
|
||||
Use this folder to add static files directly to your app. All included files and folders will be copied directly into the `/dist` folder (created when Webpack builds for production). They will also be available during development when you run `yarn rw dev`.
|
||||
|
||||
> Note: files will _not_ hot reload while the development server is running. You'll need to manually stop/start to access file changes.
|
||||
|
||||
### Example Use
|
||||
|
||||
A file like `favicon.png` will be copied to `/dist/favicon.png`. A folder containing a file such as `static-files/my-logo.jpg` will be copied to `/dist/static-files/my-logo.jpg`. These can be referenced in your code directly without any special handling, e.g.
|
||||
|
||||
```
|
||||
<link rel="icon" type="image/png" href="/favicon.png" />
|
||||
```
|
||||
|
||||
and
|
||||
|
||||
```
|
||||
<img src="/static-files/my-logo.jpg"> alt="Logo" />
|
||||
```
|
||||
|
||||
Behind the scenes, we are using Webpack's ["copy-webpack-plugin"](https://github.com/webpack-contrib/copy-webpack-plugin).
|
||||
|
||||
## Best Practices
|
||||
|
||||
Because assets in this folder are bypassing the javascript module system, **this folder should be used sparingly** for assets such as favicons, robots.txt, manifests, libraries incompatible with Webpack, etc.
|
||||
|
||||
In general, it's best to import files directly into a template, page, or component. This allows Webpack to include that file in the bundle, which ensures Webpack will correctly process and move assets into the distribution folder, providing error checks and correct paths along the way.
|
||||
|
||||
### Example Asset Import with Webpack
|
||||
|
||||
Instead of handling our logo image as a static file per the example above, we can do the following:
|
||||
|
||||
```
|
||||
import React from "react"
|
||||
import logo from "./my-logo.jpg"
|
||||
|
||||
|
||||
function Header() {
|
||||
return <img src={logo} alt="Logo" />
|
||||
}
|
||||
|
||||
export default Header
|
||||
```
|
||||
|
||||
Behind the scenes, we are using Webpack's ["file-loader"](https://webpack.js.org/loaders/file-loader/) and ["url-loader](https://webpack.js.org/loaders/url-loader/) (for files smaller than 10kb).
|
||||
BIN
packages/redwood/test/fixtures/02-create-redwood-app/web/public/favicon.png
vendored
Normal file
BIN
packages/redwood/test/fixtures/02-create-redwood-app/web/public/favicon.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.8 KiB |
2
packages/redwood/test/fixtures/02-create-redwood-app/web/public/robots.txt
vendored
Normal file
2
packages/redwood/test/fixtures/02-create-redwood-app/web/public/robots.txt
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
User-agent: *
|
||||
Disallow:
|
||||
20
packages/redwood/test/fixtures/02-create-redwood-app/web/src/Routes.js
vendored
Normal file
20
packages/redwood/test/fixtures/02-create-redwood-app/web/src/Routes.js
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
// In this file, all Page components from 'src/pages` are auto-imported. Nested
|
||||
// directories are supported, and should be uppercase. Each subdirectory will be
|
||||
// prepended onto the component name.
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// 'src/pages/HomePage/HomePage.js' -> HomePage
|
||||
// 'src/pages/Admin/BooksPage/BooksPage.js' -> AdminBooksPage
|
||||
|
||||
import { Router, Route } from '@redwoodjs/router'
|
||||
|
||||
const Routes = () => {
|
||||
return (
|
||||
<Router>
|
||||
<Route notfound page={NotFoundPage} />
|
||||
</Router>
|
||||
)
|
||||
}
|
||||
|
||||
export default Routes
|
||||
0
packages/redwood/test/fixtures/02-create-redwood-app/web/src/components/.keep
vendored
Normal file
0
packages/redwood/test/fixtures/02-create-redwood-app/web/src/components/.keep
vendored
Normal file
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user