Compare commits

..

69 Commits

Author SHA1 Message Date
Steven
c76781fac9 Publish Stable
- @vercel/build-utils@2.15.0
 - vercel@24.0.1
 - @vercel/client@10.4.0
 - @vercel/frameworks@0.7.0
 - @vercel/go@1.3.1
 - @vercel/node-bridge@2.2.0
 - @vercel/node@1.14.0
 - @vercel/python@2.2.1
 - @vercel/redwood@0.6.0
 - @vercel/routing-utils@1.13.0
 - @vercel/ruby@1.3.1
 - @vercel/static-build@0.23.0
2022-03-22 15:17:06 -04:00
Steven
451e0b0cfb Publish Canary
- @vercel/build-utils@2.14.1-canary.8
 - vercel@24.0.1-canary.9
 - @vercel/client@10.3.1-canary.8
 - @vercel/frameworks@0.6.1-canary.7
 - @vercel/go@1.3.1-canary.8
 - @vercel/node@1.13.1-canary.9
 - @vercel/python@2.2.1-canary.8
 - @vercel/redwood@0.5.2-canary.6
 - @vercel/ruby@1.3.1-canary.8
 - @vercel/static-build@0.22.2-canary.6
2022-03-22 14:53:04 -04:00
Ethan Arrowood
cf477d45b2 [frameworks] add pnpm to framework install placeholders (#7587)
Add `pnpm` commands to framework `installCommand.placeholders` so that it appears in the UI.

Additionally, adds the `pnpm-lock.yaml` file to an ignore list like the other lock files.
2022-03-22 14:52:07 -04:00
Steven
cdd2d69e07 Publish Canary
- @vercel/static-build@0.22.2-canary.5
2022-03-22 13:45:48 -04:00
Lee Robinson
43f1f8b257 [static-build] Don't fail CRA builds on warnings (#7584) 2022-03-22 11:04:42 -05:00
Steven
34055e3599 Publish Canary
- @vercel/build-utils@2.14.1-canary.7
 - vercel@24.0.1-canary.8
 - @vercel/client@10.3.1-canary.7
 - @vercel/frameworks@0.6.1-canary.6
 - @vercel/go@1.3.1-canary.7
 - @vercel/node@1.13.1-canary.8
 - @vercel/python@2.2.1-canary.7
 - @vercel/redwood@0.5.2-canary.5
 - @vercel/ruby@1.3.1-canary.7
 - @vercel/static-build@0.22.2-canary.4
2022-03-22 11:32:44 -04:00
Steven
26abb0a85a [api] Update /api/examples/list to be static for vc init (#7596)
Previously, this API would download the entire git repository for each request. Instead, we can defer downloading to the `/download` API only and change the list API to be statically generated at build time.

This will improve the time to render the results from `vc init`.


## Before
- `https://vercel-lu6z5kf4s.vercel.sh/api/examples/list` responds in 6200 ms
- `https://vercel-lu6z5kf4s.vercel.sh/api/examples/list-all` responds in 800ms

## After
- `https://vercel-ctsxcwzgc.vercel.sh/api/examples/list` responds in 60 ms 
- `https://vercel-ctsxcwzgc.vercel.sh/api/examples/list-all` responds in 60 ms
2022-03-22 11:26:19 -04:00
Lee Robinson
a1e337e0dd [examples] Change hugo template to one that works with older version (#7601) 2022-03-22 08:42:34 -05:00
Steven
b72ead480f [tests] Bump turborepo to 1.1.9 (#7598)
Bump to latest turborepo
2022-03-22 03:15:42 +00:00
Lee Robinson
77cf68105f [Fix Hugo Version. (#7600) 2022-03-21 18:14:25 -05:00
Steven
d800f55dfa [cli] Fix vc init spinner (#7594) 2022-03-21 16:34:29 -04:00
Ethan Arrowood
9dde99f19e Publish Canary
- @vercel/build-utils@2.14.1-canary.6
 - vercel@24.0.1-canary.7
 - @vercel/client@10.3.1-canary.6
 - @vercel/frameworks@0.6.1-canary.5
 - @vercel/go@1.3.1-canary.6
 - @vercel/node@1.13.1-canary.7
 - @vercel/python@2.2.1-canary.6
 - @vercel/redwood@0.5.2-canary.4
 - @vercel/ruby@1.3.1-canary.6
 - @vercel/static-build@0.22.2-canary.3
2022-03-21 13:15:51 -06:00
Ethan Arrowood
fae7a083fc Revert "Remove file system environment variable (#7535)" (#7595)
This reverts commit e908378486.
2022-03-21 13:13:16 -06:00
Ethan Arrowood
cbd651d6ee add exit code check (#7578) 2022-03-18 15:48:30 -06:00
Nathan Rajlich
6077a706d1 [build-utils] Allow arbitrary properties on the Meta interface (#7582)
`vc build` is going to re-use the `meta` object between Builder
invocations, to allow arbitrary state to be shared between them. So
allow for additional properties to be specified on `Meta` with an
`unknown` type.
2022-03-17 17:27:42 -07:00
Nathan Rajlich
cedc82dd9e [build-utils] Mark arbitrary properties on Config as unknown (#7554) 2022-03-17 17:27:35 -07:00
Nathan Rajlich
b420006401 [build-utils] Remove AnalyzeOptions and analyze() docs (#7550)
The `analyze()` function on a Builder was removed a long time ago.
2022-03-17 17:27:26 -07:00
Steven
8ba604e8fc [tests] Remove unused dep cheerio (#7579)
- Closes #7576
- Closes #7500
2022-03-18 00:22:03 +00:00
Nathan Rajlich
fadeee4568 [cli] Update 14-svelte-node fixture to run "dev" command (#7583) 2022-03-17 16:18:50 -07:00
Lee Robinson
2b15ba7f46 Downgrade Hugo Version (#7562) 2022-03-16 14:39:06 -05:00
Ethan Arrowood
4cdfd0e58c [tests] Fix pnpm integration tests (#7563)
* fix test 24 and add test 25

* move pnp/symlink test to cli and complete hoisted test

* fix execa

* remove unnecessary gitignore

* Update packages/cli/test/integration.js

Co-authored-by: Steven <steven@ceriously.com>

* Update packages/cli/test/integration.js

Co-authored-by: Steven <steven@ceriously.com>

* complete cherry-pick

* remove package.json edit

* use fs-extra remove

* use fs-extra.remove correctly

Co-authored-by: Steven <steven@ceriously.com>
2022-03-16 14:49:02 -04:00
Steven
b3ccb5f3ef Publish Canary
- @vercel/build-utils@2.14.1-canary.5
 - vercel@24.0.1-canary.6
 - @vercel/client@10.3.1-canary.5
 - @vercel/frameworks@0.6.1-canary.4
 - @vercel/go@1.3.1-canary.5
 - @vercel/node@1.13.1-canary.6
 - @vercel/python@2.2.1-canary.5
 - @vercel/redwood@0.5.2-canary.3
 - @vercel/ruby@1.3.1-canary.5
 - @vercel/static-build@0.22.2-canary.2
2022-03-15 16:08:42 -04:00
Steven
584acc43b7 [node] Consolidate dev and prd tsconfig.json (#7549)
In a previous PR (#4254), the behavior of `vercel dev` was added separately without matching how deployments work.

This PR consolidates the `tsconfig.json` options for `vercel` deployments as well as `vercel dev` so they work the same.

Fixes https://github.com/vercel/customer-issues/issues/349
2022-03-15 16:03:28 -04:00
Adrian Bettridge-Wiese
f64be93b94 Add screenshots to frameworks (#7570) 2022-03-15 12:48:44 -07:00
Adrian Bettridge-Wiese
9abd31769e Revert "Add screenshot property to frameworks" (#7569)
This reverts commit 09e3b35e74.
2022-03-15 13:58:44 -04:00
Adrian Bettridge-Wiese
09e3b35e74 Add screenshot property to frameworks 2022-03-15 12:47:40 -05:00
Nathan Rajlich
8aa9a0ea05 [build-utils] Remove as cast in Lambda (#7553)
`Files` can now be properly narrowed by checking "type", so no need for the `as` cast here anymore.
2022-03-14 18:04:58 +00:00
Nathan Rajlich
b2d0ed74c6 Revert "[ruby] Use new Lambda() (#7551)"
This reverts commit 501be936c0.
2022-03-12 11:22:49 -08:00
Nathan Rajlich
aef936af0f Revert "[python] Use new Lambda()"
This reverts commit 7eba282af5.
2022-03-12 11:22:44 -08:00
Nathan Rajlich
501be936c0 [ruby] Use new Lambda() (#7551)
`createLambda()` is deprecated.
2022-03-11 21:19:32 -08:00
Nathan Rajlich
7eba282af5 [python] Use new Lambda()
`createLambda()` is deprecated.
2022-03-11 21:03:42 -08:00
Nathan Rajlich
cf3e4bd726 [build-utils] Use File type for Prerender fallback (#7539)
Tiny follow-up to #7530 since we can now use this union type to express
the same group of File implementation types.
2022-03-11 15:44:06 -05:00
Ethan Arrowood
ee5361b00e Revert "pnpm pnp symlinkn integration test (#7543)" (#7548)
This reverts commit bd929dd5c5.
2022-03-11 15:30:22 -05:00
Ethan Arrowood
bd929dd5c5 pnpm pnp symlinkn integration test (#7543)
* temp commit

* update test case

* check for build cache hit

* Update packages/build-utils/test/integration.test.ts

Co-authored-by: Steven <steven@ceriously.com>

Co-authored-by: Steven <steven@ceriously.com>
2022-03-11 10:52:48 -07:00
Sean Massa
4ee064bb61 [static-build] Add @vercel/static-build Builder (#7536) 2022-03-10 13:21:24 -06:00
Sean Massa
312a2090a6 [client] preserve symlinks during deploy upload (#7533)
Ensure that deploy uploads preserve symlinks.

---

Card: https://linear.app/vercel/issue/BUI-23/preserve-symlinks-in-vc-deploy
2022-03-10 01:54:03 +00:00
Sean Massa
a82f117217 [build-utils] Preserve symlinks for FileRef and FileBlob types in download() (#7534)
Co-authored-by: Nathan Rajlich <n@n8.io>
2022-03-09 16:41:03 -06:00
Ethan Arrowood
e908378486 Remove file system environment variable (#7535)
When running this example using `pnpm`, the filesystem environment variable was causing issues.

This change removes the variable and the file since it no longer serves a purpose. 

Deployment was tested using `pnpm`, `npm`, and `yarn` and all seem to run successfully now
2022-03-09 13:53:23 -06:00
Sean Massa
8cda5263eb [build-utils] Streamle File types for better type narrowing (#7530) 2022-03-08 14:29:33 -08:00
Ethan Arrowood
a24fd64bce Publish Canary
- @vercel/build-utils@2.14.1-canary.4
 - vercel@24.0.1-canary.5
 - @vercel/client@10.3.1-canary.4
 - @vercel/frameworks@0.6.1-canary.3
 - @vercel/go@1.3.1-canary.4
 - @vercel/node-bridge@2.1.2-canary.1
 - @vercel/node@1.13.1-canary.5
 - @vercel/python@2.2.1-canary.4
 - @vercel/redwood@0.5.2-canary.2
 - @vercel/routing-utils@1.12.1-canary.0
 - @vercel/ruby@1.3.1-canary.4
2022-03-08 12:39:54 -07:00
Ethan Arrowood
0c515a46d5 [build-utils] Change pretty command to pnpm run (#7529) 2022-03-08 11:24:56 -08:00
Gal Schlezinger
f19690dc32 [build-utils] Add EdgeFunction output type (#7510)
Co-authored-by: Steven <steven@ceriously.com>
2022-03-08 18:58:26 +02:00
JJ Kasper
6b2a1c3866 [node-bridge][build-utils] Add multi payload lambda handling in node-bridge (#7507)
### Related Issues

x-ref: https://github.com/vercel/next.js/pull/34935

### 📋 Checklist

<!--
  Please keep your PR as a Draft until the checklist is complete
-->

#### Tests

- [ ] The code changed/added as part of this PR has been covered with tests
- [ ] All tests pass locally with `yarn test-unit`

#### Code Review

- [ ] This PR has a concise title and thorough description useful to a reviewer
- [ ] Issue from task tracker has a link to this PR
2022-03-06 08:57:45 +00:00
Sean Massa
1e54d606d7 [cli] fail when local config is missing (#7516)
Currently, when the path is not found in a `vc deploy -A SOME_PATH` command, the fallback config is used, which is unexpected behavior. This PR changes that to throw an error that says the path was not found.

---

Card: https://linear.app/vercel/issue/BUI-32/vc-deploy-a-should-fail-when-path-not-found
2022-03-04 00:33:45 +00:00
Nathan Rajlich
c4ab0ebe9c Publish Canary
- vercel@24.0.1-canary.4
 - @vercel/node@1.13.1-canary.4
2022-03-03 13:49:02 -08:00
Nathan Rajlich
321f1232a1 [node] Move @vercel/node-bridge to dependencies (#7515)
Fixes issue introduced by #7436 when using `vc dev`. Since the dev-server script now imports `@vercel/node-bridge` directly, instead of copying the relevant files into the package, the bridge needs to be a regular dependency otherwise the import will fail.

```
Error: Cannot find module '@vercel/node-bridge/launcher.js'
Require stack:
- /usr/local/lib/node_modules/vercel/node_modules/@vercel/node/dist/dev-server.js
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:902:15)
    at Function.Module._load (internal/modules/cjs/loader.js:746:27)
    at Module.require (internal/modules/cjs/loader.js:974:19)
    at require (internal/modules/cjs/helpers.js:93:18)
    at Object.<anonymous> (/usr/local/lib/node_modules/vercel/node_modules/@vercel/node/dist/dev-server.js:79:23)
    at Module._compile (internal/modules/cjs/loader.js:1085:14)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1114:10)
    at Module.load (internal/modules/cjs/loader.js:950:32)
    at Function.Module._load (internal/modules/cjs/loader.js:790:12)
    at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:76:12)
Error! `node api/hello.js` failed with exit code 1
```
2022-03-03 21:04:33 +00:00
Nathan Rajlich
8a8203e149 Publish Canary
- @vercel/redwood@0.5.2-canary.1
2022-03-02 17:23:02 -08:00
Sean Massa
33527165e7 remove outdated comment (#7512) 2022-03-02 17:21:08 -08:00
Sean Massa
db10383bc8 [redwood] Add @vercel/redwood Builder (#7503) 2022-03-02 15:17:29 -08:00
Sean Massa
56960e506e [cli] enhance changelog accuracy and format (#7387)
* refactor and add test to changelog

* group changelog into areas

* remove revert and reverted commits from changelog

* make sure Revert commits that revert a commit in a previous changelog are not filtered

* run "yarn test" as part of "yarn test-unit"

* remove advanced syntax

* remove advanced syntax

* temp changelog

* remove temp changelog

* remove global jest config

* Delete symlink

* scope jest dir to just the test files we care about
2022-03-02 10:22:56 -08:00
Ethan Arrowood
a17f3a96ec Publish Canary
- @vercel/build-utils@2.14.1-canary.3
 - vercel@24.0.1-canary.3
 - @vercel/client@10.3.1-canary.3
 - @vercel/go@1.3.1-canary.3
 - @vercel/node@1.13.1-canary.3
 - @vercel/python@2.2.1-canary.3
 - @vercel/ruby@1.3.1-canary.3
2022-03-02 08:21:30 -07:00
Sam Ko
9ff86a896c [examples] Update todo functionality in the "sveltekit" example (#7506) 2022-03-01 15:50:04 -08:00
Jared Palmer
6ccb4354f9 Add support for PNPM (#6834)
Add support for `pnpm` as well as new fixtures for `pnpm` with and without workspaces

#### Tests

- [x] The code changed/added as part of this PR has been covered with tests
- [x] All tests pass locally with `yarn test-unit && yarn test-integration-once` 

#### Code Review

- [x] This PR has a concise title and thorough description useful to a reviewer
- [x] Issue from task tracker has a link to this PR
2022-03-01 22:34:39 +00:00
Nathan Rajlich
82ba932447 Publish Canary
- @vercel/build-utils@2.14.1-canary.2
 - vercel@24.0.1-canary.2
 - @vercel/client@10.3.1-canary.2
 - @vercel/frameworks@0.6.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
2022-02-28 19:57:09 -08:00
Nathan Rajlich
b995618afb [build-utils] Make files in Lambda be optional (#7498)
This ensures better backwards compatibility.
2022-02-28 19:53:25 -08:00
Nathan Rajlich
c897b24417 [build-utils] Allow Prerender type in BuildV2 output (#7499) 2022-02-28 19:52:55 -08:00
Nathan Rajlich
e64b2e1993 [build-utils] Make Builder routes output optional (#7497) 2022-02-28 16:05:17 -08:00
Haneen Mahdin
9358a5469e [docs] Fix wrong test command in CONTRIBUTING (#7392)
* docs: use meaningful word in contributing

I have changed the word `run` to `pass` in the Contributing Guidelines file inside `Verifying your change` documentation.
This provides a better understanding of how to run tests after every change.

* docs: remove `test` command run in local development

Remove guideline to test the code using `yarn test`, the test command does not exist in the project root but the build command automatically runs the tests.

* docs: add info about how tests are run

Add information about tests are run in this repo

* docs: fix testing scripts reference

Fixed some mistakes in the contributing readme
- Added `yarn test-unit` instead of `yarn test`

Co-authored-by: Steven <steven@ceriously.com>
2022-02-25 17:43:45 -05:00
Ella
2a24210b7d [examples] Fix link to Remix nested routes documentation (#7366)
* Remix example: fix link to nested routes

* Update about.tsx

Co-authored-by: Ella <72365100+eilla1@users.noreply.github.com>
Co-authored-by: Steven <steven@ceriously.com>
2022-02-23 12:26:49 -05:00
Lee Robinson
2644a59984 [examples] Re-add 11ty license and author info (#7476) 2022-02-23 11:19:27 -05:00
Lee Robinson
4eeb8c298c Update default Hugo & Zola versions. (#7467) 2022-02-22 14:23:59 -06:00
Nathan Rajlich
0351f02dff Publish Canary
- @vercel/build-utils@2.14.1-canary.1
 - vercel@24.0.1-canary.1
 - @vercel/client@10.3.1-canary.1
 - @vercel/frameworks@0.6.1-canary.1
 - @vercel/go@1.3.1-canary.1
 - @vercel/node@1.13.1-canary.1
 - @vercel/python@2.2.1-canary.1
 - @vercel/ruby@1.3.1-canary.1
2022-02-22 12:13:21 -08:00
Yuanlin Lin
0d7fa2f912 [frameworks] Updated Umi.js logo (#7470)
Co-authored-by: Andy <AndyBitz@users.noreply.github.com>
2022-02-22 19:59:32 +01:00
Nathan Rajlich
3b646880e7 [node] Use NodejsLambda class (#7436)
Updates `@vercel/node` to utilize the `NodejsLambda` class so that it doesn't need to explicitly bundle in the launcher/bridge files into the build result. This reduces the complexity of the Builder and is a cleaner separation of concerns. The `helpers.test.ts` file has been moved to `@vercel/node-bridge` so it's being removed in this PR as well.
2022-02-22 16:57:11 +00:00
Steven
350a0e5f36 [examples] Bump Next.js to 12.1.0 (#7458) 2022-02-18 18:53:26 -05:00
Steven
5c21d400bd Update dev test for image optimization with next@latest and python flask (#7454)
Related to https://github.com/vercel/next.js/pull/34431
2022-02-18 16:37:59 +00:00
Nathan Rajlich
04029013a6 Publish Canary
- @vercel/build-utils@2.14.1-canary.0
 - vercel@24.0.1-canary.0
 - @vercel/client@10.3.1-canary.0
 - @vercel/frameworks@0.6.1-canary.0
 - @vercel/go@1.3.1-canary.0
 - @vercel/node-bridge@2.1.2-canary.0
 - @vercel/node@1.13.1-canary.0
 - @vercel/python@2.2.1-canary.0
 - @vercel/ruby@1.3.1-canary.0
2022-02-17 20:40:07 -08:00
Nathan Rajlich
c65e7fa883 [node-bridge] Move helpers to node-bridge (#7451) 2022-02-17 20:36:37 -08:00
Knut Melvær
27b68be93f [frameworks] Add Sanity Studio (#7350)
Adds the default config and detector for a Sanity Studio project.
2022-02-16 14:26:39 -08:00
1749 changed files with 354951 additions and 7600 deletions

View File

@@ -1,7 +1,12 @@
node_modules node_modules
dist dist
examples examples
packages/node/src/bridge.ts
packages/*/test/fixtures packages/*/test/fixtures
# cli
packages/cli/@types packages/cli/@types
packages/cli/download packages/cli/download
packages/cli/dist packages/cli/dist
@@ -9,9 +14,24 @@ packages/cli/test/dev/fixtures
packages/cli/bin packages/cli/bin
packages/cli/link packages/cli/link
packages/cli/src/util/dev/templates/*.ts packages/cli/src/util/dev/templates/*.ts
# client
packages/client/tests/fixtures packages/client/tests/fixtures
packages/client/lib packages/client/lib
packages/node/src/bridge.ts
# node-bridge
packages/node-bridge/bridge.js packages/node-bridge/bridge.js
packages/node-bridge/launcher.js packages/node-bridge/launcher.js
packages/node-bridge/helpers.js
packages/node-bridge/source-map-support.js
# middleware
packages/middleware/src/entries.js packages/middleware/src/entries.js
# static-build
packages/static-build/test/fixtures
packages/static-build/test/build-fixtures
packages/static-build/test/cache-fixtures
# redwood
packages/redwood/test/fixtures

View File

@@ -16,17 +16,17 @@ yarn install
yarn bootstrap yarn bootstrap
yarn build yarn build
yarn lint yarn lint
yarn test yarn test-unit
``` ```
Make sure all the tests pass before making changes. Make sure all the tests pass before making changes.
## Verifying your change ## Verifying your change
Once you are done with your changes (we even suggest doing it along the way), make sure all the test still run by running: Once you are done with your changes (we even suggest doing it along the way), make sure all the test still pass by running:
``` ```
yarn build && yarn test yarn test-unit
``` ```
from the root of the project. from the root of the project.

View File

@@ -9,7 +9,6 @@ A Runtime is an npm module that implements the following interface:
interface Runtime { interface Runtime {
version: number; version: number;
build: (options: BuildOptions) => Promise<BuildResult>; build: (options: BuildOptions) => Promise<BuildResult>;
analyze?: (options: AnalyzeOptions) => Promise<string>;
prepareCache?: (options: PrepareCacheOptions) => Promise<CacheOutputs>; prepareCache?: (options: PrepareCacheOptions) => Promise<CacheOutputs>;
shouldServe?: (options: ShouldServeOptions) => Promise<boolean>; shouldServe?: (options: ShouldServeOptions) => Promise<boolean>;
startDevServer?: ( startDevServer?: (
@@ -72,26 +71,6 @@ export async function build(options: BuildOptions) {
} }
``` ```
### `analyze()`
An **optional** exported function that returns a unique fingerprint used for the
purpose of [build
de-duplication](https://vercel.com/docs/v2/platform/deployments#deduplication).
If the `analyze()` function is not supplied, then a random fingerprint is
assigned to each build.
**Example:**
```typescript
import { AnalyzeOptions } from '@vercel/build-utils';
export async function analyze(options: AnalyzeOptions) {
// Do calculations to generate a fingerprint based off the source code here…
return 'fingerprint goes here';
}
```
### `prepareCache()` ### `prepareCache()`
An **optional** exported function that is executed after [`build()`](#build) is An **optional** exported function that is executed after [`build()`](#build) is

46
api/_lib/script/build.ts Normal file
View File

@@ -0,0 +1,46 @@
import fs from 'fs/promises';
import { join } from 'path';
import { getExampleList } from '../examples/example-list';
import { mapOldToNew } from '../examples/map-old-to-new';
const repoRoot = join(__dirname, '..', '..', '..');
const pubDir = join(repoRoot, 'public');
async function main() {
console.log(`Building static frontend ${repoRoot}...`);
await fs.rm(pubDir, { recursive: true, force: true });
await fs.mkdir(pubDir);
const examples = await getExampleList();
const pathListAll = join(pubDir, 'list-all.json');
await fs.writeFile(pathListAll, JSON.stringify(examples));
const exampleDirs = await fs.readdir(join(repoRoot, 'examples'), {
withFileTypes: true,
});
const existingExamples = exampleDirs
.filter(dir => dir.isDirectory())
.map(dir => ({
name: dir.name,
visible: true,
suggestions: [],
}));
const oldExamples = Object.keys(mapOldToNew).map(key => ({
name: key,
visible: false,
suggestions: mapOldToNew[key],
}));
const pathList = join(pubDir, 'list.json');
await fs.writeFile(
pathList,
JSON.stringify([...existingExamples, ...oldExamples])
);
console.log('Completed building static frontend.');
}
main().catch(console.error);

View File

@@ -1,10 +0,0 @@
import { VercelRequest, VercelResponse } from '@vercel/node';
import { getExampleList } from '../_lib/examples/example-list';
import { withApiHandler } from '../_lib/util/with-api-handler';
export default withApiHandler(async function (
req: VercelRequest,
res: VercelResponse
) {
res.status(200).json(await getExampleList());
});

View File

@@ -1,27 +0,0 @@
import { extract } from '../_lib/examples/extract';
import { summary } from '../_lib/examples/summary';
import { VercelRequest, VercelResponse } from '@vercel/node';
import { mapOldToNew } from '../_lib/examples/map-old-to-new';
import { withApiHandler } from '../_lib/util/with-api-handler';
export default withApiHandler(async function (
req: VercelRequest,
res: VercelResponse
) {
await extract('https://github.com/vercel/vercel/archive/main.zip', '/tmp');
const exampleList = summary('/tmp/vercel-main/examples');
const existingExamples = Array.from(exampleList).map(key => ({
name: key,
visible: true,
suggestions: [],
}));
const oldExamples = Object.keys(mapOldToNew).map(key => ({
name: key,
visible: false,
suggestions: mapOldToNew[key],
}));
res.status(200).json([...existingExamples, ...oldExamples]);
});

View File

@@ -0,0 +1,20 @@
MIT License
Copyright (c) 2022 Zach Leatherman @zachleat
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.

View File

@@ -1,5 +1,19 @@
{ {
"private": true, "private": true,
"repository": {
"type": "git",
"url": "git://github.com/11ty/eleventy-base-blog.git"
},
"author": {
"name": "Zach Leatherman",
"email": "zachleatherman@gmail.com",
"url": "https://zachleat.com/"
},
"license": "MIT",
"bugs": {
"url": "https://github.com/11ty/eleventy-base-blog/issues"
},
"homepage": "https://github.com/11ty/eleventy-base-blog#readme",
"scripts": { "scripts": {
"build": "eleventy", "build": "eleventy",
"watch": "eleventy --watch", "watch": "eleventy --watch",

View File

@@ -1,2 +1,19 @@
# Hugo
public
.hugo_build.lock
## OS Files
# Windows
Thumbs.db
ehthumbs.db
Desktop.ini
$RECYCLE.BIN/
# OSX
.DS_Store
# Env Variables
.env .env
.env.build .env.build
.vercel

View File

@@ -1,4 +1,39 @@
baseURL = "http://example.org/" baseURL = "https://hugo-template.vercel.app"
languageCode = "en-us" title = "Hugo Template"
title = "My New Hugo Site" theme = "etch"
theme = "ananke" languageCode = "en-US"
enableInlineShortcodes = true
pygmentsCodeFences = true
pygmentsUseClasses = true
ignoreErrors = ["error-missing-instagram-accesstoken"]
[params]
description = "A Hugo template, hosted with Vercel."
copyright = "Copyright © 2021 Your Name"
dark = "auto"
highlight = true
[menu]
[[menu.main]]
identifier = "posts"
name = "posts"
title = "posts"
url = "/"
weight = 10
[[menu.main]]
identifier = "about"
name = "about"
title = "about"
url = "/about/"
weight = 20
[permalinks]
posts = "/:title/"
[markup.goldmark.renderer]
# Allow HTML in Markdown
unsafe = true
[markup.tableOfContents]
ordered = true

View File

@@ -0,0 +1,5 @@
---
title: 'Home'
---
This is some info about me.

View File

@@ -0,0 +1,21 @@
+++
title = "About"
+++
Written in Go, Hugo is an open source static site generator available under the [Apache Licence 2.0.](https://github.com/gohugoio/hugo/blob/master/LICENSE) Hugo supports TOML, YAML and JSON data file types, Markdown and HTML content files and uses shortcodes to add rich content. Other notable features are taxonomies, multilingual mode, image processing, custom output formats, HTML/CSS/JS minification and support for Sass SCSS workflows.
Hugo makes use of a variety of open source projects including:
- https://github.com/yuin/goldmark
- https://github.com/alecthomas/chroma
- https://github.com/muesli/smartcrop
- https://github.com/spf13/cobra
- https://github.com/spf13/viper
Hugo is ideal for blogs, corporate websites, creative portfolios, online magazines, single page applications or even a website with thousands of pages.
Hugo is for people who want to hand code their own website without worrying about setting up complicated runtimes, dependencies and databases.
Websites built with Hugo are extremelly fast, secure and can be deployed anywhere including, AWS, GitHub Pages, Heroku, Netlify and any other hosting provider.
Learn more and contribute on [GitHub](https://github.com/gohugoio).

View File

@@ -0,0 +1,50 @@
+++
author = "Hugo Authors"
title = "Emoji Support"
date = "2019-03-05"
description = "Guide to emoji usage in Hugo"
tags = [
"emoji",
]
+++
Emoji can be enabled in a Hugo project in a number of ways.
<!--more-->
The [`emojify`](https://gohugo.io/functions/emojify/) function can be called directly in templates or [Inline Shortcodes](https://gohugo.io/templates/shortcode-templates/#inline-shortcodes).
To enable emoji globally, set `enableEmoji` to `true` in your sites [configuration](https://gohugo.io/getting-started/configuration/) and then you can type emoji shorthand codes directly in content files; e.g.
<p><span class="nowrap"><span class="emojify">🙈</span> <code>:see_no_evil:</code></span> <span class="nowrap"><span class="emojify">🙉</span> <code>:hear_no_evil:</code></span> <span class="nowrap"><span class="emojify">🙊</span> <code>:speak_no_evil:</code></span></p>
<br>
The [Emoji cheat sheet](http://www.emoji-cheat-sheet.com/) is a useful reference for emoji shorthand codes.
---
**N.B.** The above steps enable Unicode Standard emoji characters and sequences in Hugo, however the rendering of these glyphs depends on the browser and the platform. To style the emoji you can either use a third party emoji font or a font stack; e.g.
{{< highlight html >}}
.emoji {
font-family: Apple Color Emoji,Segoe UI Emoji,NotoColorEmoji,Segoe UI Symbol,Android Emoji,EmojiSymbols;
}
{{< /highlight >}}
{{< css.inline >}}
<style>
.emojify {
font-family: Apple Color Emoji,Segoe UI Emoji,NotoColorEmoji,Segoe UI Symbol,Android Emoji,EmojiSymbols;
font-size: 2rem;
vertical-align: middle;
}
@media screen and (max-width:650px) {
.nowrap {
display: block;
margin: 25px 0;
}
}
</style>
{{< /css.inline >}}

View File

@@ -0,0 +1,155 @@
+++
author = "Hugo Authors"
title = "Markdown Syntax Guide"
date = "2019-03-11"
description = "Sample article showcasing basic Markdown syntax and formatting for HTML elements."
tags = [
"markdown",
"css",
"html",
"themes",
]
categories = [
"themes",
"syntax",
]
series = ["Themes Guide"]
aliases = ["migrate-from-jekyl"]
+++
This article offers a sample of basic Markdown syntax that can be used in Hugo content files, also it shows whether basic HTML elements are decorated with CSS in a Hugo theme.
<!--more-->
## Headings
The following HTML `<h1>``<h6>` elements represent six levels of section headings. `<h1>` is the highest section level while `<h6>` is the lowest.
# H1
## H2
### H3
#### H4
##### H5
###### H6
## Paragraph
Xerum, quo qui aut unt expliquam qui dolut labo. Aque venitatiusda cum, voluptionse latur sitiae dolessi aut parist aut dollo enim qui voluptate ma dolestendit peritin re plis aut quas inctum laceat est volestemque commosa as cus endigna tectur, offic to cor sequas etum rerum idem sintibus eiur? Quianimin porecus evelectur, cum que nis nust voloribus ratem aut omnimi, sitatur? Quiatem. Nam, omnis sum am facea corem alique molestrunt et eos evelece arcillit ut aut eos eos nus, sin conecerem erum fuga. Ri oditatquam, ad quibus unda veliamenimin cusam et facea ipsamus es exerum sitate dolores editium rerore eost, temped molorro ratiae volorro te reribus dolorer sperchicium faceata tiustia prat.
Itatur? Quiatae cullecum rem ent aut odis in re eossequodi nonsequ idebis ne sapicia is sinveli squiatum, core et que aut hariosam ex eat.
## Blockquotes
The blockquote element represents content that is quoted from another source, optionally with a citation which must be within a `footer` or `cite` element, and optionally with in-line changes such as annotations and abbreviations.
#### Blockquote without attribution
> Tiam, ad mint andaepu dandae nostion secatur sequo quae.
> **Note** that you can use _Markdown syntax_ within a blockquote.
#### Blockquote with attribution
> Don't communicate by sharing memory, share memory by communicating.</p>
> — <cite>Rob Pike[^1]</cite>
[^1]: The above quote is excerpted from Rob Pike's [talk](https://www.youtube.com/watch?v=PAAkCSZUG1c) during Gopherfest, November 18, 2015.
## Tables
Tables aren't part of the core Markdown spec, but Hugo supports supports them out-of-the-box.
| Name | Age |
| ----- | --- |
| Bob | 27 |
| Alice | 23 |
#### Inline Markdown within tables
| Inline&nbsp;&nbsp;&nbsp; | Markdown&nbsp;&nbsp;&nbsp; | In&nbsp;&nbsp;&nbsp; | Table |
| ------------------------ | -------------------------- | ----------------------------------- | ------ |
| _italics_ | **bold** | ~~strikethrough~~&nbsp;&nbsp;&nbsp; | `code` |
## Code Blocks
#### Code block with backticks
```
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Example HTML5 Document</title>
</head>
<body>
<p>Test</p>
</body>
</html>
```
#### Code block indented with four spaces
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Example HTML5 Document</title>
</head>
<body>
<p>Test</p>
</body>
</html>
#### Code block with Hugo's internal highlight shortcode
{{< highlight html >}}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Example HTML5 Document</title>
</head>
<body>
<p>Test</p>
</body>
</html>
{{< /highlight >}}
## List Types
#### Ordered List
1. First item
2. Second item
3. Third item
#### Unordered List
- List item
- Another item
- And another item
#### Nested list
- Item
1. First Sub-item
2. Second Sub-item
## Other Elements — abbr, sub, sup, kbd, mark
<abbr title="Graphics Interchange Format">GIF</abbr> is a bitmap image format.
H<sub>2</sub>O
X<sup>n</sup> + Y<sup>n</sup> = Z<sup>n</sup>
Press <kbd><kbd>CTRL</kbd>+<kbd>ALT</kbd>+<kbd>Delete</kbd></kbd> to end the session.
Most <mark>salamanders</mark> are nocturnal, and hunt for insects, worms, and other small creatures.

View File

@@ -1,7 +0,0 @@
---
title: 'My First Post'
date: 2019-07-18T17:18:05+01:00
draft: false
---
# Hugo on Vercel

View File

@@ -0,0 +1,60 @@
+++
author = "Hugo Authors"
title = "Placeholder Text"
date = "2019-03-09"
description = "Lorem Ipsum Dolor Si Amet"
tags = [
"markdown",
"text",
]
+++
Lorem est tota propiore conpellat pectoribus de
pectora summo. <!--more-->Redit teque digerit hominumque toris verebor lumina non cervice
subde tollit usus habet Arctonque, furores quas nec ferunt. Quoque montibus nunc
caluere tempus inhospita parcite confusaque translucet patri vestro qui optatis
lumine cognoscere flos nubis! Fronde ipsamque patulos Dryopen deorum.
1. Exierant elisi ambit vivere dedere
2. Duce pollice
3. Eris modo
4. Spargitque ferrea quos palude
Rursus nulli murmur; hastile inridet ut ab gravi sententia! Nomine potitus
silentia flumen, sustinet placuit petis in dilapsa erat sunt. Atria
tractus malis.
1. Comas hunc haec pietate fetum procerum dixit
2. Post torum vates letum Tiresia
3. Flumen querellas
4. Arcanaque montibus omnes
5. Quidem et
# Vagus elidunt
<svg class="canon" xmlns="http://www.w3.org/2000/svg" overflow="visible" viewBox="0 0 496 373" height="373" width="496"><g fill="none"><path stroke="#000" stroke-width=".75" d="M.599 372.348L495.263 1.206M.312.633l494.95 370.853M.312 372.633L247.643.92M248.502.92l246.76 370.566M330.828 123.869V1.134M330.396 1.134L165.104 124.515"></path><path stroke="#ED1C24" stroke-width=".75" d="M275.73 41.616h166.224v249.05H275.73zM54.478 41.616h166.225v249.052H54.478z"></path><path stroke="#000" stroke-width=".75" d="M.479.375h495v372h-495zM247.979.875v372"></path><ellipse cx="498.729" cy="177.625" rx=".75" ry="1.25"></ellipse><ellipse cx="247.229" cy="377.375" rx=".75" ry="1.25"></ellipse></g></svg>
[The Van de Graaf Canon](https://en.wikipedia.org/wiki/Canons_of_page_construction#Van_de_Graaf_canon)
## Mane refeci capiebant unda mulcebat
Victa caducifer, malo vulnere contra
dicere aurato, ludit regale, voca! Retorsit colit est profanae esse virescere
furit nec; iaculi matertera et visa est, viribus. Divesque creatis, tecta novat collumque vulnus est, parvas. **Faces illo pepulere** tempus adest. Tendit flamma, ab opes virum sustinet, sidus sequendo urbis.
Iubar proles corpore raptos vero auctor imperium; sed et huic: manus caeli
Lelegas tu lux. Verbis obstitit intus oblectamina fixis linguisque ausus sperare
Echionides cornuaque tenent clausit possit. Omnia putatur. Praeteritae refert
ausus; ferebant e primus lora nutat, vici quae mea ipse. Et iter nil spectatae
vulnus haerentia iuste et exercebat, sui et.
Eurytus Hector, materna ipsumque ut Politen, nec, nate, ignari, vernum cohaesit sequitur. Vel **mitis temploque** vocatus, inque alis, _oculos nomen_ non silvis corpore coniunx ne displicet illa. Crescunt non unus, vidit visa quantum inmiti flumina mortis facto sic: undique a alios vincula sunt iactata abdita! Suspenderat ego fuit tendit: luna, ante urbem
Propoetides **parte**.
{{< css.inline >}}
<style>
.canon { background: white; width: 100%; height: auto;}
</style>
{{< /css.inline >}}

View File

@@ -0,0 +1,42 @@
+++
author = "Hugo Authors"
title = "Rich Content"
date = "2019-03-10"
description = "A brief description of Hugo Shortcodes"
tags = [
"shortcodes",
"privacy",
]
+++
Hugo ships with several [Built-in Shortcodes](https://gohugo.io/content-management/shortcodes/#use-hugo-s-built-in-shortcodes) for rich content, along with a [Privacy Config](https://gohugo.io/about/hugo-and-gdpr/) and a set of Simple Shortcodes that enable static and no-JS versions of various social media embeds.
## <!--more-->
## Instagram Simple Shortcode
{{< instagram_simple BGvuInzyFAe hidecaption >}}
<br>
---
## YouTube Privacy Enhanced Shortcode
{{< youtube ZJthWmvUzzc >}}
<br>
---
## Twitter Simple Shortcode
{{< twitter_simple 1085870671291310081 >}}
<br>
---
## Vimeo Simple Shortcode
{{< vimeo_simple 48912912 >}}

View File

@@ -1,17 +0,0 @@
[more]
other = "Ещё"
[allTitle]
other = "Все {{.Title }}"
[recentTitle]
other = "Недавние {{.Title }}"
[readMore]
other = "читать дальше"
[whatsInThis]
other = "Содержание {{ .Type }}"
[related]
other = "Схожие"

File diff suppressed because one or more lines are too long

View File

@@ -1 +0,0 @@
!function(n){function t(e){if(r[e])return r[e].exports;var o=r[e]={i:e,l:!1,exports:{}};return n[e].call(o.exports,o,o.exports,t),o.l=!0,o.exports}var r={};t.m=n,t.c=r,t.i=function(n){return n},t.d=function(n,r,e){t.o(n,r)||Object.defineProperty(n,r,{configurable:!1,enumerable:!0,get:e})},t.n=function(n){var r=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(r,"a",r),r},t.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},t.p="",t(t.s=1)}([function(n,t){},function(n,t,r){"use strict";var e=r(0);!function(n){n&&n.__esModule}(e)}]);

1
examples/hugo/themes/etch/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
.DS_Store

View File

@@ -0,0 +1,20 @@
The MIT License (MIT)
Copyright (c) 2020 Lukas Joswiak
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.

View File

@@ -0,0 +1,33 @@
# Etch
Etch is a simple, responsive theme for [Hugo](https://gohugo.io) with a focus on writing. A live demo is available at https://lukasjoswiak.github.io/etch/.
<img src="https://raw.githubusercontent.com/LukasJoswiak/etch/master/images/screenshot_small.png" alt="screenshot" width="545px">
## Features:
- Homepage with list of posts.
- Support for pages.
- Responsive design for optimized mobile experience.
- Syntax highlighting with customizable theme.
- Dark theme which automatically adjusts based on users' setting ([example](https://github.com/LukasJoswiak/etch/wiki/Dark-mode)).
- No external dependencies, no JavaScript, no web fonts.
- Internationalization friendly: use default English translations or create your own
## Installation
To install `etch`, download the repository into the `themes` folder in the root of your site.
```
$ git submodule add https://github.com/LukasJoswiak/etch.git themes/etch
```
Then, use the theme to generate your site.
```
$ hugo server -t etch
```
Use the [sample configuration](https://github.com/LukasJoswiak/etch/wiki/Configuration#sample-configuration) as a starting point. See the [configuration](https://github.com/LukasJoswiak/etch/wiki/Configuration) page for more info.
Read the [wiki](https://github.com/LukasJoswiak/etch/wiki) to learn about more options.

View File

@@ -0,0 +1,2 @@
+++
+++

View File

@@ -0,0 +1,53 @@
{{ if not (eq .Site.Params.dark "on") -}}
@media (prefers-color-scheme: dark) {
{{ end -}}
html {
scrollbar-color: #6c6c6c #2e2e2e;
}
body {
color: #ebebeb;
background: #121212;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
header#banner a {
color: #e0e0e0;
text-decoration: none;
}
header#banner nav ul li a {
color: #cccccc;
}
main#content a {
color: #00b1ed;
}
main#content p {
color: #f5f5f5;
}
main#content hr {
background: #5c5c5c;
}
main#content #toc h4 {
color: #d4d4d4;
}
main#content ul#posts small {
color: #a7a7a7;
}
main#content ul#posts li a:hover {
color: #21c7ff;
}
main#content header#post-header div {
color: #a7a7a7;
}
{{- if not (eq .Site.Params.dark "on") -}}
}
{{- end -}}

View File

@@ -0,0 +1,281 @@
*, *:before, *:after {
box-sizing: border-box;
}
html {
font-size: 62.5%;
}
body {
font-size: 16px;
font-size: 1.6rem;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
color: #313a3d;
width: 100%;
margin: 0 auto;
padding: 0 16px;
line-height: 1.6;
}
header#banner {
margin: 25px 0;
}
header#banner a {
color: #313a3d;
text-decoration: none;
}
header#banner a:hover {
text-decoration: underline;
}
header#banner h2 {
display: inline;
font-size: 21px;
font-size: 2.1rem;
margin: 0 8px 0 0;
}
header#banner nav {
display: inline-block;
}
header#banner nav ul {
list-style-type: none;
font-size: 1.05em;
text-transform: lowercase;
margin: 0;
padding: 0;
}
header#banner nav ul li {
display: inline;
margin: 0 3px;
}
header#banner nav ul li a {
color: #454545;
}
main#content a {
color: #007dfa;
text-decoration: none;
}
main#content a:hover {
text-decoration: underline;
}
main#content h1,
main#content h2,
main#content h3,
main#content h4,
main#content h5,
main#content h6 {
margin-bottom: 0;
line-height: 1.15;
}
main#content h3 {
font-size: 19px;
font-size: 1.9rem;
}
main#content h1 + p,
main#content h2 + p,
main#content h3 + p,
main#content h4 + p,
main#content h5 + p,
main#content h6 + p {
margin-top: 5px;
}
main#content p {
color: #394548;
margin: 16px 0;
}
main#content hr {
height: 1px;
border: 0;
background: #d8d8d8;
}
main#content abbr {
cursor: help;
}
/* index.html styles */
main#content ul#posts {
list-style-type: none;
font-size: 16px;
font-size: 1.6rem;
margin-top: 0;
padding: 0;
}
main#content ul#posts li {
margin: 5px 0;
padding: 0;
}
main#content ul#posts small {
font-size: 0.8em;
color: #767676;
margin-left: 10px;
}
main#content ul#posts li a {
text-decoration: none;
}
main#content ul#posts li a:hover {
color: #369aff;
}
main#content ul#posts li a:hover small {
color: inherit;
}
/* single.html styles */
main#content header#post-header h1 {
display: block;
font-size: 23px;
font-size: 2.3rem;
font-weight: 600;
line-height: 1.15;
}
main#content header#post-header > div {
display: block;
font-size: 0.85em;
color: #767676;
}
main#content #toc {
border: 1px solid #b1b1b1;
border-radius: 1px;
line-height: 26px;
margin: 16px 0;
padding: 9px 14px;
}
main#content #toc h4 {
font-size: 1.06em;
color: #3d3d3d;
margin: 0;
}
main#content #toc nav#TableOfContents {
margin-top: 4px;
}
main#content #toc nav#TableOfContents > ul, main#content #toc nav#TableOfContents > ol {
margin-left: -40px;
}
main#content #toc ul, main#content #toc ol {
font-size: 0.98em;
margin: 0;
padding: 0 0 0 40px;
}
main#content #toc ul {
list-style-type: none;
}
main#content #toc ol {
counter-reset: item;
}
main#content #toc ol li {
display: block;
}
main#content #toc ol li:before {
content: counters(item, ".") ". ";
counter-increment: item;
}
main#content img {
max-width: 100%;
margin: 0 auto;
}
main#content figure {
margin: 16px 0;
}
main#content figure img {
display: block;
max-width: 100%;
margin: 0 auto;
}
main#content figure figcaption {
font-size: 0.92em;
font-style: italic;
line-height: 22px;
text-align: center;
margin-top: 6px;
padding: 0 10px;
}
main#content figure figcaption h4 {
font-style: normal;
display: inline;
margin: 0;
}
main#content figure figcaption p {
display: inline;
margin: 0;
padding-left: 8px;
}
main#content blockquote {
font-style: italic;
margin-top: 10px;
margin-bottom: 10px;
margin-left: 50px;
padding-left: 15px;
border-left: 3px solid #ccc;
}
main#content code,
main#content pre {
font-family: 'Menlo', monospace;
}
main#content code {
font-size: 0.96em;
padding: 0 5px;
}
main#content pre {
display: block;
overflow-x: auto;
font-size: 14px;
font-size: 1.4rem;
white-space: pre;
margin: 20px 0;
padding: 1.5rem 1.5rem;
line-height: 1.4;
}
main#content pre code {
padding: 0;
}
main#content section.footnotes {
font-size: 0.9em;
}
footer#footer {
font-size: 14px;
font-size: 1.4rem;
font-weight: 400;
color: #b3b3b3;
margin: 40px 0;
}

View File

@@ -0,0 +1,52 @@
@media (min-width: 770px) {
body {
width: 600px;
line-height: 1.5;
}
main#content hr {
width: 108%;
margin-left: -3.8%;
}
/* index.html styles */
header#banner h2 {
font-size: 25px;
font-size: 2.5rem;
}
main#content h3 {
font-size: 20px;
font-size: 2rem;
}
main#content ul#posts {
font-size: 18px;
font-size: 1.8rem;
}
/* single.html styles */
main#content header#post-header h1 {
font-size: 24px;
font-size: 2.4rem;
}
main#content img {
max-width: 108%;
margin-left: -3.8%;
}
main#content figure {
margin-left: -3.8%;
}
main#content figure img {
max-width: 108%;
}
main#content pre {
width: 108%;
margin-left: -3.8%;
padding: 1.5rem 2.2rem;
}
}

View File

@@ -0,0 +1,59 @@
/* Background */ .chroma { color: #f8f8f2; background-color: #272822 }
/* Error */ .chroma .err { color: #960050; background-color: #1e0010 }
/* LineTableTD */ .chroma .lntd { vertical-align: top; padding: 0; margin: 0; border: 0; }
/* LineTable */ .chroma .lntable { border-spacing: 0; padding: 0; margin: 0; border: 0; width: auto; overflow: auto; display: block; }
/* LineHighlight */ .chroma .hl { display: block; width: 100%;background-color: #ffffcc }
/* LineNumbersTable */ .chroma .lnt { margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #7f7f7f }
/* LineNumbers */ .chroma .ln { margin-right: 0.4em; padding: 0 0.4em 0 0.4em;color: #7f7f7f }
/* Keyword */ .chroma .k { color: #66d9ef }
/* KeywordConstant */ .chroma .kc { color: #66d9ef }
/* KeywordDeclaration */ .chroma .kd { color: #66d9ef }
/* KeywordNamespace */ .chroma .kn { color: #f92672 }
/* KeywordPseudo */ .chroma .kp { color: #66d9ef }
/* KeywordReserved */ .chroma .kr { color: #66d9ef }
/* KeywordType */ .chroma .kt { color: #66d9ef }
/* NameAttribute */ .chroma .na { color: #a6e22e }
/* NameClass */ .chroma .nc { color: #a6e22e }
/* NameConstant */ .chroma .no { color: #66d9ef }
/* NameDecorator */ .chroma .nd { color: #a6e22e }
/* NameException */ .chroma .ne { color: #a6e22e }
/* NameFunction */ .chroma .nf { color: #a6e22e }
/* NameOther */ .chroma .nx { color: #a6e22e }
/* NameTag */ .chroma .nt { color: #f92672 }
/* Literal */ .chroma .l { color: #ae81ff }
/* LiteralDate */ .chroma .ld { color: #e6db74 }
/* LiteralString */ .chroma .s { color: #e6db74 }
/* LiteralStringAffix */ .chroma .sa { color: #e6db74 }
/* LiteralStringBacktick */ .chroma .sb { color: #e6db74 }
/* LiteralStringChar */ .chroma .sc { color: #e6db74 }
/* LiteralStringDelimiter */ .chroma .dl { color: #e6db74 }
/* LiteralStringDoc */ .chroma .sd { color: #e6db74 }
/* LiteralStringDouble */ .chroma .s2 { color: #e6db74 }
/* LiteralStringEscape */ .chroma .se { color: #ae81ff }
/* LiteralStringHeredoc */ .chroma .sh { color: #e6db74 }
/* LiteralStringInterpol */ .chroma .si { color: #e6db74 }
/* LiteralStringOther */ .chroma .sx { color: #e6db74 }
/* LiteralStringRegex */ .chroma .sr { color: #e6db74 }
/* LiteralStringSingle */ .chroma .s1 { color: #e6db74 }
/* LiteralStringSymbol */ .chroma .ss { color: #e6db74 }
/* LiteralNumber */ .chroma .m { color: #ae81ff }
/* LiteralNumberBin */ .chroma .mb { color: #ae81ff }
/* LiteralNumberFloat */ .chroma .mf { color: #ae81ff }
/* LiteralNumberHex */ .chroma .mh { color: #ae81ff }
/* LiteralNumberInteger */ .chroma .mi { color: #ae81ff }
/* LiteralNumberIntegerLong */ .chroma .il { color: #ae81ff }
/* LiteralNumberOct */ .chroma .mo { color: #ae81ff }
/* Operator */ .chroma .o { color: #f92672 }
/* OperatorWord */ .chroma .ow { color: #f92672 }
/* Comment */ .chroma .c { color: #75715e }
/* CommentHashbang */ .chroma .ch { color: #75715e }
/* CommentMultiline */ .chroma .cm { color: #75715e }
/* CommentSingle */ .chroma .c1 { color: #75715e }
/* CommentSpecial */ .chroma .cs { color: #75715e }
/* CommentPreproc */ .chroma .cp { color: #75715e }
/* CommentPreprocFile */ .chroma .cpf { color: #75715e }
/* GenericDeleted */ .chroma .gd { color: #f92672 }
/* GenericEmph */ .chroma .ge { font-style: italic }
/* GenericInserted */ .chroma .gi { color: #a6e22e }
/* GenericStrong */ .chroma .gs { font-weight: bold }
/* GenericSubheading */ .chroma .gu { color: #75715e }

View File

@@ -0,0 +1,19 @@
# Learn how to use Date format (date, created, updated)
# -> https://gohugo.io/functions/dateformat/
[posts]
[posts.title]
other = "Posts"
[posts.date]
other = "Jan 2, 2006"
[post]
[post.created]
other = "January 2, 2006"
[post.updated]
other = "Updated January 2, 2006"

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

View File

@@ -0,0 +1,11 @@
<!DOCTYPE html>
<html>
{{- partial "head.html" . -}}
<body>
{{- partial "header.html" . -}}
<main id="content">
{{- block "main" . }}{{- end }}
</main>
{{- partial "footer.html" . -}}
</body>
</html>

View File

@@ -0,0 +1,6 @@
<li>
<a href="{{ .Permalink }}">
{{ .Title }}
<small><time>{{ .Date | time.Format (i18n "posts.date") }}</time></small>
</a>
</li>

View File

@@ -0,0 +1,3 @@
{{ define "main" }}
{{- partial "posts.html" . -}}
{{ end }}

View File

@@ -0,0 +1,41 @@
{{- $pctx := . -}}
{{- if .IsHome -}}{{ $pctx = .Site }}{{- end -}}
{{- $pages := slice -}}
{{- if or $.IsHome $.IsSection -}}
{{- $pages = $pctx.RegularPages -}}
{{- else -}}
{{- $pages = $pctx.Pages -}}
{{- end -}}
{{- $limit := .Site.Config.Services.RSS.Limit -}}
{{- if ge $limit 1 -}}
{{- $pages = $pages | first $limit -}}
{{- end -}}
{{- printf "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>" | safeHTML }}
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>{{ if eq .Title .Site.Title }}{{ .Site.Title }}{{ else }}{{ with .Title }}{{.}} on {{ end }}{{ .Site.Title }}{{ end }}</title>
<link>{{ .Permalink }}</link>
<description>Recent content {{ if ne .Title .Site.Title }}{{ with .Title }}in {{.}} {{ end }}{{ end }}on {{ .Site.Title }}</description>
<generator>Hugo -- gohugo.io</generator>{{ with .Site.LanguageCode }}
<language>{{.}}</language>{{end}}{{ with .Site.Author.email }}
<managingEditor>{{.}}{{ with $.Site.Author.name }} ({{.}}){{end}}</managingEditor>{{end}}{{ with .Site.Author.email }}
<webMaster>{{.}}{{ with $.Site.Author.name }} ({{.}}){{end}}</webMaster>{{end}}{{ with .Site.Copyright }}
<copyright>{{.}}</copyright>{{end}}{{ if not .Date.IsZero }}
<lastBuildDate>{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}</lastBuildDate>{{ end }}
{{ with .OutputFormats.Get "RSS" }}
{{ printf "<atom:link href=%q rel=\"self\" type=%q />" .Permalink .MediaType | safeHTML }}
{{ end }}
{{ range where .Site.Pages "Kind" "page" }}
{{ if or (eq .Section "posts") (eq .Section "post") }}
<item>
<title>{{ .Title }}</title>
<link>{{ .Permalink }}</link>
<pubDate>{{ .Date.Format "Mon, 02 Jan 2006 15:04:05 -0700" | safeHTML }}</pubDate>
{{ with .Site.Author.email }}<author>{{.}}{{ with $.Site.Author.name }} ({{.}}){{end}}</author>{{end}}
<guid>{{ .Permalink }}</guid>
<description>{{ .Content | html }}</description>
</item>
{{ end }}
{{ end }}
</channel>
</rss>

View File

@@ -0,0 +1,17 @@
{{ define "main" }}
<article>
<header id="post-header">
<h1>{{ .Title }}</h1>
<div>
{{- if isset .Params "date" -}}
{{ if eq .Lastmod .Date }}
<time>{{ .Date | time.Format (i18n "post.created") }}</time>
{{ else }}
<time>{{ .Lastmod | time.Format (i18n "post.updated") }}</time>
{{ end }}
{{- end -}}
</div>
</header>
{{- .Content -}}
</article>
{{ end }}

View File

@@ -0,0 +1,8 @@
{{ define "main" }}
<h3>{{ .Title }}</h3>
<ul id="posts">
{{- range .Pages }}
{{ .Render "li" }}
{{- end }}
</ul>
{{ end }}

View File

@@ -0,0 +1,4 @@
{{ define "main" }}
{{ .Content }}
{{- partial "posts.html" . -}}
{{ end }}

View File

@@ -0,0 +1,3 @@
<footer id="footer">
{{ .Site.Params.copyright }}
</footer>

View File

@@ -0,0 +1,31 @@
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
{{ with .Site.Params.description -}}
<meta name="description" content="{{ . }}">
{{ end }}
{{ printf `<link rel="shortcut icon" href="%s">` ("favicon.ico" | absURL) | safeHTML }}
{{ with .OutputFormats.Get "rss" -}}
{{ printf `<link rel="%s" type="%s" href="%s" title="%s">` .Rel .MediaType.Type .Permalink $.Site.Title | safeHTML }}
{{ end -}}
{{ $resources := slice -}}
{{ $resources = $resources | append (resources.Get "css/main.css") -}}
{{ $resources = $resources | append (resources.Get "css/min770px.css") -}}
{{ $dark := .Site.Params.dark | default "auto" -}}
{{ if not (eq $dark "off") -}}
{{ $resources = $resources | append (resources.Get "css/dark.css" | resources.ExecuteAsTemplate "dark.css" .) -}}
{{ end -}}
{{ if .Site.Params.highlight -}}
{{ $resources = $resources | append (resources.Get "css/syntax.css") -}}
{{ end -}}
{{ $css := $resources | resources.Concat "css/style.css" | minify }}
{{ printf `<link rel="stylesheet" href="%s">` $css.RelPermalink | safeHTML }}
<title>{{ .Title }}</title>
</head>

View File

@@ -0,0 +1,12 @@
<header id="banner">
<h2><a href="{{ .Site.BaseURL }}">{{ .Site.Title }}</a></h2>
<nav>
<ul>
{{ range .Site.Menus.main.ByWeight -}}
<li>
{{ .Pre }}<a href="{{ .URL }}" title="{{ .Title }}">{{- .Name -}}</a>{{ .Post }}
</li>
{{- end }}
</ul>
</nav>
</header>

View File

@@ -0,0 +1,6 @@
<h3>{{ i18n "posts.title" }}</h3>
<ul id="posts">
{{- range where site.RegularPages "Type" "in" site.Params.mainSections }}
{{ .Render "li" }}
{{- end }}
</ul>

View File

@@ -0,0 +1,4 @@
<aside id="toc">
<h4>Table of Contents</h4>
{{ .Page.TableOfContents }}
</aside>

View File

@@ -0,0 +1,13 @@
name = "Etch"
license = "MIT"
licenselink = "https://github.com/LukasJoswiak/etch/blob/master/LICENSE"
description = "Lightweight Hugo theme with a focus on content"
homepage = "https://github.com/LukasJoswiak/etch"
demosite = "https://lukasjoswiak.github.io/etch/"
tags = ["simple", "minimal", "clean", "fast", "blog", "responsive", "dark mode", "privacy"]
features = ["fast", "blog", "syntax highlighting", "dark mode"]
min_version = "0.41"
[author]
name = "Lukas Joswiak"
homepage = "https://lukasjoswiak.com"

View File

@@ -23,6 +23,7 @@
npm-debug.log* npm-debug.log*
yarn-debug.log* yarn-debug.log*
yarn-error.log* yarn-error.log*
.pnpm-debug.log*
# local env files # local env files
.env.local .env.local

View File

@@ -1,3 +1,6 @@
module.exports = { /** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true, reactStrictMode: true,
} }
module.exports = nextConfig

File diff suppressed because it is too large Load Diff

View File

@@ -7,12 +7,12 @@
"lint": "next lint" "lint": "next lint"
}, },
"dependencies": { "dependencies": {
"next": "^12.0.8", "next": "12.1.0",
"react": "17.0.2", "react": "17.0.2",
"react-dom": "17.0.2" "react-dom": "17.0.2"
}, },
"devDependencies": { "devDependencies": {
"eslint": "8.7.0", "eslint": "8.9.0",
"eslint-config-next": "^12.0.8" "eslint-config-next": "12.1.0"
} }
} }

1633
examples/nextjs/yarn.lock Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -31,7 +31,7 @@ export default function Index() {
<p> <p>
Wait a sec...<em>its children</em>? To understand what we mean by Wait a sec...<em>its children</em>? To understand what we mean by
this,{" "} this,{" "}
<a href="https://remix.run/tutorial/4-nested-routes-params"> <a href="https://remix.run/docs/en/v1/guides/routing">
read all about nested routes in the docs read all about nested routes in the docs
</a> </a>
. .

View File

@@ -0,0 +1,3 @@
# Run `vercel env pull` to generate a .env file from your Vercel project
SANITY_STUDIO_API_PROJECT_ID=
SANITY_STUDIO_API_DATASET=

View File

@@ -0,0 +1,12 @@
# Logs
/logs
*.log
# Coverage directory used by tools like istanbul
/coverage
# Dependency directories
node_modules
# Compiled sanity studio
/dist

29
examples/sanity/README.md Normal file
View File

@@ -0,0 +1,29 @@
# Sanity Blogging Content Studio
Congratulations, you have now installed Sanity Studio, an open source real-time content editing environment connected to the Sanity backend.
Now you can do the following things:
- [Read “getting started” in the docs](https://www.sanity.io/docs/introduction/getting-started?utm_source=readme)
- Check out the example frontend: [React/Next.js](https://github.com/sanity-io/tutorial-sanity-blog-react-next)
- [Read the blog post about this template](https://www.sanity.io/blog/build-your-own-blog-with-sanity-and-next-js?utm_source=readme)
- [Join the community Slack](https://slack.sanity.io/?utm_source=readme)
- [Extend and build plugins](https://www.sanity.io/docs/content-studio/extending?utm_source=readme)
## Develop locally
Install dependencies:
```sh
npx @sanity/cli install
```
Pull down environment variables from your Vercel project (requires the [Vercel CLI](https://vercel.com/cli)):
```sh
vercel env pull
```
You can also run `npx @sanity/init` in this repo and agree to reconfigure it. You'll then be able to select from existing projects. The CLI will update `sanity.json` with the project ID and dataset name.

View File

@@ -0,0 +1,7 @@
{
"#": "Used by Sanity to keep track of configuration file checksums, do not delete or modify!",
"@sanity/default-layout": "bb034f391ba508a6ca8cd971967cbedeb131c4d19b17b28a0895f32db5d568ea",
"@sanity/default-login": "6fb6d3800aa71346e1b84d95bbcaa287879456f2922372bb0294e30b968cd37f",
"@sanity/form-builder": "b38478227ba5e22c91981da4b53436df22e48ff25238a55a973ed620be5068aa",
"@sanity/data-aspects": "d199e2c199b3e26cd28b68dc84d7fc01c9186bf5089580f2e2446994d36b3cb6"
}

View File

@@ -0,0 +1,3 @@
{
"listOptions": {}
}

View File

@@ -0,0 +1,6 @@
{
"toolSwitcher": {
"order": [],
"hidden": []
}
}

View File

@@ -0,0 +1,7 @@
{
"providers": {
"mode": "append",
"redirectOnSingle": false,
"entries": []
}
}

View File

@@ -0,0 +1,5 @@
{
"images": {
"directUploads": true
}
}

View File

@@ -0,0 +1,30 @@
{
"name": "verceltemplateblogstudio",
"private": true,
"version": "1.0.0",
"description": "This is the public list of examples for **Vercel**",
"main": "package.json",
"author": "Knut Melvær <knut@sanity.io>",
"license": "UNLICENSED",
"scripts": {
"start": "sanity start",
"build": "sanity build"
},
"keywords": [
"sanity"
],
"dependencies": {
"@sanity/core": "^2.26",
"@sanity/default-layout": "^2.26",
"@sanity/default-login": "^2.26",
"@sanity/desk-tool": "^2.26",
"@sanity/vision": "^2.26",
"prop-types": "^15.7",
"react": "^17.0",
"react-dom": "^17.0",
"styled-components": "^5.2"
},
"devDependencies": {
"@sanity/cli": "^2.26"
}
}

View File

@@ -0,0 +1 @@
User-specific packages can be placed here

View File

@@ -0,0 +1,29 @@
{
"root": true,
"project": {
"name": "vercel-template-blog-studio"
},
"api": {
"projectId": "YOUR_PROJECT_ID",
"dataset": "YOUR_DATASET_NAME"
},
"plugins": [
"@sanity/base",
"@sanity/default-layout",
"@sanity/default-login",
"@sanity/desk-tool"
],
"env": {
"development": {
"plugins": [
"@sanity/vision"
]
}
},
"parts": [
{
"name": "part:@sanity/base/schema",
"path": "./schemas/schema"
}
]
}

View File

@@ -0,0 +1,48 @@
export default {
name: 'author',
title: 'Author',
type: 'document',
fields: [
{
name: 'name',
title: 'Name',
type: 'string',
},
{
name: 'slug',
title: 'Slug',
type: 'slug',
options: {
source: 'name',
maxLength: 96,
},
},
{
name: 'image',
title: 'Image',
type: 'image',
options: {
hotspot: true,
},
},
{
name: 'bio',
title: 'Bio',
type: 'array',
of: [
{
title: 'Block',
type: 'block',
styles: [{title: 'Normal', value: 'normal'}],
lists: [],
},
],
},
],
preview: {
select: {
title: 'name',
media: 'image',
},
},
}

View File

@@ -0,0 +1,65 @@
/**
* This is the schema definition for the rich text fields used for
* for this blog studio. When you import it in schemas.js it can be
* reused in other parts of the studio with:
* {
* name: 'someName',
* title: 'Some title',
* type: 'blockContent'
* }
*/
export default {
title: 'Block Content',
name: 'blockContent',
type: 'array',
of: [
{
title: 'Block',
type: 'block',
// Styles let you set what your user can mark up blocks with. These
// correspond with HTML tags, but you can set any title or value
// you want and decide how you want to deal with it where you want to
// use your content.
styles: [
{title: 'Normal', value: 'normal'},
{title: 'H1', value: 'h1'},
{title: 'H2', value: 'h2'},
{title: 'H3', value: 'h3'},
{title: 'H4', value: 'h4'},
{title: 'Quote', value: 'blockquote'},
],
lists: [{title: 'Bullet', value: 'bullet'}],
// Marks let you mark up inline text in the block editor.
marks: {
// Decorators usually describe a single property e.g. a typographic
// preference or highlighting by editors.
decorators: [
{title: 'Strong', value: 'strong'},
{title: 'Emphasis', value: 'em'},
],
// Annotations can be any object structure e.g. a link or a footnote.
annotations: [
{
title: 'URL',
name: 'link',
type: 'object',
fields: [
{
title: 'URL',
name: 'href',
type: 'url',
},
],
},
],
},
},
// You can add additional types here. Note that you can't use
// primitive types such as 'string' and 'number' in the same array
// as a block type.
{
type: 'image',
options: {hotspot: true},
},
],
}

View File

@@ -0,0 +1,17 @@
export default {
name: 'category',
title: 'Category',
type: 'document',
fields: [
{
name: 'title',
title: 'Title',
type: 'string',
},
{
name: 'description',
title: 'Description',
type: 'text',
},
],
}

View File

@@ -0,0 +1,65 @@
export default {
name: 'post',
title: 'Post',
type: 'document',
fields: [
{
name: 'title',
title: 'Title',
type: 'string',
},
{
name: 'slug',
title: 'Slug',
type: 'slug',
options: {
source: 'title',
maxLength: 96,
},
},
{
name: 'author',
title: 'Author',
type: 'reference',
to: {type: 'author'},
},
{
name: 'mainImage',
title: 'Main image',
type: 'image',
options: {
hotspot: true,
},
},
{
name: 'categories',
title: 'Categories',
type: 'array',
of: [{type: 'reference', to: {type: 'category'}}],
},
{
name: 'publishedAt',
title: 'Published at',
type: 'datetime',
},
{
name: 'body',
title: 'Body',
type: 'blockContent',
},
],
preview: {
select: {
title: 'title',
author: 'author.name',
media: 'mainImage',
},
prepare(selection) {
const {author} = selection
return Object.assign({}, selection, {
subtitle: author && `by ${author}`,
})
},
},
}

View File

@@ -0,0 +1,29 @@
// First, we must import the schema creator
import createSchema from 'part:@sanity/base/schema-creator'
// Then import schema types from any plugins that might expose them
import schemaTypes from 'all:part:@sanity/base/schema-type'
// We import object and document schemas
import blockContent from './blockContent'
import category from './category'
import post from './post'
import author from './author'
// Then we give our schema to the builder and provide the result to Sanity
export default createSchema({
// We name our schema
name: 'default',
// Then proceed to concatenate our document type
// to the ones provided by any plugins that are installed
types: schemaTypes.concat([
// The following are document types which will appear
// in the studio.
post,
author,
category,
// When added to this list, object types can be used as
// { type: 'typename' } in other document schemas
blockContent,
]),
})

View File

@@ -0,0 +1 @@
Files placed here will be served by the Sanity server under the `/static`-prefix

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,6 @@
{
// Note: This config is only used to help editors like VS Code understand/resolve
// parts, the actual transpilation is done by babel. Any compiler configuration in
// here will be ignored.
"include": ["./node_modules/@sanity/base/types/**/*.ts", "./**/*.ts", "./**/*.tsx"]
}

9911
examples/sanity/yarn.lock Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,7 @@
{ {
"private": true, "private": true,
"name": "sveltekit",
"version": "0.0.1",
"scripts": { "scripts": {
"dev": "svelte-kit dev", "dev": "svelte-kit dev",
"build": "svelte-kit build", "build": "svelte-kit build",
@@ -9,7 +11,7 @@
"devDependencies": { "devDependencies": {
"@sveltejs/adapter-auto": "next", "@sveltejs/adapter-auto": "next",
"@sveltejs/kit": "next", "@sveltejs/kit": "next",
"svelte": "^3.44.0" "svelte": "^3.46.0"
}, },
"type": "module", "type": "module",
"dependencies": { "dependencies": {

View File

@@ -8,6 +8,6 @@
%svelte.head% %svelte.head%
</head> </head>
<body> <body>
<div id="svelte">%svelte.body%</div> <div>%svelte.body%</div>
</body> </body>
</html> </html>

View File

@@ -1 +0,0 @@
/// <reference types="@sveltejs/kit" />

View File

@@ -1,19 +1,22 @@
import cookie from 'cookie'; import cookie from 'cookie';
import { v4 as uuid } from '@lukeed/uuid'; import { v4 as uuid } from '@lukeed/uuid';
export const handle = async ({ request, resolve }) => { export const handle = async ({ event, resolve }) => {
const cookies = cookie.parse(request.headers.cookie || ''); const cookies = cookie.parse(event.request.headers.get('cookie') || '');
request.locals.userid = cookies.userid || uuid(); event.locals.userid = cookies.userid || uuid();
const response = await resolve(request); const response = await resolve(event);
if (!cookies.userid) { if (!cookies.userid) {
// if this is the first time the user has visited this app, // if this is the first time the user has visited this app,
// set a cookie so that we recognise them when they return // set a cookie so that we recognise them when they return
response.headers['set-cookie'] = cookie.serialize('userid', request.locals.userid, { response.headers.set(
'set-cookie',
cookie.serialize('userid', event.locals.userid, {
path: '/', path: '/',
httpOnly: true httpOnly: true
}); })
);
} }
return response; return response;

View File

@@ -22,7 +22,7 @@
<div class="counter-viewport"> <div class="counter-viewport">
<div class="counter-digits" style="transform: translate(0, {100 * offset}%)"> <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> <strong>{Math.floor($displayed_count)}</strong>
</div> </div>
</div> </div>
@@ -94,4 +94,9 @@
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
.hidden {
top: -100%;
user-select: none;
}
</style> </style>

View File

@@ -1,6 +1,8 @@
import { invalidate } from '$app/navigation';
// this action (https://svelte.dev/tutorial/actions) allows us to // this action (https://svelte.dev/tutorial/actions) allows us to
// progressively enhance a <form> that already works without JS // 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; let current_token;
async function handle_submit(e) { async function handle_submit(e) {
@@ -8,31 +10,35 @@ export function enhance(form, { pending, error, result }) {
e.preventDefault(); e.preventDefault();
const body = new FormData(form); const data = new FormData(form);
if (pending) pending(body, form); if (pending) pending({ data, form });
try { try {
const res = await fetch(form.action, { const response = await fetch(form.action, {
method: form.method, method: form.method,
headers: { headers: {
accept: 'application/json' accept: 'application/json'
}, },
body body: data
}); });
if (token !== current_token) return; if (token !== current_token) return;
if (res.ok) { if (response.ok) {
result(res, form); if (result) result({ data, form, response });
const url = new URL(form.action);
url.search = url.hash = '';
invalidate(url.href);
} else if (error) { } else if (error) {
error(res, null, form); error({ data, form, error: null, response });
} else { } else {
console.error(await res.text()); console.error(await response.text());
} }
} catch (e) { } catch (e) {
if (error) { if (error) {
error(null, e, form); error({ data, form, error: e, response: null });
} else { } else {
throw e; throw e;
} }

View File

@@ -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}`);
};

View File

@@ -1,6 +1,6 @@
/* /*
This module is used by the /todos.json and /todos/[uid].json This module is used by the /todos endpoint to
endpoints to make calls to api.svelte.dev, which stores todos make calls to api.svelte.dev, which stores todos
for each user. The leading underscore indicates that this is for each user. The leading underscore indicates that this is
a private module, _not_ an endpoint — visiting /todos/_api a private module, _not_ an endpoint — visiting /todos/_api
will net you a 404 response. will net you a 404 response.
@@ -11,35 +11,12 @@
const base = 'https://api.svelte.dev'; const base = 'https://api.svelte.dev';
export async function api(request, resource, data) { export function api(method, resource, data) {
// user must have a cookie set return fetch(`${base}/${resource}`, {
if (!request.locals.userid) { method,
return { status: 401 };
}
const res = await fetch(`${base}/${resource}`, {
method: request.method,
headers: { headers: {
'content-type': 'application/json' 'content-type': 'application/json'
}, },
body: data && JSON.stringify(data) 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()
};
} }

View 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;
};

View File

@@ -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;
};

View File

@@ -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> <script>
import { enhance } from '$lib/form';
import { scale } from 'svelte/transition'; import { scale } from 'svelte/transition';
import { flip } from 'svelte/animate'; import { flip } from 'svelte/animate';
export let todos; 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> </script>
<svelte:head> <svelte:head>
@@ -46,13 +15,10 @@
<form <form
class="new" class="new"
action="/todos.json" action="/todos"
method="post" method="post"
use:enhance={{ use:enhance={{
result: async (res, form) => { result: async ({ form }) => {
const created = await res.json();
todos = [...todos, created];
form.reset(); form.reset();
} }
}} }}
@@ -68,41 +34,33 @@
animate:flip={{ duration: 200 }} animate:flip={{ duration: 200 }}
> >
<form <form
action="/todos/{todo.uid}.json?_method=PATCH" action="/todos?_method=PATCH"
method="post" method="post"
use:enhance={{ use:enhance={{
pending: (data) => { pending: ({ data }) => {
todo.done = !!data.get('done'); todo.done = !!data.get('done');
}, }
result: patch
}} }}
> >
<input type="hidden" name="uid" value={todo.uid} />
<input type="hidden" name="done" value={todo.done ? '' : 'true'} /> <input type="hidden" name="done" value={todo.done ? '' : 'true'} />
<button class="toggle" aria-label="Mark todo as {todo.done ? 'not done' : 'done'}" /> <button class="toggle" aria-label="Mark todo as {todo.done ? 'not done' : 'done'}" />
</form> </form>
<form <form class="text" action="/todos?_method=PATCH" method="post" use:enhance>
class="text" <input type="hidden" name="uid" value={todo.uid} />
action="/todos/{todo.uid}.json?_method=PATCH"
method="post"
use:enhance={{
result: patch
}}
>
<input aria-label="Edit todo" type="text" name="text" value={todo.text} /> <input aria-label="Edit todo" type="text" name="text" value={todo.text} />
<button class="save" aria-label="Save todo" /> <button class="save" aria-label="Save todo" />
</form> </form>
<form <form
action="/todos/{todo.uid}.json?_method=DELETE" action="/todos?_method=DELETE"
method="post" method="post"
use:enhance={{ use:enhance={{
pending: () => (todo.pending_delete = true), pending: () => (todo.pending_delete = true)
result: () => {
todos = todos.filter((t) => t.uid !== todo.uid);
}
}} }}
> >
<input type="hidden" name="uid" value={todo.uid} />
<button class="delete" aria-label="Delete todo" disabled={todo.pending_delete} /> <button class="delete" aria-label="Delete todo" disabled={todo.pending_delete} />
</form> </form>
</div> </div>
@@ -158,7 +116,7 @@
.done { .done {
transform: none; transform: none;
opacity: 0.4; 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 { form.text {

View File

@@ -5,8 +5,10 @@ const config = {
kit: { kit: {
adapter: adapter(), adapter: adapter(),
// hydrate the <div id="svelte"> element in src/app.html // Override http methods in the Todo forms
target: '#svelte' methodOverride: {
allowed: ['PATCH', 'DELETE']
}
} }
}; };

View File

@@ -32,7 +32,6 @@
"@typescript-eslint/parser": "4.28.0", "@typescript-eslint/parser": "4.28.0",
"async-retry": "1.2.3", "async-retry": "1.2.3",
"buffer-replace": "1.0.0", "buffer-replace": "1.0.0",
"cheerio": "1.0.0-rc.3",
"eslint": "7.29.0", "eslint": "7.29.0",
"eslint-config-prettier": "8.3.0", "eslint-config-prettier": "8.3.0",
"eslint-plugin-jest": "24.3.6", "eslint-plugin-jest": "24.3.6",
@@ -43,8 +42,9 @@
"node-fetch": "2.6.1", "node-fetch": "2.6.1",
"npm-package-arg": "6.1.0", "npm-package-arg": "6.1.0",
"prettier": "2.3.1", "prettier": "2.3.1",
"ts-eager": "2.0.2",
"ts-jest": "27.0.4", "ts-jest": "27.0.4",
"turbo": "1.0.18" "turbo": "1.1.9"
}, },
"scripts": { "scripts": {
"lerna": "lerna", "lerna": "lerna",
@@ -54,9 +54,10 @@
"publish-from-github": "./utils/publish.sh", "publish-from-github": "./utils/publish.sh",
"changelog": "node utils/changelog.js", "changelog": "node utils/changelog.js",
"build": "turbo run build", "build": "turbo run build",
"vercel-build": "mkdir -p public && echo '<a href=\"https://vercel.com/import\">Import</a>' > public/output.html", "vercel-build": "yarn build && cd api && node -r ts-eager/register ./_lib/script/build.ts",
"pre-commit": "lint-staged", "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-cli": "node utils/run.js test-integration-cli",
"test-integration-once": "node utils/run.js test-integration-once", "test-integration-once": "node utils/run.js test-integration-once",
"test-integration-dev": "node utils/run.js test-integration-dev", "test-integration-dev": "node utils/run.js test-integration-dev",

View File

@@ -1,6 +1,6 @@
{ {
"name": "@vercel/build-utils", "name": "@vercel/build-utils",
"version": "2.14.0", "version": "2.15.0",
"license": "MIT", "license": "MIT",
"main": "./dist/index.js", "main": "./dist/index.js",
"types": "./dist/index.d.js", "types": "./dist/index.d.js",
@@ -30,7 +30,7 @@
"@types/node-fetch": "^2.1.6", "@types/node-fetch": "^2.1.6",
"@types/semver": "6.0.0", "@types/semver": "6.0.0",
"@types/yazl": "^2.4.1", "@types/yazl": "^2.4.1",
"@vercel/frameworks": "0.6.0", "@vercel/frameworks": "0.7.0",
"@vercel/ncc": "0.24.0", "@vercel/ncc": "0.24.0",
"aggregate-error": "3.0.1", "aggregate-error": "3.0.1",
"async-retry": "1.2.3", "async-retry": "1.2.3",

View File

@@ -67,8 +67,7 @@ function getPublicBuilder(
typeof builder.src === 'string' && typeof builder.src === 'string' &&
isOfficialRuntime('static', builder.use) && isOfficialRuntime('static', builder.use) &&
/^.*\/\*\*\/\*$/.test(builder.src) && /^.*\/\*\*\/\*$/.test(builder.src) &&
builder.config && builder.config?.zeroConfig === true
builder.config.zeroConfig === true
) { ) {
return builder as Builder & { src: string }; return builder as Builder & { src: string };
} }

View File

@@ -0,0 +1,44 @@
import type { Files } from './types';
/**
* An Edge Functions output
*/
export class EdgeFunction {
type: 'EdgeFunction';
/**
* A display name for the edge function.
*/
name: string;
/**
* The deployment target.
* Only v8-worker is currently supported.
*/
deploymentTarget: 'v8-worker';
/**
* The entrypoint for the edge function.
*/
entrypoint: string;
/**
* The list of files to be included in the edge function bundle.
*/
files: Files;
/**
* Extra environment variables in use for the user code, to be
* assigned to the edge function.
*/
envVarsInUse?: string[];
constructor(params: Omit<EdgeFunction, 'type'>) {
this.type = 'EdgeFunction';
this.name = params.name;
this.deploymentTarget = params.deploymentTarget;
this.entrypoint = params.entrypoint;
this.files = params.files;
this.envVarsInUse = params.envVarsInUse;
}
}

View File

@@ -1,6 +1,6 @@
import assert from 'assert'; import assert from 'assert';
import intoStream from 'into-stream'; import intoStream from 'into-stream';
import { File } from './types'; import { FileBase } from './types';
interface FileBlobOptions { interface FileBlobOptions {
mode?: number; mode?: number;
@@ -14,7 +14,7 @@ interface FromStreamOptions {
stream: NodeJS.ReadableStream; stream: NodeJS.ReadableStream;
} }
export default class FileBlob implements File { export default class FileBlob implements FileBase {
public type: 'FileBlob'; public type: 'FileBlob';
public mode: number; public mode: number;
public data: string | Buffer; public data: string | Buffer;
@@ -48,6 +48,10 @@ export default class FileBlob implements File {
return new FileBlob({ mode, contentType, data }); return new FileBlob({ mode, contentType, data });
} }
async toStreamAsync(): Promise<NodeJS.ReadableStream> {
return this.toStream();
}
toStream(): NodeJS.ReadableStream { toStream(): NodeJS.ReadableStream {
return intoStream(this.data); return intoStream(this.data);
} }

View File

@@ -3,7 +3,7 @@ import fs from 'fs-extra';
import multiStream from 'multistream'; import multiStream from 'multistream';
import path from 'path'; import path from 'path';
import Sema from 'async-sema'; import Sema from 'async-sema';
import { File } from './types'; import { FileBase } from './types';
const semaToPreventEMFILE = new Sema(20); const semaToPreventEMFILE = new Sema(20);
@@ -20,7 +20,7 @@ interface FromStreamOptions {
fsPath: string; fsPath: string;
} }
class FileFsRef implements File { class FileFsRef implements FileBase {
public type: 'FileFsRef'; public type: 'FileFsRef';
public mode: number; public mode: number;
public fsPath: string; public fsPath: string;

View File

@@ -3,7 +3,7 @@ import fetch from 'node-fetch';
import multiStream from 'multistream'; import multiStream from 'multistream';
import retry from 'async-retry'; import retry from 'async-retry';
import Sema from 'async-sema'; import Sema from 'async-sema';
import { File } from './types'; import { FileBase } from './types';
interface FileRefOptions { interface FileRefOptions {
mode?: number; mode?: number;
@@ -23,7 +23,7 @@ class BailableError extends Error {
} }
} }
export default class FileRef implements File { export default class FileRef implements FileBase {
public type: 'FileRef'; public type: 'FileRef';
public mode: number; public mode: number;
public digest: string; public digest: string;

View File

@@ -3,6 +3,7 @@ import debug from '../debug';
import FileFsRef from '../file-fs-ref'; import FileFsRef from '../file-fs-ref';
import { File, Files, Meta } from '../types'; import { File, Files, Meta } from '../types';
import { remove, mkdirp, readlink, symlink } from 'fs-extra'; import { remove, mkdirp, readlink, symlink } from 'fs-extra';
import streamToBuffer from './stream-to-buffer';
export interface DownloadedFiles { export interface DownloadedFiles {
[filePath: string]: FileFsRef; [filePath: string]: FileFsRef;
@@ -15,20 +16,45 @@ export function isSymbolicLink(mode: number): boolean {
return (mode & S_IFMT) === S_IFLNK; return (mode & S_IFMT) === S_IFLNK;
} }
async function prepareSymlinkTarget(
file: File,
fsPath: string
): Promise<string> {
const mkdirPromise = mkdirp(path.dirname(fsPath));
if (file.type === 'FileFsRef') {
const [target] = await Promise.all([readlink(file.fsPath), mkdirPromise]);
return target;
}
if (file.type === 'FileRef' || file.type === 'FileBlob') {
const targetPathBufferPromise = await streamToBuffer(
await file.toStreamAsync()
);
const [targetPathBuffer] = await Promise.all([
targetPathBufferPromise,
mkdirPromise,
]);
return targetPathBuffer.toString('utf8');
}
throw new Error(
`file.type "${(file as any).type}" not supported for symlink`
);
}
async function downloadFile(file: File, fsPath: string): Promise<FileFsRef> { async function downloadFile(file: File, fsPath: string): Promise<FileFsRef> {
const { mode } = file; const { mode } = file;
if (mode && isSymbolicLink(mode) && file.type === 'FileFsRef') {
const [target] = await Promise.all([ if (isSymbolicLink(mode)) {
readlink((file as FileFsRef).fsPath), const target = await prepareSymlinkTarget(file, fsPath);
mkdirp(path.dirname(fsPath)),
]);
await symlink(target, fsPath); await symlink(target, fsPath);
return FileFsRef.fromFsPath({ mode, fsPath }); return FileFsRef.fromFsPath({ mode, fsPath });
} else { }
const stream = file.toStream(); const stream = file.toStream();
return FileFsRef.fromStream({ mode, stream, fsPath }); return FileFsRef.fromStream({ mode, stream, fsPath });
} }
}
async function removeFile(basePath: string, fileMatched: string) { async function removeFile(basePath: string, fileMatched: string) {
const file = path.join(basePath, fileMatched); const file = path.join(basePath, fileMatched);

View File

@@ -46,8 +46,8 @@ export default async function glob(
const files = await vanillaGlob(pattern, options); const files = await vanillaGlob(pattern, options);
for (const relativePath of files) { for (const relativePath of files) {
const fsPath = normalizePath(path.join(options.cwd!, relativePath)); const fsPath = normalizePath(path.join(options.cwd, relativePath));
let stat: Stats = options.statCache![fsPath] as Stats; let stat: Stats = options.statCache[fsPath] as Stats;
assert( assert(
stat, stat,
`statCache does not contain value for ${relativePath} (resolved to ${fsPath})` `statCache does not contain value for ${relativePath} (resolved to ${fsPath})`

View File

@@ -8,12 +8,13 @@ import { deprecate } from 'util';
import { NowBuildError } from '../errors'; import { NowBuildError } from '../errors';
import { Meta, PackageJson, NodeVersion, Config } from '../types'; import { Meta, PackageJson, NodeVersion, Config } from '../types';
import { getSupportedNodeVersion, getLatestNodeVersion } from './node-version'; 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 { export interface ScanParentDirsResult {
/** /**
* "yarn" or "npm", depending on the presence of lockfiles. * "yarn", "npm", or "pnpm" depending on the presence of lockfiles.
*/ */
cliType: CliType; cliType: CliType;
/** /**
@@ -252,7 +253,7 @@ export async function scanParentDirs(
} }
// eslint-disable-next-line no-await-in-loop // eslint-disable-next-line no-await-in-loop
const [packageLockJson, hasYarnLock] = await Promise.all([ const [packageLockJson, hasYarnLock, pnpmLockYaml] = await Promise.all([
fs fs
.readJson(path.join(currentDestPath, 'package-lock.json')) .readJson(path.join(currentDestPath, 'package-lock.json'))
.catch(error => { .catch(error => {
@@ -263,17 +264,26 @@ export async function scanParentDirs(
throw error; throw error;
}), }),
fs.pathExists(path.join(currentDestPath, 'yarn.lock')), 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'; cliType = 'npm';
lockfileVersion = packageLockJson.lockfileVersion; 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 // 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` // that the lockfile is in a higher path than where the `package.json`
// file was found. // file was found.
if (packageLockJson || hasYarnLock) { if (packageLockJson || hasYarnLock || pnpmLockYaml) {
break; break;
} }
} }
@@ -341,6 +351,13 @@ export async function runNpmInstall(
commandArgs = args commandArgs = args
.filter(a => a !== '--prefer-offline') .filter(a => a !== '--prefer-offline')
.concat(['install', '--no-audit', '--unsafe-perm']); .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 { } else {
opts.prettyCommand = 'yarn install'; opts.prettyCommand = 'yarn install';
commandArgs = ['install', ...args]; commandArgs = ['install', ...args];
@@ -448,6 +465,8 @@ export async function runPackageJsonScript(
if (cliType === 'npm') { if (cliType === 'npm') {
opts.prettyCommand = `npm run ${scriptName}`; opts.prettyCommand = `npm run ${scriptName}`;
} else if (cliType === 'pnpm') {
opts.prettyCommand = `pnpm run ${scriptName}`;
} else { } else {
opts.prettyCommand = `yarn run ${scriptName}`; opts.prettyCommand = `yarn run ${scriptName}`;
} }

View File

@@ -81,6 +81,7 @@ export {
getIgnoreFilter, getIgnoreFilter,
}; };
export { EdgeFunction } from './edge-function';
export { export {
detectBuilders, detectBuilders,
detectOutputDirectory, detectOutputDirectory,

View File

@@ -3,17 +3,17 @@ import Sema from 'async-sema';
import { ZipFile } from 'yazl'; import { ZipFile } from 'yazl';
import minimatch from 'minimatch'; import minimatch from 'minimatch';
import { readlink } from 'fs-extra'; import { readlink } from 'fs-extra';
import { Files, Config } from './types';
import FileFsRef from './file-fs-ref';
import { isSymbolicLink } from './fs/download'; import { isSymbolicLink } from './fs/download';
import streamToBuffer from './fs/stream-to-buffer'; import streamToBuffer from './fs/stream-to-buffer';
import type { Files, Config } from './types';
interface Environment { interface Environment {
[key: string]: string; [key: string]: string;
} }
export interface LambdaOptions { export type LambdaOptions = LambdaOptionsWithFiles | LambdaOptionsWithZipBuffer;
files: Files;
export interface LambdaOptionsBase {
handler: string; handler: string;
runtime: string; runtime: string;
memory?: number; memory?: number;
@@ -21,10 +21,21 @@ export interface LambdaOptions {
environment?: Environment; environment?: Environment;
allowQuery?: string[]; allowQuery?: string[];
regions?: string[]; regions?: string[];
supportsMultiPayloads?: boolean;
}
export interface LambdaOptionsWithFiles extends LambdaOptionsBase {
files: Files;
}
/**
* @deprecated Use `LambdaOptionsWithFiles` instead.
*/
export interface LambdaOptionsWithZipBuffer extends LambdaOptionsBase {
/** /**
* @deprecated Use `files` property instead. * @deprecated Use `files` property instead.
*/ */
zipBuffer?: Buffer; zipBuffer: Buffer;
} }
interface GetLambdaOptionsFromFunctionOptions { interface GetLambdaOptionsFromFunctionOptions {
@@ -34,7 +45,7 @@ interface GetLambdaOptionsFromFunctionOptions {
export class Lambda { export class Lambda {
type: 'Lambda'; type: 'Lambda';
files: Files; files?: Files;
handler: string; handler: string;
runtime: string; runtime: string;
memory?: number; memory?: number;
@@ -46,9 +57,10 @@ export class Lambda {
* @deprecated Use `await lambda.createZip()` instead. * @deprecated Use `await lambda.createZip()` instead.
*/ */
zipBuffer?: Buffer; zipBuffer?: Buffer;
supportsMultiPayloads?: boolean;
constructor({ constructor(opts: LambdaOptions) {
files, const {
handler, handler,
runtime, runtime,
maxDuration, maxDuration,
@@ -56,10 +68,13 @@ export class Lambda {
environment = {}, environment = {},
allowQuery, allowQuery,
regions, regions,
zipBuffer, supportsMultiPayloads,
}: LambdaOptions) { } = opts;
if (!zipBuffer) { if ('files' in opts) {
assert(typeof files === 'object', '"files" must be an object'); assert(typeof opts.files === 'object', '"files" must be an object');
}
if ('zipBuffer' in opts) {
assert(Buffer.isBuffer(opts.zipBuffer), '"zipBuffer" must be a Buffer');
} }
assert(typeof handler === 'string', '"handler" is not a string'); assert(typeof handler === 'string', '"handler" is not a string');
assert(typeof runtime === 'string', '"runtime" is not a string'); assert(typeof runtime === 'string', '"runtime" is not a string');
@@ -81,6 +96,13 @@ export class Lambda {
); );
} }
if (supportsMultiPayloads !== undefined) {
assert(
typeof supportsMultiPayloads === 'boolean',
'"supportsMultiPayloads" is not a boolean'
);
}
if (regions !== undefined) { if (regions !== undefined) {
assert(Array.isArray(regions), '"regions" is not an Array'); assert(Array.isArray(regions), '"regions" is not an Array');
assert( assert(
@@ -89,7 +111,7 @@ export class Lambda {
); );
} }
this.type = 'Lambda'; this.type = 'Lambda';
this.files = files; this.files = 'files' in opts ? opts.files : undefined;
this.handler = handler; this.handler = handler;
this.runtime = runtime; this.runtime = runtime;
this.memory = memory; this.memory = memory;
@@ -97,12 +119,16 @@ export class Lambda {
this.environment = environment; this.environment = environment;
this.allowQuery = allowQuery; this.allowQuery = allowQuery;
this.regions = regions; this.regions = regions;
this.zipBuffer = zipBuffer; this.zipBuffer = 'zipBuffer' in opts ? opts.zipBuffer : undefined;
this.supportsMultiPayloads = supportsMultiPayloads;
} }
async createZip(): Promise<Buffer> { async createZip(): Promise<Buffer> {
let { zipBuffer } = this; let { zipBuffer } = this;
if (!zipBuffer) { if (!zipBuffer) {
if (!this.files) {
throw new Error('`files` is not defined');
}
await sema.acquire(); await sema.acquire();
try { try {
zipBuffer = await createZip(this.files); zipBuffer = await createZip(this.files);
@@ -136,7 +162,7 @@ export async function createZip(files: Files): Promise<Buffer> {
for (const name of names) { for (const name of names) {
const file = files[name]; const file = files[name];
if (file.mode && isSymbolicLink(file.mode) && file.type === 'FileFsRef') { if (file.mode && isSymbolicLink(file.mode) && file.type === 'FileFsRef') {
const symlinkTarget = await readlink((file as FileFsRef).fsPath); const symlinkTarget = await readlink(file.fsPath);
symlinkTargets.set(name, symlinkTarget); symlinkTargets.set(name, symlinkTarget);
} }
} }
@@ -150,7 +176,7 @@ export async function createZip(files: Files): Promise<Buffer> {
if (typeof symlinkTarget === 'string') { if (typeof symlinkTarget === 'string') {
zipFile.addBuffer(Buffer.from(symlinkTarget, 'utf8'), name, opts); zipFile.addBuffer(Buffer.from(symlinkTarget, 'utf8'), name, opts);
} else { } else {
const stream = file.toStream() as import('stream').Readable; const stream = file.toStream();
stream.on('error', reject); stream.on('error', reject);
zipFile.addReadStream(stream, name, opts); zipFile.addReadStream(stream, name, opts);
} }

View File

@@ -1,6 +1,6 @@
import { Lambda, LambdaOptions } from './lambda'; import { Lambda, LambdaOptionsWithFiles } from './lambda';
interface NodejsLambdaOptions extends LambdaOptions { interface NodejsLambdaOptions extends LambdaOptionsWithFiles {
shouldAddHelpers: boolean; shouldAddHelpers: boolean;
shouldAddSourcemapSupport: boolean; shouldAddSourcemapSupport: boolean;
awsLambdaHandler?: string; awsLambdaHandler?: string;

Some files were not shown because too many files have changed in this diff Show More