Compare commits

..

112 Commits

Author SHA1 Message Date
Steven
46c8cb1a68 Publish Stable
- @now/build-utils@1.3.2
 - @now/next@2.3.7
 - @now/node@1.3.3
 - @now/static-build@0.14.3
2020-01-06 18:44:26 -05:00
Steven
faeb053ea6 Publish Canary
- @now/build-utils@1.3.2-canary.1
 - now@16.7.2-canary.3
 - @now/next@2.3.7-canary.1
 - @now/node@1.3.3-canary.1
 - @now/static-build@0.14.3-canary.1
2020-01-06 18:30:34 -05:00
Steven
708a09b86a [now-build-utils] Add usage of package.json engines (#3512)
Add a better upgrade message that shows usage of `engines` in the `package.json` file.
2020-01-06 18:29:08 -05:00
Steven
89403e93e4 Publish Canary
- @now/build-utils@1.3.2-canary.0
 - @now/next@2.3.7-canary.0
 - @now/node@1.3.3-canary.0
 - @now/static-build@0.14.3-canary.0
2020-01-06 17:01:47 -05:00
Steven
ecb0c08fe2 [now-build-utils] Fix now dev to use system node (#3509)
This PR will use the system installed version of Node.js and avoid printing a warning or error if a discontinued version is selected.

This optimization was already in `@now/node` but for some reason it was never add to `@now/next`.

The reason why its relevant today is because the warnings turned into errors due to Node 8 deprecation and we don't have the "Project" in `now dev` so we don't know which version of node to select.

So instead of determining the version, `now dev` will always use `node` in the PATH and avoid printing warnings or errors. This also results in less FS reads since we no longer need to read package.json.
2020-01-06 17:00:46 -05:00
Andy Bitz
0b88c158b9 Publish Stable
- @now/frameworks@0.0.3
2020-01-06 20:15:04 +01:00
Andy
ec3a38107a [frameworks] Add settings to frameworks (#3506)
* [frameworks] Add `settings` to frameworks

* Fix svelte

* Add `outputDirectory`

* Update Next.js outputDirectory placeholder

* Type settings

Co-authored-by: Leo Lamprecht <mindrun@icloud.com>
2020-01-06 20:12:38 +01:00
Steven
0c0f1c6eb5 Publish Stable
- @now/build-utils@1.3.1
 - @now/next@2.3.6
 - @now/node@1.3.2
 - @now/static-build@0.14.2
2020-01-06 13:21:41 -05:00
Steven
ed296ef733 Publish Canary
- @now/build-utils@1.3.1-canary.1
 - now@16.7.2-canary.2
 - @now/static-build@0.14.2-canary.0
2020-01-06 13:10:05 -05:00
Steven
246f47ec95 [now-static-build] Fix distDir when zero config framework is detected (#3507)
There was a regression with framework detection that was preferring the frameworks output directory instead of the `distDir` defined in the `@now/static-build`.

The fix is to only run framework detection when `builds` is not defined (ie zero config).

Related to https://github.com/Ebury/chameleon/pull/63
2020-01-06 18:07:25 +00:00
Steven
9d95b99b72 [now-build-utils] Add support for dynamic handle: miss (#3457)
This extends the behavior of `featHandleMiss: true` flag to do the following:

- Reduce zero config API routes so that only dynamic path segment files (`api/[id].js`) get a route.
- Remove zero config out directory route (`public/`)—the files will be renamed instead.
- Use redirects for API routes when `cleanUrls: true` and use rewrites when `cleanUrls: false` from extension to the extension-less file.
- Normalize existing routes to begin with `^` and end with `$`.
2020-01-06 16:07:47 +00:00
Steven
3de8ae9d7e Publish Canary
- @now/build-utils@1.3.1-canary.0
 - @now/node@1.3.2-canary.0
2020-01-06 10:19:23 -05:00
Steven
44f6e1904e [now-build-utils][now-node] Throw new NowBuildError() (#3496)
This PR does the following

- Add and export class, `NowBuildError`, that can be thrown to stop the build and print an error but it will not print a stack trace.
- Improve logic for discontinued node versions and add more tests
- Remove hack (#3425) for undefined TERM, fixed by updating dependencies
- Rename `silent` variable to `isAuto` which means the node version was automatically selected, not defined in `package.json`
- Rename `test` deployments to `test2020` so that a fresh project is created with latest Node.js 12.x
2020-01-06 15:00:27 +00:00
Max Rovensky
d9c84fc4ce Publish Canary
- now@16.7.2-canary.1
 - @now/python@1.1.1-canary.0
2020-01-06 21:45:01 +08:00
Max
b5142d935b Fix event order in CLI (#3502)
This should fix [PRODUCT-893](https://zeit.atlassian.net/browse/PRODUCT-893) and [PRODUCT-941](https://zeit.atlassian.net/browse/PRODUCT-941)
2020-01-06 13:43:44 +00:00
luc
718a451110 Publish Canary
- now@16.7.2-canary.0
 - now-client@6.0.2-canary.0
2020-01-06 11:24:45 +01:00
Andy
9755847855 [now-client] Ignore .env.* files by default (#3436)
Ignore `.env.*` files by default.

[PRODUCT-804]

[PRODUCT-804]: https://zeit.atlassian.net/browse/PRODUCT-804
2020-01-06 10:19:55 +00:00
Luc
abc417b6b3 [now-client] Use @zeit/fetch instead of node-fetch (#3490)
We want to take advantage of the better defaults and retry policies (among others).

This bumps `@zeit/fetch` and replaces `node-fetch` with `@zeit/fetch` in `now-client`.

Also update retry policy for "uploading" files to:
- base 10ms
- 5 retries
- factor 6

which means the timeouts are 10, 60, 360, 2160, 12960
2020-01-06 09:01:17 +00:00
Steven
d6f71c8d7b Publish Stable
- @now/frameworks@0.0.2
 - @now/build-utils@1.3.0
 - now@16.7.1
 - now-client@6.0.1
 - @now/next@2.3.5
 - @now/node@1.3.1
 - @now/python@1.1.0
 - @now/routing-utils@1.5.0
 - @now/static-build@0.14.1
2020-01-03 12:39:08 -05:00
JJ Kasper
d90892dc9c Publish Stable
- @now/next@2.3.4
2020-01-03 08:45:34 -06:00
Tim Neutkens
60d2f8b96c Publish Canary
- @now/next@2.3.4-canary.1
2020-01-03 12:36:15 +01:00
JJ Kasper
2488adf80d [now-next] Add support for experimental basePath (#3478)
* Add support for experimental basePath

* Update base-path fixture

* Update type

* Update basePath route source and add invariants
2020-01-03 12:32:20 +01:00
Steven
9deb5b31d2 Publish Canary
- now@16.7.1-canary.5
2020-01-02 19:32:01 -05:00
Steven
ae55823c3c Publish Canary
- @now/frameworks@0.0.2-canary.3
 - @now/build-utils@1.2.1-canary.7
 - @now/static-build@0.14.1-canary.8
2020-01-02 18:09:49 -05:00
Andy
d3395553fe [frameworks][now-static-build] Add support for Scully (#3469)
Add support for Scully.
2020-01-02 22:25:57 +00:00
JJ Kasper
e742dd3a48 Publish Canary
- @now/next@2.3.4-canary.0
2020-01-02 13:24:06 -06:00
JJ Kasper
4f0f44e746 Publish Stable
- @now/next@2.3.3
2020-01-02 13:18:38 -06:00
JJ Kasper
0da98a7f5d Revert "[now-next] Implement handle: miss for custom-routes (#3456)" (#3488)
This reverts commit 40bbff9bee.
2020-01-02 13:15:16 -06:00
Steven
685989ae57 Publish Canary
- @now/build-utils@1.2.1-canary.6
 - @now/next@2.3.3-canary.0
 - @now/node@1.3.1-canary.1
 - @now/static-build@0.14.1-canary.7
2020-01-02 12:42:36 -05:00
Steven
6bc121e7b1 [now-build-utils] Add support for getLatestNodeVersion() and config.nodeVersion (#3483)
This PR does a few things:

1. Add functions `getLatestNodeVersion()` and `getOldestNodeVersion()` for use in api-project.
2. Add property `config.nodeVersion` which has precedence over default Node 8.

We want new projects to use the latest node version without setting any configuration but we don't want to break old projects. So during project creation, the value of `getLatestNodeVersion()` will be saved and then each deployment of that project will assign that value to `config.nodeVersion`. 

Implements [PRODUCT-837]

[PRODUCT-837]: https://zeit.atlassian.net/browse/PRODUCT-837
2020-01-02 17:34:31 +00:00
JJ Kasper
56d3fed954 Publish Stable
- @now/next@2.3.2
2019-12-31 15:56:54 -06:00
JJ Kasper
40bbff9bee [now-next] Implement handle: miss for custom-routes (#3456)
This implements `{ handle: 'miss' }` which will allow more efficiently checking dynamic routes after a matching rewrite. This is not fully available in production yet and the tests will fail for this PR until it is ready in Now

x-ref: https://github.com/zeit/next.js/pull/9568
2019-12-31 19:36:50 +00:00
Steven
66ab011f4a Publish Canary
- @now/next@2.3.2-canary.0
 - @now/node@1.3.1-canary.0
2019-12-30 13:48:36 -05:00
Steven
f4237d3db0 [now-node][now-next] Bump node-file-trace to 0.4.1 (#3481)
Bumps `node-file-trace` to version [0.4.1](https://github.com/zeit/node-file-trace/releases/tag/0.4.1).

- Add special case for semver@7: [#87](https://github.com/zeit/node-file-trace/pull/87)
- Handle babel/ts compiled imports: [#79](https://github.com/zeit/node-file-trace/pull/79)
2019-12-30 18:26:32 +00:00
JJ Kasper
6f9a083dba [now-next] Add handling for new routes-manifest version (#3482)
This handles the new `routes-manifest` version in the latest canary of Next.js since we throw an error if the version isn't handled by `@now/next`

unblocks: https://github.com/zeit/now/pull/3481
2019-12-30 17:58:19 +00:00
dependabot[bot]
688fcc6a5b Bump handlebars from 4.1.2 to 4.5.3 (#3476)
Bumps [handlebars](https://github.com/wycats/handlebars.js) from 4.1.2 to 4.5.3.
<details>
<summary>Changelog</summary>

*Sourced from [handlebars's changelog](https://github.com/wycats/handlebars.js/blob/master/release-notes.md).*

> ## v4.5.3 - November 18th, 2019
> Bugfixes:
> 
> - fix: add "no-prototype-builtins" eslint-rule and fix all occurences - f7f05d7
> - fix: add more properties required to be enumerable - 1988878
> 
> Chores / Build:
> - fix: use !== 0 instead of != 0 - c02b05f
> - add chai and dirty-chai and sinon, for cleaner test-assertions and spies, 
>   deprecate old assertion-methods  - 93e284e, 886ba86, 0817dad, 93516a0
> 
> Security:
> 
> - The properties `__proto__`, `__defineGetter__`, `__defineSetter__` and `__lookupGetter__` 
>   have been added to the list of "properties that must be enumerable".
>   If a property by that name is found and not enumerable on its parent, 
>   it will silently evaluate to `undefined`. This is done in both the compiled template and the "lookup"-helper. 
>   This will prevent new Remote-Code-Execution exploits that have been
>   published recently.
> 
> Compatibility notes: 
> 
> - Due to the security-fixes. The semantics of the templates using
>   `__proto__`, `__defineGetter__`, `__defineSetter__` and `__lookupGetter__` in the respect that those expression now return 
>   `undefined` rather than their actual value from the proto.
> - The semantics have not changed in cases where the properties are  enumerable, as in:
> 
> ```js
> {
>   __proto__: 'some string'
> }
> ```
> 
> - The change may be breaking in that respect, but we still only 
>   increase the patch-version, because the incompatible use-cases
>   are not intended, undocumented and far less important than fixing
>   Remote-Code-Execution exploits on existing systems.
> 
> 
> 
> [Commits](https://github.com/wycats/handlebars.js/compare/v4.5.2...v4.5.3)
> 
> ## v4.5.2 - November 13th, 2019
> # Bugfixes
> 
> - fix: use String(field) in lookup when checking for "constructor" - d541378
> - test: add fluent API for testing Handlebars - c2ac79c
> 
> Compatibility notes:
> - no incompatibility are to be expected
></tr></table> ... (truncated)
</details>
<details>
<summary>Commits</summary>

- [`c819c8b`](c819c8b533) v4.5.3
- [`827c9d0`](827c9d0747) Update release notes
- [`f7f05d7`](f7f05d7558) fix: add "no-prototype-builtins" eslint-rule and fix all occurences
- [`1988878`](1988878087) fix: add more properties required to be enumerable
- [`886ba86`](886ba86c2f) test/chore: add chai/expect and sinon to "runtime"-environment
- [`0817dad`](0817dad7e7) test: add sinon as global variable to eslint in the specs
- [`93516a0`](93516a0b07) test: add sinon.js for spies, deprecate current assertions
- [`93e284e`](93e284ed9b) chore: add chai and dirty-chai for better test assertions
- [`c02b05f`](c02b05fa81) fix: use !== 0 instead of != 0
- [`8de121d`](8de121d21c) v4.5.2
- Additional commits viewable in [compare view](https://github.com/wycats/handlebars.js/compare/v4.1.2...v4.5.3)
</details>
<br />

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=handlebars&package-manager=npm_and_yarn&previous-version=4.1.2&new-version=4.5.3)](https://help.github.com/articles/configuring-automated-security-fixes)

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot ignore this [patch|minor|major] version` will close this PR and stop Dependabot creating any more for this minor/major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
- `@dependabot use these labels` will set the current labels as the default for future PRs for this repo and language
- `@dependabot use these reviewers` will set the current reviewers as the default for future PRs for this repo and language
- `@dependabot use these assignees` will set the current assignees as the default for future PRs for this repo and language
- `@dependabot use this milestone` will set the current milestone as the default for future PRs for this repo and language

You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/zeit/now/network/alerts).

</details>
2019-12-30 14:13:42 +00:00
Shu Ding
847102cf62 Publish Canary
- @now/frameworks@0.0.2-canary.2
2019-12-28 07:23:53 +08:00
Shu Ding
25d5b9c9cf add missing logos (#3475) 2019-12-28 07:22:47 +08:00
Nathan Rajlich
271bab786e Publish Canary
- now@16.7.1-canary.4
 - now-client@6.0.1-canary.1
 - @now/routing-utils@1.4.1-canary.3
2019-12-23 17:33:19 -08:00
Nathan Rajlich
028e023aba [now-routing-utils] Make status code be configurable (#3470)
Now v1 static deployments use 301 by default, so this change allows the routing utils to match that behavior.
2019-12-24 00:56:47 +00:00
Steven
39719eed20 [now-client] Fix single file deploy with new routing properties (#3465)
There is an undocumented feature that adds a route when a single file is deployed, for example a single image or a zip file. This was causing the legacy routes to be added even when `rewrites` or `redirects` was defined. This PR fixes that case when the user has a single file, `now.json`, with redirects defined.
2019-12-24 00:07:30 +00:00
Andy Bitz
438339258d Publish Canary
- @now/build-utils@1.2.1-canary.5
2019-12-23 22:21:11 +01:00
Andy
be445c987c [now-build-utils] Only add 404 route when there are no api routes (#3468)
* [now-build-utils] Only add 404 route when there are no api routes

* Fix startWith

* Update packages/now-build-utils/src/detect-routes.ts

Co-Authored-By: Steven <steven@ceriously.com>

* Import isHandler

Co-authored-by: Steven <steven@ceriously.com>
2019-12-23 22:20:10 +01:00
Andy Bitz
93fef7885b Publish Canary
- @now/static-build@0.14.1-canary.6
2019-12-23 18:32:49 +01:00
Andy
899c9962ad [now-static-build] Ensure outputDirectory is used when it exists (#3466) 2019-12-23 18:32:29 +01:00
Andy Bitz
2b601d2424 Publish Canary
- @now/static-build@0.14.1-canary.5
2019-12-23 17:15:20 +01:00
Andy
3e36b05434 [now-static-build] Fix outputDirectory and add test (#3464) 2019-12-23 17:14:19 +01:00
Andy Bitz
59c9665c3f Publish Canary
- @now/static-build@0.14.1-canary.4
2019-12-23 15:57:53 +01:00
Andy
901137c7f6 [now-static-build] Add missing frameworks (#3463)
* [now-static-build] Add missing frameworks

* Update test

* Revert "Update test"

This reverts commit 86b2169caf145200b164b0c2f860c22d50b495cb.
2019-12-23 15:55:41 +01:00
Andy Bitz
e594e7bbbb Publish Canary
- @now/build-utils@1.2.1-canary.4
2019-12-23 10:02:00 +01:00
Andy
a477b1c22e [now-build-utils] Add option to ignore build script (#3461) 2019-12-23 10:00:45 +01:00
Andy Bitz
22ac20d838 Publish Canary
- @now/frameworks@0.0.2-canary.1
 - @now/build-utils@1.2.1-canary.3
 - now@16.7.1-canary.3
 - now-client@6.0.1-canary.0
 - @now/static-build@0.14.1-canary.3
2019-12-20 16:30:42 +01:00
Andy
3794234d7a [now-build-utils][now-static-build][now-cli] Update detectors and undo previous changes (#3452)
* Revert detect-builders and detect-routes changes

* Add `projectSettings` and support non-api routes

* Start with framework detectors

* Update @now/static-build

* Update now-dev

* Update tests

* Use local builders fro testing with now-dev

* Add outputDirectory to @now/static builds

* Ignore update only for bundeled builders

* Revert now-dev builder changes

* Revert more changes

* Adjust tests further

* Update gridsome test

* Adjust hugo test

* Undo version change

* Read file instead of importing

* Ignore failed.page.txt

* Update packages/now-build-utils/src/detect-builders.ts

Co-Authored-By: Steven <steven@ceriously.com>

* Simplify outputDirectory

* Remove NODE_ENV

* Convert tests to typescript

* Remove console.log

Co-authored-by: Steven <steven@ceriously.com>
2019-12-20 16:29:39 +01:00
Andy Bitz
92a40db048 Publish Stable
- @now/next@2.3.1
2019-12-20 14:28:26 +01:00
Steven
502aad7c2b Publish Canary
- @now/build-utils@1.2.1-canary.2
 - now@16.7.1-canary.2
 - @now/next@2.3.1-canary.3
 - @now/python@1.0.2-canary.0
 - @now/static-build@0.14.1-canary.2
2019-12-19 13:33:02 -05:00
Steven
b49afb61a6 [now-build-utils] Add handle: miss route to zero config (#3403)
This PR adds the route `handle: miss` and a catch-all route for the api directory.

The plan is to rename files in `/api` and `/public` (in a future PR) to be extension-less and then the route is only used to rewrite the extension to the extension-less file (for example, `/api/user.go` => `/api/user`)

This reduces the routes needed for zero config (previously N routes for N files down to 1 route for N files).
2019-12-19 18:30:48 +00:00
Steven
d380902ad3 [all] Fix types for Route vs Source (#3450)
This PR deletes the incorrect `Route` type defined in `@now/build-utils` and instead relies on the correct type defined in `@now/routing-utils`. There is no change to runtime code since this is strictly a change to the typescript types. The one exception to this is I had to change the sort order for our build script so that `@now/routing-utils` is built first.

This is necessary for PR #3403
2019-12-18 23:10:26 +00:00
Andy
ffaed62094 [now-dev] Update tests with verbose logging (#3447)
Updates the tests for `now dev` to log more and make the hopefully more reliable.
2019-12-18 21:57:59 +00:00
Tommaso De Rossi
b0adeb68fe [now-python] Skip reinstalling user dependencies for now dev (#3352)
Same as #2926 but for python
Fixes #3351
2019-12-18 21:04:06 +00:00
JJ Kasper
2372832654 Publish Canary
- @now/next@2.3.1-canary.2
 - @now/routing-utils@1.4.1-canary.2
2019-12-18 13:57:42 -06:00
JJ Kasper
e6a9586b7e [now-routing-utils] Add replacing of multi-match characters (#3446)
This makes sure to replace multi-match characters used in `path-to-regexp` when converting redirects.

Fixes `/:path*/` being converted to `/$1*/` and now converts it to `/$1/`
2019-12-18 19:43:58 +00:00
Tim Neutkens
9687415eed Publish Canary
- @now/next@2.3.1-canary.1
2019-12-18 10:54:34 +01:00
JJ Kasper
49b375ed6a [now-next] Disable running next export from export-intent (#3448)
As requested by @timneutkens after investigating we're disabling auto running `next export` for the user during a build since most users who want their app exported will define `next export` in their `build` script
2019-12-18 03:01:33 +00:00
Shu Ding
906dea096e Publish Canary
- @now/frameworks@0.0.2-canary.0
 - @now/next@2.3.1-canary.0
2019-12-18 03:04:00 +08:00
Shu Ding
3225a83084 Add @now/frameworks (#3445)
* add @now/frameworks

* add newlines

* add websites

* add logos
2019-12-18 02:35:45 +08:00
JJ Kasper
87794cfcc5 [now-next] Remove node 8 test (#3426)
This removes the `node 8` firebase test since `node 8` is being deprecated and we have the same test running against `node 10` also
2019-12-17 16:08:56 +00:00
Steven
79ad0ce0c4 Publish Canary
- @now/routing-utils@1.4.1-canary.1
2019-12-17 10:24:05 -05:00
Steven
fda5987465 [now-routing-utils] Merge routes with multiple handles (#3442)
This PR adds support for `handle: miss` and `handle: hit` and really any arbitrary `handle` when merging routes from the builder and from the user.
2019-12-17 15:16:07 +00:00
Andy Bitz
5cfdd5a6b2 Publish Canary
- @now/build-utils@1.2.1-canary.1
 - now@16.7.1-canary.1
 - @now/static-build@0.14.1-canary.1
2019-12-17 15:32:03 +01:00
Andy Bitz
bd6e0f9f93 Publish Stable
- @now/next@2.3.0
2019-12-17 15:30:37 +01:00
Andy
aa8d002309 [now-cli][now-build-utils] Adjust tests for new detectors (#3443)
* Adjust README

* Fix now-dev test

* Add hugo to the PATH

* Fix Hugo build

* Add more logging

* Resolve path

* Do not use the build script as dev command

* Update yarn.lock file

* fetch with retry

* Remove sh from README

* Use Set for Hugo config files
2019-12-17 15:27:12 +01:00
Andy Bitz
42ce9aca86 Publish Canary
- @now/build-utils@1.2.1-canary.0
 - now@16.7.1-canary.0
 - @now/next@2.2.1-canary.1
 - @now/routing-utils@1.4.1-canary.0
 - @now/static-build@0.14.1-canary.0
2019-12-17 00:25:35 +01:00
Andy
156f596189 [now-cli][now-static-build] Add support for buildCommand, devCommand and outputDirectory (#3434)
* Revert "Revert "[now-static-build] Add support `buildCommand`, `devCommand` and `outputDirectory` (#3422)" (#3428)"

This reverts commit f7b4dd4458.

* Handle generic node projects with /public

* Remove .only

* Ensure node_modules/.bin is also available during `now dev`

* Remove config log

* Adjust test

* Fix integration tests

* Fix public check

* Remove build + public

* Remove _scan

* Remove any casting

* Use `spawnCommand` for dev

* Remove unused import

* Remove cross-spawn

* Fix null config

* Fix build

* Only do a single Buffer.concat
2019-12-17 00:21:58 +01:00
JJ Kasper
8acfd5bf71 [now-next] Add testing for export handling (#3437)
Follow up to #3431 adding tests for this behavior

Tests to add:
- [x] custom routes: redirects
- [x] custom routes: rewrites
- [x] confirming each test is actually a `next export` deploy somehow
2019-12-16 22:47:36 +00:00
Andy
76c99ebb28 [now-build-utils] Restore previous detectors (#3441) 2019-12-16 23:20:48 +01:00
Alejandro Pacheco
5fb119b99c [now-cli] Changed scale error message (#3394)
The error message does not give a clear reason of why it failed
2019-12-16 21:44:40 +00:00
Steven
99b766d9cb [now-routing-utils] Add validation for handle:hit and handle:miss (#3438)
This PR adds initial support for `handle: hit` and `handle: miss` routes.
2019-12-16 20:56:48 +00:00
Andy
c207cf9b40 [now-cli] Change --team warning style (#3439)
* [now-cli] Change warning style

* Adjust test

* Fix screen error
2019-12-16 19:38:43 +01:00
Andy
dd00ac4621 [now-cli] Change automatic version detection message (#3440)
* [now-cli] Change automatic version detection message

* Fix unit test
2019-12-16 19:16:23 +01:00
Allen Hai
3d18a067a0 remove unused vars from builder-cache file (#3411) 2019-12-16 09:03:58 -05:00
Tim Neutkens
c48571a799 Publish Canary
- @now/next@2.2.1-canary.0
2019-12-16 12:49:02 +01:00
Joe Haddad
6eeb6983d9 [now-next] Support for next export (#3431)
* Add Support for `next export`

* Add some test cases

* tests require canary next.js

* bump

* fix test cases

* Update packages/now-next/src/index.ts

Co-Authored-By: Joe Haddad <joe.haddad@zeit.co>

* Update packages/now-next/src/index.ts

Co-Authored-By: Joe Haddad <joe.haddad@zeit.co>
2019-12-16 12:46:39 +01:00
Steven
aee33f040d Publish Stable
- @now/build-utils@1.2.0
 - @now/cgi@1.0.1
 - now@16.7.0
 - @now/go@1.0.1
 - @now/next@2.2.0
 - @now/node@1.3.0
 - @now/python@1.0.1
 - @now/ruby@1.0.1
 - @now/static-build@0.14.0
2019-12-14 07:58:04 -05:00
Steven
b100677b3b Publish Canary
- @now/next@2.1.2-canary.3
2019-12-14 07:18:41 -05:00
Joe Haddad
9241b3ae2f [now-next] Compute Rewrites & Redirects Earlier (#3430)
This PR strictly moves code to make the diff for an upcoming PR cleaner.
2019-12-14 03:04:35 +00:00
Steven
1088da6871 Publish Canary
- @now/build-utils@1.1.2-canary.5
 - now@16.6.4-canary.6
 - @now/next@2.1.2-canary.2
 - @now/node@1.2.2-canary.2
 - @now/static-build@0.13.2-canary.3
2019-12-13 18:12:54 -05:00
Andy
f7b4dd4458 Revert "[now-static-build] Add support buildCommand, devCommand and outputDirectory (#3422)" (#3428)
This reverts commit 5a6d1a135f.
2019-12-13 18:12:16 -05:00
Steven
fb85b6b27a Publish Canary
- @now/build-utils@1.1.2-canary.4
 - now@16.6.4-canary.5
 - @now/next@2.1.2-canary.1
 - @now/node@1.2.2-canary.1
 - @now/static-build@0.13.2-canary.2
2019-12-13 17:24:55 -05:00
Steven
2e5e9b9a6f [now-build-utils] Fix error tput: No value for $TERM and no -T specified (#3425) 2019-12-13 17:23:41 -05:00
Steven
d3cc306e5b [now-build-utils] Remove unused execa (#3427)
~~Reverts the execa bump from #3422~~

Removes `execa` since it is no longer used.
2019-12-13 17:23:18 -05:00
Steven
d6c6a2a271 [docs] Fix broken link to runtimes (#3424) 2019-12-13 15:48:06 -05:00
Andy Bitz
6171a58ae3 Publish Canary
- @now/build-utils@1.1.2-canary.3
 - now@16.6.4-canary.4
 - @now/static-build@0.13.2-canary.1
2019-12-13 19:39:50 +01:00
Andy
5a6d1a135f [now-static-build] Add support buildCommand, devCommand and outputDirectory (#3422)
* [now-static-build] Handle `buildCommand`, `devCommand` and `outputDirectory`

* Adjust tests

* Swap order

* Add `node_modules/.bin` to PATH

* Remove @types/execa

* Append PATH only to spawn options

* Remove test check

* Only add when there is a command
2019-12-13 19:30:09 +01:00
Steven
68deab9007 [tests] Fix unit test coverage (#3420)
This PR reduces the time running Circle CI tests.

Since creating the monorepo in #2812, the coverage broke and then was fixed in #2876 with a workaround which would run unit tests twice.

More recently, we enabled Now CLI to always run tests in #3305 so that means coverage data is always generated.

This PR is a final proper fix so that unit tests run once which saves approximately 2 minutes per push (CI workflow).
2019-12-12 22:13:02 +00:00
Steven
d6114e2bef [deps] Fix yarn.lock signal-exit (#3419)
This patch was lost in a previous PR so I added it back
2019-12-12 20:16:21 +00:00
Steven
5fdc55f3fb [now-cli] Remove dead link to max lambda size (#3418)
We used to have a default `maxLambdaSize` and allow the user to increase to 50 MB.

However, this is no longer true. Today, the `maxLambdaSize` for every function is 50 MB and is not configurable, it's a hard limit.

This PR removes the dead link to avoid confusion like in Issue #3416.
2019-12-12 19:41:54 +00:00
Mark Glagola
751b166536 [now-cli] Add renewal price to now domains inspect (#3401)
Adds `Renewal Price` to `now domains inspect` command if the domain was bought with ZEIT.
2019-12-12 18:03:19 +00:00
Andy Bitz
6ffc8d97f4 Publish Canary
- @now/build-utils@1.1.2-canary.2
 - now@16.6.4-canary.3
2019-12-12 18:37:10 +01:00
Andy
67a80d6b83 [now-cli][now-build-utils] Update detectors (#3402)
* [now-build-utils] Consider `yarn build` and `npm run build` as `buildCommand`

* [@now/build-utils] Update new detectors

* Update unit tests

* [@now/build-utils] Update detect-builder and detect-routes

* Update tests

* Run prettier

* Add more tests

* [now-cli] Use default detectors

* Add now-dev test

* Add a generic node project fallback

* Fix build

* Use public as default

* Ensure generic node project is last

* Update tests

* Update tests again

* Update packages/now-build-utils/src/detectors/filesystem.ts

Co-Authored-By: Nathan Rajlich <n@n8.io>

* Remove parentheses

* Revert "Remove parentheses"

This reverts commit 03f9aba07b0a6d4088719ca9afd602ce8fb1e9c1.

* Use getDependencyVersion instead of hasDependency
2019-12-12 18:28:24 +01:00
Steven
934cf772bc Publish Canary
- @now/build-utils@1.1.2-canary.1
 - now@16.6.4-canary.2
2019-12-12 10:58:21 -05:00
Andy
b01a24afdb [now-build-utils][now-cli] Move builds schema and functions schema to build-utils (#3417)
* [@now/build-utils] Add functions schema

* [now-cli] Use functions schema from build-utils

* Move buildsSchema to build-utils

* Add retries to test

* Add await
2019-12-12 16:02:19 +01:00
hi_Haowen
0ad75b52bf [now dev] Fix validate functions config failed in now json (#3414)
Follow up to #3408 .

```
> Error! Checking for updates failed
> Now CLI 16.6.3 dev (beta) — https://zeit.co/feedback/dev
> Error! Invalid `functions` property: ['api/test.js'] should NOT have additional properties
```
2019-12-12 13:59:39 +00:00
Andy Bitz
050772e78a Publish Canary
- now@16.6.4-canary.1
2019-12-12 13:23:12 +01:00
Andy
7c05dc1420 [now-cli] Do not handle cert errors for deployments (#3409)
Domain related things for deployment will now happen async
2019-12-12 13:19:26 +01:00
Steven
bdd25ac727 Publish Canary
- @now/build-utils@1.1.2-canary.0
 - @now/cgi@1.0.1-canary.1
 - now@16.6.4-canary.0
 - @now/go@1.0.1-canary.1
 - @now/next@2.1.2-canary.0
 - @now/node@1.2.2-canary.0
 - @now/python@1.0.1-canary.1
 - @now/ruby@1.0.1-canary.1
 - @now/static-build@0.13.2-canary.0
2019-12-11 17:30:11 -05:00
Steven
3a27328828 [now-build-utils] Discontinue Node 8 (#3406)
This PR adds a `discontinueDate` to Node 8 and prints a warning if the current deployment is using it.

```
    ┌──────────────────────────────────────────────────────────────────────────────────────────────┐
    │                                                                                              │
    │   WARNING                                                                                    │
    │                                                                                              │
    │   Node.js 8.10.x will be discontinued on 2020-01-06.                                         │
    │   Deployments created on or after 2020-01-06 will fail to build.                             │
    │   Please use one of the following supported `engines` in `package.json`: ["12.x","10.x"]     │
    │   This change is a result of a decision made by an upstream infrastructure provider (AWS).   │
    │   Read more: https://docs.aws.amazon.com/lambda/latest/dg/runtime-support-policy.html        │
    │                                                                                              │
    └──────────────────────────────────────────────────────────────────────────────────────────────┘
```

Starting January 2020, Node 8 deployments will fail to build and print an error.

```
Found `engines` in `package.json` with an unsupported Node.js version range: 8.10.x
Please use one of the following supported ranges: ["12.x","10.x"]
```

[PRODUCT-796]

[PRODUCT-796]: https://zeit.atlassian.net/browse/PRODUCT-796
2019-12-11 22:27:16 +00:00
Nathan Rajlich
c076a5620f [all] Move "Downloading deployment source files" message to download() (#3413)
Before, the debug log message "Downloading user files..." was copy+pasted to all the builders.

This change centralizes that log message to be inside the `download()` function for consistency and DRY purposes.

Additionally, the wording has changed as per [INFRA-289], and a resulting timestamp message is also printed.

[INFRA-289]: https://zeit.atlassian.net/browse/INFRA-289
2019-12-11 20:59:14 +00:00
Nathan Rajlich
2bd8ef9eed [now-next] Do not pass runtime env vars via argv in now dev (#3340)
Before this change, in `@now/next` when running via `now dev`,
the runtime env vars get passed to the child `dev-server.js`
process via argv.

This is problematic because it causes the env vars to be visible in
the process listing, and also causes the command itself to be very
large.

In some cases, with a lot of env vars, we've seen the command be too
large and it will fail to spawn (https://serverfault.com/a/163390/294389).

This changes the start-up process such that the env vars are passed
in via Node.js `fork()` IPC, rather than via `argv`.
2019-12-11 19:18:08 +00:00
JJ Kasper
500014f2fc [now-next] Handle symlinks in createPseudoLayer (#3404)
This makes sure to handle symlinks created in mono repos while creating the zip for a lambda based page in Next.js

Fixes #3400
2019-12-11 15:43:14 +00:00
JJ Kasper
17687e9bcd Fix unused pre-commit package overriding husky (#3405)
Saw my `pre-commit` hook wasn't being triggered after running `yarn` and noticed it was due to an un-used `pre-commit` dependency in `now-cli` overriding the changes to my `.git/hooks/pre-commit` file done by `husky`

**Note**: you will probably need to run `yarn install --force` after this is applied before the correct `pre-commit` changes are applied by `husky`
2019-12-11 14:35:30 +00:00
Andy
90354e9fe7 [now-cgi][now-next][now-ruby] Unify logging about downloading user files (#3397)
* [now-cgi][now-next][now-ruby] Unify logging about downloading user files

* Update next tests

* Bump Next.js Version
2019-12-10 21:15:32 +01:00
Leo Lamprecht
6236631beb [now-dev] Improved feedback link (#3399)
We've shut down our Typeform for feedback, so we can simply the feedback link. The old one will continue working, but we should start using the new one.

Pending on https://github.com/zeit/front/pull/5874.

Fixes #3377
2019-12-10 18:18:10 +00:00
366 changed files with 20598 additions and 2894 deletions

View File

@@ -340,6 +340,10 @@ jobs:
- run:
name: Running Unit Tests
command: yarn test-unit --clean false
- persist_to_workspace:
root: .
paths:
- packages/now-cli/.nyc_output
coverage:
docker:
@@ -349,12 +353,6 @@ jobs:
- checkout
- attach_workspace:
at: .
- run:
name: Compiling `now dev` HTML error templates
command: node packages/now-cli/scripts/compile-templates.js
- run:
name: Run unit tests
command: yarn workspace now run test-unit
- run:
name: Run coverage report
command: yarn workspace now run coverage

2
.gitignore vendored
View File

@@ -19,3 +19,5 @@ packages/now-cli/test/dev/fixtures/08-hugo/hugo
packages/now-cli/test/dev/fixtures/**/dist
packages/now-cli/test/dev/fixtures/**/public
packages/now-cli/test/fixtures/integration
test/lib/deployment/failed-page.txt
.DS_Store

View File

@@ -6,7 +6,7 @@ A Runtime is an npm module that exposes a `build` function and optionally an `an
Official Runtimes are published to [npmjs.com](https://npmjs.com) as a package and referenced in the `use` property of the `now.json` configuration file.
However, the `use` property will work with any [npm install argument](https://docs.npmjs.com/cli/install) such as a git repo url which is useful for testing your Runtime.
See the [Runtimes Documentation](https://zeit.co/docs/v2/advanced/runtimes) to view example usage.
See the [Runtimes Documentation](https://zeit.co/docs/runtimes) to view example usage.
## Runtime Exports

View File

@@ -0,0 +1,708 @@
[
{
"name": "Next.js",
"slug": "nextjs",
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/next.svg",
"tagline": "Next.js makes you productive with React instantly — whether you want to build static or dynamic sites. ",
"website": "https://nextjs.org",
"detectors": {
"every": [
{
"file": "package.json",
"matchContent": "\"(dev)?(d|D)ependencies\":\\s*{[^}]*\"next\":\\s*\".+?\"[^}]*}"
}
]
},
"settings": {
"buildCommand": {
"placeholder": "`next build` or `build` from `package.json`"
},
"devCommand": {
"value": "next dev --port $PORT"
},
"outputDirectory": {
"placeholder": "Next.js default"
}
}
},
{
"name": "Gatsby",
"slug": "gatsby",
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/gatsby.svg",
"tagline": "Gatsby helps developers build blazing fast websites and apps with React.",
"website": "https://gatsbyjs.org",
"detectors": {
"every": [
{
"file": "package.json",
"matchContent": "\"(dev)?(d|D)ependencies\":\\s*{[^}]*\"gatsby\":\\s*\".+?\"[^}]*}"
}
]
},
"settings": {
"buildCommand": {
"placeholder": "`gatsby build` or `build` from `package.json`"
},
"devCommand": {
"value": "gatsby develop --port $PORT"
},
"outputDirectory": {
"value": "public"
}
}
},
{
"name": "Hexo",
"slug": "hexo",
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/hexo.svg",
"tagline": "Hexo is a fast, simple & powerful blog framework powered by Node.js.",
"detectors": {
"every": [
{
"file": "package.json",
"matchContent": "\"(dev)?(d|D)ependencies\":\\s*{[^}]*\"hexo\":\\s*\".+?\"[^}]*}"
}
]
},
"settings": {
"buildCommand": {
"placeholder": "`hexo generate` or `build` from `package.json`"
},
"devCommand": {
"value": "hexo server --port $PORT"
},
"outputDirectory": {
"value": "public"
}
}
},
{
"name": "Eleventy",
"slug": "eleventy",
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/eleventy.svg",
"tagline": "11ty is a simpler static site generator written in JavaScript, created to be an alternative to Jekyll.",
"detectors": {
"every": [
{
"file": "package.json",
"matchContent": "\"(dev)?(d|D)ependencies\":\\s*{[^}]*\"@11ty\\/eleventy\":\\s*\".+?\"[^}]*}"
}
]
},
"settings": {
"buildCommand": {
"placeholder": "`npx @11ty/eleventy` or `build` from `package.json`"
},
"devCommand": {
"value": "npx @11ty/eleventy --serve --watch --port $PORT"
},
"outputDirectory": {
"value": "_site"
}
}
},
{
"name": "Docusaurus",
"slug": "docusaurus",
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/docusaurus.svg",
"tagline": "Docusaurus makes it easy to maintain Open Source documentation websites.",
"detectors": {
"some": [
{
"file": "package.json",
"matchContent": "\"(dev)?(d|D)ependencies\":\\s*{[^}]*\"docusaurus\":\\s*\".+?\"[^}]*}"
},
{
"file": "package.json",
"matchContent": "\"(dev)?(d|D)ependencies\":\\s*{[^}]*\"@docusaurus\\/core\":\\s*\".+?\"[^}]*}"
}
]
},
"settings": {
"buildCommand": {
"placeholder": "`docusaurus-build` or `build` from `package.json`"
},
"devCommand": {
"value": "docusaurus-start --port $PORT"
},
"outputDirectory": {
"value": "build"
}
}
},
{
"name": "Preact",
"slug": "preact",
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/preact.svg",
"tagline": "Preact is a fast 3kB alternative to React with the same modern API.",
"website": "https://preactjs.com",
"detectors": {
"every": [
{
"file": "package.json",
"matchContent": "\"(dev)?(d|D)ependencies\":\\s*{[^}]*\"preact-cli\":\\s*\".+?\"[^}]*}"
}
]
},
"settings": {
"buildCommand": {
"placeholder": "`preact build` or `build` from `package.json`"
},
"devCommand": {
"value": "preact watch --port $PORT"
},
"outputDirectory": {
"value": "build"
}
}
},
{
"name": "Ember",
"slug": "ember",
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/ember.svg",
"tagline": "Ember.js helps webapp developers be more productive out of the box.",
"detectors": {
"every": [
{
"file": "package.json",
"matchContent": "\"(dev)?(d|D)ependencies\":\\s*{[^}]*\"ember-cli\":\\s*\".+?\"[^}]*}"
}
]
},
"settings": {
"buildCommand": {
"placeholder": "`ember build` or `build` from `package.json`"
},
"devCommand": {
"value": "ember serve --port $PORT"
},
"outputDirectory": {
"value": "dist"
}
}
},
{
"name": "Vue.js",
"slug": "vue",
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/vue.svg",
"tagline": "Vue.js is a versatile JavaScript framework that is as approachable as it is performant.",
"website": "https://vuejs.org",
"detectors": {
"every": [
{
"file": "package.json",
"matchContent": "\"(dev)?(d|D)ependencies\":\\s*{[^}]*\"@vue\\/cli-service\":\\s*\".+?\"[^}]*}"
}
]
},
"settings": {
"buildCommand": {
"placeholder": "`vue-cli-service build` or `build` from `package.json`"
},
"devCommand": {
"value": "vue-cli-service serve --port $PORT"
},
"outputDirectory": {
"value": "dist"
}
}
},
{
"name": "Scully",
"slug": "scully",
"tagline": "Scully is a static site generator for Angular.",
"detectors": {
"every": [
{
"file": "package.json",
"matchContent": "\"(dev)?(d|D)ependencies\":\\s*{[^}]*\"@scullyio\\/init\":\\s*\".+?\"[^}]*}"
}
]
},
"settings": {
"buildCommand": {
"placeholder": "`ng build && scully` or `build` from `package.json`"
},
"devCommand": {
"value": "ng serve --port $PORT"
},
"outputDirectory": {
"value": "dist"
}
}
},
{
"name": "Angular",
"slug": "angular",
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/angular.svg",
"tagline": "Angular is a TypeScript-based cross-platform framework from Google.",
"website": "https://angular.io",
"detectors": {
"every": [
{
"file": "package.json",
"matchContent": "\"(dev)?(d|D)ependencies\":\\s*{[^}]*\"@angular\\/cli\":\\s*\".+?\"[^}]*}"
}
]
},
"settings": {
"buildCommand": {
"placeholder": "`ng build` or `build` from `package.json`"
},
"devCommand": {
"value": "ng serve --port $PORT"
},
"outputDirectory": {
"value": "dist"
}
}
},
{
"name": "Polymer",
"slug": "polymer",
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/polymer.svg",
"tagline": "Polymer is an open-source webapps library from Google, for building using Web Components.",
"detectors": {
"every": [
{
"file": "package.json",
"matchContent": "\"(dev)?(d|D)ependencies\":\\s*{[^}]*\"polymer-cli\":\\s*\".+?\"[^}]*}"
}
]
},
"settings": {
"buildCommand": {
"placeholder": "`polymer build` or `build` from `package.json`"
},
"devCommand": {
"value": "polymer serve --port $PORT"
},
"outputDirectory": {
"value": "build"
}
}
},
{
"name": "Svelte",
"slug": "svelte",
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/svelte.svg",
"tagline": "Svelte lets you write high performance reactive apps with significantly less boilerplate. ",
"website": "https://svelte.dev",
"detectors": {
"every": [
{
"file": "package.json",
"matchContent": "\"(dev)?(d|D)ependencies\":\\s*{[^}]*\"sirv-cli\":\\s*\".+?\"[^}]*}"
}
]
},
"settings": {
"buildCommand": {
"placeholder": "`rollup -c` or `build` from `package.json`"
},
"devCommand": {
"value": "sirv public --single --dev --port $PORT"
},
"outputDirectory": {
"value": "public"
}
}
},
{
"name": "Create-React-App",
"slug": "create-react-app",
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/react.svg",
"tagline": "Create React App allows you to get going with React in no time.",
"website": "https://create-react-app.dev",
"detectors": {
"some": [
{
"file": "package.json",
"matchContent": "\"(dev)?(d|D)ependencies\":\\s*{[^}]*\"react-scripts\":\\s*\".+?\"[^}]*}"
},
{
"file": "package.json",
"matchContent": "\"(dev)?(d|D)ependencies\":\\s*{[^}]*\"react-dev-utils\":\\s*\".+?\"[^}]*}"
}
]
},
"settings": {
"buildCommand": {
"placeholder": "`react-scripts build` or `build` from `package.json`"
},
"devCommand": {
"value": "react-scripts start"
},
"outputDirectory": {
"value": "build"
}
}
},
{
"name": "Gridsome",
"slug": "gridsome",
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/gridsome.svg",
"tagline": "Gridsome is a Vue.js-powered framework for building websites & apps that are fast by default.",
"detectors": {
"every": [
{
"file": "package.json",
"matchContent": "\"(dev)?(d|D)ependencies\":\\s*{[^}]*\"gridsome\":\\s*\".+?\"[^}]*}"
}
]
},
"settings": {
"buildCommand": {
"placeholder": "`gridsome build` or `build` from `package.json`"
},
"devCommand": {
"value": "gridsome develop -p $PORT"
},
"outputDirectory": {
"value": "dist"
}
}
},
{
"name": "UmiJS",
"slug": "umijs",
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/umi.svg",
"tagline": "UmiJS is an extensible enterprise-level React application framework.",
"website": "https://umijs.org",
"detectors": {
"every": [
{
"file": "package.json",
"matchContent": "\"(dev)?(d|D)ependencies\":\\s*{[^}]*\"umi\":\\s*\".+?\"[^}]*}"
}
]
},
"settings": {
"buildCommand": {
"placeholder": "`umi build` or `build` from `package.json`"
},
"devCommand": {
"value": "umi dev --port $PORT"
},
"outputDirectory": {
"value": "dist"
}
}
},
{
"name": "Sapper",
"slug": "sapper",
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/svelte.svg",
"tagline": "Sapper is a framework for building high-performance universal web apps with Svelte.",
"website": "https://sapper.svelte.dev",
"detectors": {
"every": [
{
"file": "package.json",
"matchContent": "\"(dev)?(d|D)ependencies\":\\s*{[^}]*\"sapper\":\\s*\".+?\"[^}]*}"
}
]
},
"settings": {
"buildCommand": {
"placeholder": "`sapper export` or `build` from `package.json`"
},
"devCommand": {
"value": "sapper dev --port $PORT"
},
"outputDirectory": {
"value": "__sapper__/export"
}
}
},
{
"name": "Saber",
"slug": "saber",
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/saber.svg",
"tagline": "Saber is a framework for building static sites in Vue.js that supports data from any source.",
"detectors": {
"every": [
{
"file": "package.json",
"matchContent": "\"(dev)?(d|D)ependencies\":\\s*{[^}]*\"saber\":\\s*\".+?\"[^}]*}"
}
]
},
"settings": {
"buildCommand": {
"placeholder": "`saber build` or `build` from `package.json`"
},
"devCommand": {
"value": "saber --port $PORT"
},
"outputDirectory": {
"value": "public"
}
}
},
{
"name": "Stencil",
"slug": "stencil",
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/stencil.svg",
"tagline": "Stencil is a powerful toolchain for building Progressive Web Apps and Design Systems.",
"detectors": {
"every": [
{
"file": "package.json",
"matchContent": "\"(dev)?(d|D)ependencies\":\\s*{[^}]*\"@stencil\\/core\":\\s*\".+?\"[^}]*}"
}
]
},
"settings": {
"buildCommand": {
"placeholder": "`stencil build` or `build` from `package.json`"
},
"devCommand": {
"value": "stencil build --dev --watch --serve --port $PORT"
},
"outputDirectory": {
"value": "www"
}
}
},
{
"name": "Nuxt.js",
"slug": "nuxtjs",
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/nuxt.svg",
"tagline": "Nuxt.js is the web comprehensive framework that lets you dream big with Vue.js.",
"website": "https://nuxtjs.org",
"detectors": {
"every": [
{
"file": "package.json",
"matchContent": "\"(dev)?(d|D)ependencies\":\\s*{[^}]*\"nuxt\":\\s*\".+?\"[^}]*}"
}
]
},
"settings": {
"buildCommand": {
"placeholder": "`nuxt build` or `build` from `package.json`"
},
"devCommand": {
"value": "nuxt"
},
"outputDirectory": {
"value": "dist"
}
}
},
{
"name": "Hugo",
"slug": "hugo",
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/hugo.svg",
"tagline": "Hugo is the worlds fastest framework for building websites, written in Go.",
"website": "https://gohugo.io",
"detectors": {
"some": [
{
"file": "config.yaml"
},
{
"file": "config.toml"
},
{
"file": "config.json"
}
]
},
"settings": {
"buildCommand": {
"value": "hugo"
},
"devCommand": {
"value": "hugo server -D -w -p $PORT"
},
"outputDirectory": {
"placeholder": "`public` or `publishDir` from the `config` file"
}
}
},
{
"name": "Jekyll",
"slug": "jekyll",
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/jekyll.svg",
"tagline": "Jekyll makes it super easy to transform your plain text into static websites and blogs.",
"detectors": {
"every": [
{
"file": "_config.yml"
}
]
},
"settings": {
"buildCommand": {
"value": "jekyll build"
},
"devCommand": {
"value": "bundle exec jekyll serve --watch --port $PORT"
},
"outputDirectory": {
"placeholder": "`_site` or `destination` from `_config.yml`"
}
}
},
{
"name": "Brunch",
"slug": "brunch",
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/brunch.svg",
"tagline": "Brunch is a fast and simple webapp build tool with seamless incremental compilation for rapid development.",
"detectors": {
"every": [
{
"file": "brunch-config.js"
}
]
},
"settings": {
"buildCommand": {
"placeholder": "`brunch build --production` or `build` from `package.json`"
},
"devCommand": {
"value": "brunch watch --server --port $PORT"
},
"outputDirectory": {
"value": "public"
}
}
},
{
"name": "Middleman",
"slug": "middleman",
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/middleman.svg",
"tagline": "Middleman is a static site generator that uses all the shortcuts and tools in modern web development.",
"detectors": {
"every": [
{
"file": "config.rb"
}
]
},
"settings": {
"buildCommand": {
"value": "bundle exec middleman build"
},
"devCommand": {
"value": "bundle exec middleman server -p $PORT"
},
"outputDirectory": {
"value": "build"
}
}
},
{
"name": "Vanilla",
"slug": "vanilla",
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/vanilla.svg",
"tagline": "Love the original way of making websites?"
},
{
"name": "Storybook",
"slug": "storybook",
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/storybook.svg",
"tagline": "Storybook is an open source tool for developing UI components in isolation for React, Vue, and Angular.",
"website": "https://storybook.js.org"
},
{
"name": "Docz",
"slug": "docz",
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/docz.svg",
"tagline": "Docz makes it easy to write and publish beautiful interactive documentation for your code.",
"website": "https://docz.site"
},
{
"name": "mdx-deck",
"slug": "mdx-deck",
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/mdx-deck.svg",
"tagline": "MDX Deck allows you to swiftly create React MDX-based presentation decks.",
"website": "https://github.com/jxnblk/mdx-deck"
},
{
"name": "Aurelia",
"slug": "aurelia",
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/aurelia.svg",
"tagline": "Aurelia is an all-in-one framework for building web, desktop, and mobile applications."
},
{
"name": "VuePress",
"slug": "vuepress",
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/vuepress.png",
"tagline": "VuePress is the performant way to create static sites with Vue.js."
},
{
"name": "Charge.js",
"slug": "charge",
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/chargejs.svg",
"tagline": "Charge is an opinionated, zero-config static site generator written in JavaScript."
},
{
"name": "Riot.js",
"slug": "riot",
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/riot.svg",
"tagline": "Riot.js lets you build user interfaces with custom tags using simple and enjoyable syntax."
},
{
"name": "Marko.js",
"slug": "marko",
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/marko.png",
"tagline": "Marko is a super fast UI library that makes building web apps fun."
},
{
"name": "Mithril.js",
"slug": "mithril",
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/mithriljs.svg",
"tagline": "Mithril is a lightweight modern web framework for that makes it easy to build SPAs."
},
{
"name": "Metalsmith",
"slug": "metalsmith",
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/metalsmith.png",
"tagline": "Metalsmith is an extremely simple, extendable static site generator."
},
{
"name": "HyperApp",
"slug": "hyperapp",
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/hyperapp.svg",
"tagline": "HyperApp is a low-footprint framework for building web interfaces without a learning curve."
},
{
"name": "Zola",
"slug": "zola",
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/zola.svg",
"tagline": "Zola is a one-stop static site engine for all of your static needs."
},
{
"name": "Pelican",
"slug": "pelican",
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/pelican.png",
"tagline": "Pelican is a versatile static site generator, written in Python."
},
{
"name": "MkDocs",
"slug": "mkdocs",
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/mkdocs.svg",
"tagline": "MkDocs is a fast, simple and downright gorgeous static site generator that's geared towards building project documentation."
},
{
"name": "Assemble",
"slug": "assemble",
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/assemble.svg",
"tagline": "A static site generator for Grunt.js and Yeoman, Assemble makes it dead simple to build modular sites and blogs."
},
{
"name": "Ionic React",
"slug": "ionic-react",
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/ionic-react.svg",
"tagline": "Ionic React allows you to build mobile PWAs with React and the Ionic Framework."
},
{
"name": "Foundation",
"slug": "foundation",
"logo": "https://raw.githubusercontent.com/zeit/now/master/packages/frameworks/logos/foundation.svg",
"tagline": "Foundation is the most advanced responsive front-end framework in the world."
}
]

26
packages/frameworks/index.d.ts vendored Normal file
View File

@@ -0,0 +1,26 @@
export interface FrameworkDetectionItem {
file: string;
matchContent?: string;
}
interface Setting {
value?: string;
placeholder?: string;
}
export interface Framework {
name: string;
slug: string;
logo: string;
tagline: string;
website: string;
detectors?: {
every?: FrameworkDetectionItem[];
some?: FrameworkDetectionItem[];
};
settings?: {
buildCommand?: Setting;
devCommand?: Setting;
outputDirectory?: Setting;
};
}

View File

@@ -0,0 +1 @@
<svg width="48" height="48" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M24 1L3 8.636l3.203 28.313L24 47l17.797-10.051L45 8.636 24 1z" fill="#DA0B36"/><path d="M24 1v5.106-.023V47l17.797-10.051L45 8.636 24 1z" fill="#C10933"/><path d="M24.022 6L11 36h4.855l2.618-6.713h11.054L32.145 36H37L24.022 6zm3.804 19.15H20.22l3.803-9.403 3.804 9.402z" fill="#fff"/></svg>

After

Width:  |  Height:  |  Size: 374 B

View File

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 52 48">
<path fill="#111" stroke="#190000" stroke-linecap="square" stroke-miterlimit="10" stroke-width=".5" d="M22.32 4.48h7.5l16.5 38.97h-8.55l-3.53-8.9H17.71l-3.63 8.75h-8.4L22.33 4.48h0zm3.53 9.68c.05.15 5.45 13.13 5.45 13.13H20.55s5.27-13.24 5.3-13.13z"/>
<path fill="#fff" stroke="#190000" stroke-linecap="square" stroke-miterlimit="10" stroke-width=".5" d="M25.77 14l5.44 13.13H20.47S25.73 13.9 25.77 14z"/>
</svg>

After

Width:  |  Height:  |  Size: 490 B

View File

@@ -0,0 +1,61 @@
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" fill="none">
<path fill="url(#paint0_linear)" d="M31.48 8.75l-4.44 2.99-4.58-6.9 4.44-2.99 4.58 6.9z"/>
<path fill="url(#paint1_linear)" d="M35.09 29.48l7.58 11.45L33.64 47l-7.6-11.45-1.31-2 9.03-6.06 1.33 2z"/>
<path fill="url(#paint2_linear)" d="M23.7 37.13l1.67 2.52-6.87 4.62-3-4.52 1.5-1 5.38-3.62 1.32 2z"/>
<path fill="url(#paint3_linear)" d="M38.84 24.07l1.93-1.3 3 4.52-4.44 2.99-1.67-2.52 2.5-1.7-1.32-1.99zm-1.18 3.69l-1.33-2 2.51-1.69 1.33 2-2.51 1.69z"/>
<path fill="url(#paint4_linear)" d="M7.7 24.72l-1.5 1.01-4.57-6.9 6.88-4.62 3.2 4.84-5.37 3.6 5.38-3.6 1.36 2.06-5.37 3.61z"/>
<path fill="url(#paint5_linear)" d="M24.47 13.46l-9.04 6.07-1.37-2.06L6.55 6.13 15.58.06 23.1 11.4l1.37 2.06z"/>
<path fill="url(#paint6_linear)" d="M29.55 10.05l-2.51 1.69-1.37-2.07-3.2-4.83 4.43-2.99 4.58 6.9-1.93 1.3z"/>
<path fill="#714896" d="M18.33 40.74l-1.33-2 5.38-3.6 1.32 1.99-5.37 3.61z"/>
<path fill="#6F4795" d="M37.66 27.76l-1.33-2 2.51-1.69 1.33 2-2.51 1.69z"/>
<path fill="#88519F" d="M7.7 24.72l-1.36-2.06 5.38-3.61 1.36 2.06-5.37 3.61z"/>
<path fill="#85509E" d="M27.04 11.74l-1.37-2.07L28.18 8l1.37 2.06-2.51 1.69z"/>
<path fill="#8D166A" d="M35.09 29.48l-9.04 6.07-1.32-2 9.03-6.06 1.33 2z"/>
<path fill="#A70D6F" d="M23.1 11.4l1.37 2.06-9.04 6.07-1.37-2.06 9.04-6.07z"/>
<path fill="#9E61AD" d="M5.14 9.75l1.71 2.57-2.56 1.72-1.7-2.57 2.55-1.72z"/>
<path fill="#8053A3" d="M14.36 40.6l1.7 2.57-2.55 1.72-1.71-2.57 2.56-1.72z"/>
<path fill="url(#paint7_linear)" d="M7.63 43.19L.15 31.8l40-26.93 7.84 11.2L7.63 43.19z"/>
<defs>
<linearGradient id="paint0_linear" x1="-12.53" x2="47.68" y1="-9.38" y2="33.11" gradientUnits="userSpaceOnUse">
<stop stop-color="#C06FBB"/>
<stop offset="1" stop-color="#6E4D9B"/>
</linearGradient>
<linearGradient id="paint1_linear" x1="37.82" x2="4.33" y1="43" y2="6.94" gradientUnits="userSpaceOnUse">
<stop stop-color="#6E4D9B"/>
<stop offset=".14" stop-color="#77327A"/>
<stop offset=".29" stop-color="#B31777"/>
<stop offset=".84" stop-color="#CD0F7E"/>
<stop offset="1" stop-color="#ED2C89"/>
</linearGradient>
<linearGradient id="paint2_linear" x1="-7.42" x2="35.06" y1="-28.24" y2="47.35" gradientUnits="userSpaceOnUse">
<stop stop-color="#C06FBB"/>
<stop offset="1" stop-color="#6E4D9B"/>
</linearGradient>
<linearGradient id="paint3_linear" x1="-24.72" x2="44.39" y1="-12.24" y2="43.73" gradientUnits="userSpaceOnUse">
<stop stop-color="#C06FBB"/>
<stop offset="1" stop-color="#6E4D9B"/>
</linearGradient>
<linearGradient id="paint4_linear" x1="-14.41" x2="49.9" y1="-12.4" y2="44.01" gradientUnits="userSpaceOnUse">
<stop stop-color="#C06FBB"/>
<stop offset="1" stop-color="#6E4D9B"/>
</linearGradient>
<linearGradient id="paint5_linear" x1="40.79" x2="7.22" y1="43.89" y2="7.61" gradientUnits="userSpaceOnUse">
<stop stop-color="#6E4D9B"/>
<stop offset=".14" stop-color="#77327A"/>
<stop offset=".29" stop-color="#B31777"/>
<stop offset=".84" stop-color="#CD0F7E"/>
<stop offset="1" stop-color="#ED2C89"/>
</linearGradient>
<linearGradient id="paint6_linear" x1="-12.52" x2="48.68" y1="-11.86" y2="40.25" gradientUnits="userSpaceOnUse">
<stop stop-color="#C06FBB"/>
<stop offset="1" stop-color="#6E4D9B"/>
</linearGradient>
<linearGradient id="paint7_linear" x1="5.65" x2="34.95" y1="39.23" y2="2.75" gradientUnits="userSpaceOnUse">
<stop stop-color="#6E4D9B"/>
<stop offset=".14" stop-color="#77327A"/>
<stop offset=".53" stop-color="#B31777"/>
<stop offset=".79" stop-color="#CD0F7E"/>
<stop offset="1" stop-color="#ED2C89"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

@@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" width="49" height="48" fill="none">
<path fill="#3F894A" d="M14.52 35.93a3.39 3.39 0 0 0-1.14-2.41 4.65 4.65 0 0 0-.1-.1l-.02-.01a7.6 7.6 0 0 1-2.14-5.4c0-3.08 1.37-11.87 1.67-11.87.23 0 .23 4.24.08 8.22-.1 2.77.3 3.86.96 3.86.88 0 1.02-2.79 1.11-5.92.08-2.57.3-6.14.48-6.16.28 0 .51 3.55.59 6.13.1 3.2.32 5.87 1.05 5.87.77 0 1-1.23.95-3.97-.07-3.34-.07-8.03.17-8.03.3 0 1.3 3.09 1.54 11.88a7.36 7.36 0 0 1-2.14 5.39h-.01l-.11.1a3.39 3.39 0 0 0-1.14 2.42 62.5 62.5 0 0 0-.13 4.62l6.78 6.78c.1-2.95.08-5.74-.05-7.84-.05-.79-.17-1.7-.3-2.43-.05-.23-.2-.44-.2-.63v-25.6c0-2.18 2.05-3.2 3.93 1.58 1.88 4.8 1.35 21.84 1.35 23.05 0 .26-.22.56-.59.86l-.4.29c-1.12.9-1.28 1.95-1.34 2.88-.14 2.26-.25 5.31-.28 8.51l9.34-9.34c-.02-1.1-.05-2.08-.1-2.9-.02-.32-.1-.64-.16-.98-.16-.95-1.35-1.74-2.03-2.43-1.33-1.33-2.19-3.58-2.19-6.11 0-4.11 2.28-9.32 5.1-9.32 2.8 0 5.08 5.2 5.08 9.32 0 2.53-.85 4.78-2.18 6.11-.69.7-1.87 1.48-2.04 2.43-.06.34-.14.66-.16.98l-.07 1.65 13.05-13.05L24.36 0 0 24.36 14.64 39c-.02-1.16-.06-2.2-.12-3.07z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -0,0 +1,15 @@
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" fill="none">
<path fill="url(#paint0_linear)" fill-rule="evenodd" d="M17.1 48l-16-9.4a1.87 1.87 0 0 1-.92-1.61l-.1-25.7A1.89 1.89 0 0 1 1 9.64L17.32.16l7.19 6.76 6.1-6.59 16.2 9.53a1.87 1.87 0 0 1 .93 1.6l.1 25.71a1.89 1.89 0 0 1-.92 1.63l-15.7 9.13-7.52-7.07-6.6 7.13V48z" clip-rule="evenodd" opacity=".9"/>
<path fill="url(#paint1_linear)" fill-rule="evenodd" d="M44.44 13.39l.1 21.59a1.89 1.89 0 0 1-.92 1.63L25.27 47.29a1.85 1.85 0 0 1-1.87 0L4.9 36.38a1.87 1.87 0 0 1-.92-1.6l-.11-21.6a1.89 1.89 0 0 1 .93-1.63L23.15.88a1.85 1.85 0 0 1 1.87.01l18.5 10.89a1.87 1.87 0 0 1 .92 1.6v.01z" clip-rule="evenodd"/>
<path fill="#fff" d="M32.14 19.09l-7.1 1.92.1-10.96-9.5 19.41 7.09-1.92-.11 10.96 9.52-19.41z"/>
<defs>
<linearGradient id="paint0_linear" x1="23.17" x2="31.2" y1="-3.24" y2="50.11" gradientUnits="userSpaceOnUse">
<stop stop-color="#FE4386"/>
<stop offset="1" stop-color="#FFBB94"/>
</linearGradient>
<linearGradient id="paint1_linear" x1="24.59" x2="28.79" y1="2.21" y2="47.42" gradientUnits="userSpaceOnUse">
<stop stop-color="#F8016B"/>
<stop offset="1" stop-color="#FC716A"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@@ -0,0 +1,11 @@
<svg xmlns="http://www.w3.org/2000/svg" width="53" height="42" fill="none">
<path fill="#E2D9C5" d="M17.92 4.81h31.96A4.3 4.3 0 0 0 45.52.44H13.56a4.3 4.3 0 0 1 4.36 4.37z"/>
<path fill="#F2EBDA" d="M41.14 4.76A4.34 4.34 0 0 1 45.5.44H13.55a4.34 4.34 0 0 0-4.36 4.32v35.49h27.6c2.4 0 4.35-1.93 4.35-4.32V4.76z"/>
<path fill="#E2D9C5" d="M40.44.44a4.36 4.36 0 0 0-4.37 4.35v31.38c0 2.4-1.96 4.35-4.38 4.35H37a4.36 4.36 0 0 0 4.37-4.35V4.8c0-2.4 1.96-4.35 4.38-4.35h-5.31z"/>
<path fill="#E2D9C5" d="M32.53 35.92H.5c.03 2.68 1.97 4.6 4.37 4.6H36.9c-2.4 0-4.34-1.92-4.37-4.6z"/>
<path fill="#DDA064" d="M30.19 28c.88-2.74 1.68-5.53 3.56-7.67 4.1-4.66 12.34-6.03 18.31-5.88a53 53 0 0 0-5.38 5.12c-2.12 2.28-6.74 5.3-8.96 5.99-3.46 1.06-5.06 1.24-7.53 2.44z"/>
<path fill="#B57947" d="M30.19 28c.88-2.74 15.9-13.71 21.87-13.56a53.02 53.02 0 0 0-5.38 5.12c-2.12 2.28-6.74 5.32-8.96 6-3.46 1.06-5.06 1.23-7.53 2.44z"/>
<path fill="#1F2D3D" d="M38.06 8.1c0-.37-.34-.66-.77-.66H20.9c-.42 0-.76.3-.76.65 0 .37.34.66.77.66h16.4c.42 0 .76-.3.76-.66zM13.94 8.75h2.75c.45 0 .81-.3.81-.66 0-.36-.36-.65-.81-.65h-2.75c-.45 0-.81.3-.81.65 0 .37.36.66.81.66zM13.9 31.06c-.43 0-.77.3-.77.66 0 .36.34.66.77.66h8.08c.42 0 .77-.3.77-.66 0-.36-.35-.66-.77-.66H13.9zM26.25 24.72c0-.36-.35-.66-.79-.66H13.91c-.43 0-.78.3-.78.66 0 .36.35.66.78.66h11.55c.44 0 .79-.3.79-.66zM31.94 16.84c0-.36-.36-.65-.8-.65H13.93c-.44 0-.8.3-.8.65 0 .37.36.66.8.66h17.23c.43 0 .79-.3.79-.66z"/>
<path fill="#1F2D3D" d="M41.3 26.62a.77.77 0 0 0-.76.78v9.43c0 2-1.6 3.61-3.57 3.61h-.1c-2 0-3.54-1.66-3.56-3.88a.77.77 0 0 0-.77-.77H10.3V5.17c0-2 1.6-3.61 3.57-3.61h28.12l-.06.07-.08.09-.09.1-.07.08-.08.1-.07.1-.07.1-.07.1-.07.1-.06.1-.07.12-.06.1-.05.11-.06.12-.05.1c-.01.05-.03.08-.05.12l-.04.12-.05.12-.04.12-.04.11-.03.13-.04.12-.03.13-.02.12-.03.13-.02.12-.01.15-.02.1-.01.17v.1l-.01.26v6.91c0 .43.34.77.76.77.43 0 .77-.34.77-.77V6.2h7.91c.2 0 .4-.09.55-.23a.78.78 0 0 0 .22-.56C50.72 2.33 48.53 0 45.64 0H13.87a5.14 5.14 0 0 0-5.1 5.17v30.62h-8c-.2 0-.4.09-.55.23a.78.78 0 0 0-.22.56C.03 39.67 2.22 42 5.1 42h31.87c2.81 0 5.1-2.32 5.1-5.17V27.4a.77.77 0 0 0-.77-.78zm.81-21.99l.01-.07.02-.1.02-.07a3.53 3.53 0 0 1 .2-.65l.04-.07.04-.09.03-.06.04-.09.02-.03a3.72 3.72 0 0 1 .32-.48l.02-.02.08-.1.02-.02.1-.1v-.02l.1-.1.02-.01.1-.1h.01a3.46 3.46 0 0 1 1.85-.85v-.01l.16-.02H45.48l.08-.01h.09c1.76 0 3.16 1.28 3.49 3.09H42.1v-.02zm-37 35.81c-1.77 0-3.17-1.28-3.5-3.09h30.22a6 6 0 0 0 .03.24l.02.08a6 6 0 0 0 .03.15l.02.1.03.14.03.1a6.14 6.14 0 0 0 .18.56l.04.1.05.12.04.09.06.12.04.08.08.15.03.05.11.19c0 .02.02.03.03.04l.1.15a4.63 4.63 0 0 0 .13.18l.04.07.08.1.06.07a5.16 5.16 0 0 0 .15.17l.04.04H5.1z"/>
<path fill="#1F2D3D" d="M52.94 14.35v-.03a.77.77 0 0 0-.04-.21v-.01-.01a.77.77 0 0 0-.05-.1v-.01a.78.78 0 0 0-.06-.08l-.01-.02a.78.78 0 0 0-.07-.07l-.01-.02a.8.8 0 0 0-.17-.12l-.02-.01a.79.79 0 0 0-.33-.08c-6.56-.17-15.11 1.4-19.44 6.29-1.89 2.14-2.76 4.86-3.6 7.49l-.22.64v.03l-1.33 4.67a.78.78 0 0 0 .76.99c.34 0 .65-.23.75-.57l1.23-4.33c1.5-.7 2.71-1.02 4.34-1.46.85-.23 1.81-.5 2.97-.85 2.52-.76 7.34-3.97 9.55-6.35a53.37 53.37 0 0 1 5.46-5.18.78.78 0 0 0 .15-.16l.02-.02a.77.77 0 0 0 .11-.32v-.08-.02zm-19.02 6.54c1.83-2.06 4.62-3.62 8.31-4.63 1-.27 2.04-.49 3.12-.67a60.73 60.73 0 0 0-6.83 3.95 62.64 62.64 0 0 0-6.81 5.16c.56-1.4 1.23-2.7 2.21-3.8zm12.12-1.82c-2.16 2.32-6.82 5.3-8.86 5.93-1.13.34-2.08.6-2.92.83-.75.2-1.44.38-2.12.6.3-.29.66-.61 1.08-.98 1.7-1.46 3.88-3.1 6.17-4.62 3.95-2.62 7.53-4.46 10.16-5.26a60.6 60.6 0 0 0-3.5 3.5z"/>
</svg>

After

Width:  |  Height:  |  Size: 3.5 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 13 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 39 KiB

View File

@@ -0,0 +1,73 @@
<svg xmlns="http://www.w3.org/2000/svg" width="483" height="400">
<path fill="#EAF7FE" d="M316 92l15-18c-10-11-30-9-30-9l12-14-20-8c3-9 13-17 13-17-37-14-64 3-64 3 2-9 14-22 14-22-37 2-65 32-65 32 0-5 4-19 4-19s-20 14-31 35c-4 7-19 61-21 73 0 0-5-2-10-1 0 0 7 10 8 14s-7 33-10 38-7 7-9 8c0 0 3 5 6 6 0 0-1 16-3 20s-8 9-10 11c0 0 6 7 10 7l-6 10c-2 2-5-2-5-2l1 8c1 3 0 7-1 9s-5 15-6 21 1 11 1 11 2-3 4-4c0 0 0 13 3 19l9 13s-1-4 1-6c0 0 3 11 18 13 33 5 56 11 94-11 35-21 31-96 42-144 5-23 17-45 27-62 7-8 18-14 18-14h-9z"/>
<ellipse cx="248" cy="377" fill="#E5E5E5" rx="230" ry="17"/>
<path fill="#A1D4E9" d="M83 369l1-5c0-5 1-11 5-16l-3 1c5-6 10-10 13-11l-3-1c3-2 11-3 18-4l-3-2 13 1 21-4-2-6c8 0 20 2 23 3 2 0 3 5 4 5 0 0 20-11 20 8l-1 36-16-1h-28l-43 1v-2H92v-2-2l-9 1z"/>
<path fill="#85C1CE" d="M92 368h-4c0-24 24-30 24-30-21 8-20 27-20 30zM97 363l6-9c8-11 22-12 22-12-25 5-23 30-23 30h-4l1-9h-2z"/>
<path fill="#4F4E51" d="M162 82c-22-8-34-30-34-30s-6 16 1 33c6 12 19 20 26 24l7-27z"/>
<path fill="#5C5B5D" d="M162 82c-22-8-34-30-34-30s2 30 30 43l4-13z"/>
<g fill="#A1D4E9">
<path d="M128 208l-8-8c-4-7-5-15-5-15-2 2-2 6-2 7a55 55 0 00-13-9l-8 1 3 61 21 10s20-31 12-47zM95 181l-12-5s4 3 3 6c0 2 3 2 6 2v-4l3 1z"/>
<path d="M95 181l-4-1 1 4 8-1-5-2z"/>
</g>
<path fill="#CDEAF5" d="M183 64c13-22 56-42 64-45l9-12c-37 2-65 32-65 32 0-5 4-19 4-19s-20 14-31 35c-4 7-19 61-21 73 0 0-5-2-10-1 0 0 7 10 8 14s-7 33-10 38-7 7-9 8c0 0 3 5 6 6 0 0-1 16-3 20s-8 9-10 11c0 0 5 7 9 8l-5 9c-2 2-5-2-5-2l1 8c1 3 0 7-1 9s-5 15-6 21 1 11 1 11 2-3 4-4c0 0 0 13 3 19l9 13s-1-2 1-4c0 0 4 9 19 14 12 4 22 5 36 1 9-3 15-13 15-13-62 20-80-22-73-49 4-13 19-35 19-35-7 2-11-5-11-5s3 0 9-6c5-5 4-34 4-34l-6 1c1 0 2-1 6-10l-3-1v-1c2-6 1-13 3-19l2-5h6l4-17c12-54 25-85 25-85-2 6 2 16 2 16z"/>
<path fill="#5D5C5E" d="M120 235c1 2 1 5-1 6l-38 28c-2 2-5 2-6 0l-56-74c-1-2-1-5 1-6l38-29c2-1 5-1 6 1l56 74z"/>
<path fill="none" stroke="#738083" stroke-miterlimit="10" stroke-width="2" d="M120 235c1 2 1 5-1 6l-38 28c-2 2-5 2-6 0l-56-74c-1-2-1-5 1-6l38-29c2-1 5-1 6 1l56 74z"/>
<path fill="#747F84" d="M109 229l-38 28-41-54 38-29z"/>
<path fill="#414141" d="M98 247c2 2 1 4 0 5-2 1-4 1-5-1v-5c2-1 4 0 5 1z"/>
<path fill="none" stroke="#414141" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2" d="M39 187l12-9"/>
<g fill="#E9F7FE" opacity=".5">
<path d="M91 208l-33 26-18-25 33-25zM75 236l-10 7-5-6 10-7zM95 214l-21 16-2-2 21-16zM99 218l-22 16-2-2 22-16z"/>
<g>
<path d="M82 245l-10 8-5-7 10-7zM102 223l-21 17-2-3 21-16zM105 227l-21 16-2-3 21-16z"/>
</g>
<path d="M70 182l-33 25-3-3 34-26z"/>
</g>
<path fill="#A1D4E9" d="M99 207c-19 15-41 3-41 3 3-6 21-30 34-30 0 0 19 8 7 27zM87 224c-25-7-47-1-47-1-10 2-7 14-2 23l4 14 3-3c5 7 15 12 28 4 16-10 14-37 14-37z"/>
<ellipse cx="214.2" cy="174" fill="#CDEAF5" rx="10.8" ry="13.7"/>
<ellipse cx="160.3" cy="165.8" fill="#CDEAF5" rx="10.8" ry="13.7"/>
<ellipse cx="213.2" cy="170.2" fill="#FFF" rx="10.7" ry="13.5"/>
<ellipse cx="160.2" cy="162.2" fill="#FFF" rx="10.7" ry="13.5"/>
<path fill="#4F4E51" d="M166 156v1c0 2-1 4-3 4l-2-3-2 4c0 4 3 7 5 7 3 0 6-3 6-7 0-3-2-5-4-6z"/>
<path fill="#5C5B5D" d="M255 165c-4-3-9-4-9-4-4-2-13-4-23-5l-31-1h-12a38 38 0 01-4-2l-9-4-13-2-20-1-2 1-2 4v4l2 4 1 2v11c1 3 3 6 10 8l5 1c12 3 17 2 21 0s6-10 8-14v-2l1-1 1-1 3 1 2 1v4l1 4v1c0 3 1 9 4 11 1 2 6 4 11 6l11 2h21c4-1 5-3 7-7l1-1v-1l5-17 9 3 1-5zm-82-4l-4 11c-2 5-2 5-4 6-2 0-9 0-17-2-6-1-10-4-10-6v-18-1h8c6 0 14 3 17 4h2c5 2 8 4 8 6zm66 8l-5 17c-1 2-3 2-10 3h-1a91 91 0 01-24-4c-6-2-7-3-8-6l-1-15c0-2 0-3 2-3h25a143 143 0 0120 4c1 0 3 2 2 4z"/>
<path fill="#4F4E51" d="M216 163v1c0 2-1 4-3 4l-2-3-2 4c0 4 3 7 5 7 3 0 6-3 6-7 0-3-2-5-4-6z"/>
<path fill="#A1D4E9" d="M207 121s19-8 28 1c0 0 0-9-12-9-8 0-12 4-16 8zM211 111s6-6 17-4c0 0-4-4-9-3-4 1-6 3-8 7zM154 127s10 3 14 10c0 0 1-6-4-9-5-2-6-2-10-1zM171 126s-2-4-7-4c0 0 4-2 6 0 0 0 2 2 1 4z"/>
<path fill="#5C5B5D" d="M176 198l25 5 2-4v5s-7 2-13 1l10-1s-13-1-24-6zM280 102l3 2c26 10 52-4 52-4s-4 16-20 27c-15 10-39 5-39 5-2 3-3 10-3 10s-4-9-1-24c2-10 7-16 8-16"/>
<path fill="#747F83" d="M280 102l3 2c26 10 52-4 52-4s-23 31-62 15c0 0 1-7 7-13"/>
<path fill="#CDEAF5" d="M125 231s10 2 16-2c0 0 2 9 10 15 0 0 7-12 14-14l1 11s13 1 25-9c0 0-3 14-30 15v-8s-6 7-10 16c0 0-14-10-16-19h-12l2-5z"/>
<path fill="#85C1CE" d="M76 222s-13 10-22 13c0 0 22-5 29-8 0 0-6 15-24 21 0 0 17-2 24-8 0 0-8 23-25 25 0 0 10 1 19-7 9-9 11-27 10-34l-11-2zM100 207l7-5s0 5-5 8l-2-3z"/>
<path fill="#EAF7FE" d="M331 263c3-2 5-1 4-10-1-8-6-17-6-17M279 221l-5 2 6 2zM334 228s12-3 16-10"/>
<path fill="#85C1CE" d="M130 330s16 10 39 7v-8s-13 1-26-4v3l-4-2v3l-9 1z"/>
<path fill="#CDEAF5" d="M222 347h-3c-11 0-19-2-30-1l-22 1 10-10 1 3 6-10 11-15-17 6-4 6v1c-2-2-4-3-4-1l-1 2c-3 5-17 14-17 14l-2 1 3 1v2l-1 1v5l-1 10c0 2-2 4-4 4 0 0 2 2 3 1v1s-1 8 6 9h21l21 1v-3l12 1 2-4 18 1c3-19-2-26-8-27z"/>
<path fill="#EAF7FE" d="M233 367v-6l1 1-3-8c-2-4-5-7-10-7l1-2c-4-1-7-2-14-1 4-1 8-4 12-7l2 1 2-5h-1l7-8 2 3 6-16-28 9-3 3-11-11-14 19-3 7c-1-1-1-3-2-2-4 4-8 8-12 10h8l-4 2 12-1c12-1 19 4 19 4v-1c1 1 4 3 6 8 0 1 2 8 1 10l2-1v9h8s1-10-1-18h2c-1-4-4-7-7-8l-1-1s16-2 16 23h3l7 1-1-1-2-6zm-27-8l2 4-2-4z"/>
<path fill="#EAF7FE" d="M194 358l2-1c-3-2-7-2-9-2h-2s7 6 6 24h7s3-14-4-21z"/>
<g>
<path fill="#5D5C5E" d="M452 372c0 5-5 9-10 9H237c-6 0-10-4-10-9V227c0-5 4-10 10-10h205c5 0 10 5 10 10v145z"/>
<path fill="none" stroke="#738083" stroke-miterlimit="10" stroke-width="2" d="M452 372c0 5-5 9-10 9H237c-6 0-10-4-10-9V227c0-5 4-10 10-10h205c5 0 10 5 10 10v145h0z"/>
<path fill="#747F84" d="M247 231h185v136H247z"/>
<path fill="#414141" d="M243 299c0 3-2 5-5 5-2 0-4-2-4-5 0-2 2-4 4-4 3 0 5 2 5 4z"/>
<path fill="none" stroke="#414141" stroke-linecap="round" stroke-miterlimit="10" stroke-width="2" d="M440 290v18"/>
<g fill="#E9F7FE" opacity=".5">
<path d="M252 237h176v12H252zM252 252h176v58H252zM252 317h28v20h-28zM284 317h53v5h-53zM284 324h53v5h-53zM284 332h53v5h-53z"/>
<g>
<path d="M342 317h28v20h-28zM374 317h53v5h-53zM374 324h53v5h-53zM374 332h53v5h-53z"/>
</g>
<g>
<path d="M252 343h28v20h-28zM284 343h53v5h-53zM284 351h53v5h-53zM284 358h53v5h-53z"/>
</g>
<g>
<path d="M342 343h28v20h-28zM374 343h53v5h-53zM374 351h53v5h-53zM374 358h53v5h-53z"/>
</g>
</g>
</g>
<g>
<path fill="#EAF7FE" d="M382 187l8 3-10-11-15-7 2-2h-10l-30-4 2-3-39 2 1-4-6 3c0-3 5-9 5-9-6 1-11 9-11 9l-1 5-7 47h112c1-9 0-21-2-29h1zm-94-20z"/>
<path fill="#4F4E51" d="M330 260l-4 5-8-7-12 9-7-10c-2-3-2-14-2-14l-3 2 5-15s30-6 31 30z" opacity=".3"/>
<path fill="#EAF7FE" d="M333 246c1-4-1-8-1-12l2-5c1-2 3-2 5-3a385 385 0 017-4c10-5 37-8 37-8-39-15-95 0-95 0-11 7-17 30-17 30 9-7 35-22 35-22-1 11-16 11 25 41 0-6 2-11 3-17h-1z"/>
<path fill="#CDEAF5" d="M289 197c-7 5-13 12-18 19h15l13-10-15-1s21-5 29-9c10-8 17-13 26-16 0 0 1-1-1-1l4-1 10-3s-20-2-63 22z"/>
<path fill="#4F4E51" d="M285 229h-19l-2 6-1 9 22-15z" opacity=".3"/>
<path fill="#EAF7FE" d="M299 206s-26 15-27 29l-1 9 28-21v-17zM305 224c-5 16-5 16-4 24l2 8 11 11s10-7 9-14c-3-23-18-29-18-29z"/>
<path fill="#EAF7FE" d="M293 230s4-5 14-6c7 0 0-5 0-5l-13 1"/>
<path fill="#EAF7FE" d="M302 252l-2-12-2 2c3-15 2-15 5-19 3-7 3 21 3 21"/>
<path fill="#CDEAF5" d="M317 240c1-5 1-13 3-18l-2 3c-2 4-4 10-4 17 0 8 7 17 7 17l2-2-4-8s-2-3-2-9z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.3 KiB

View File

@@ -0,0 +1 @@
<svg width="48" height="48" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M42.857 24h-12v3.428h8.229c-1.2 5.143-4.972 9.43-9.943 11.143L9.429 18.857c2.057-6 7.885-10.286 14.571-10.286 5.143 0 9.771 2.572 12.686 6.515l2.571-2.229C35.83 8.23 30.343 5.143 24 5.143c-8.914 0-16.457 6.343-18.343 14.743l22.629 22.628c8.228-2.057 14.571-9.6 14.571-18.514zm-37.714.171c0 4.8 1.886 9.429 5.486 13.029 3.6 3.6 8.4 5.486 13.028 5.486L5.143 24.17z" fill="#fff"/><path d="M24 0C10.8 0 0 10.8 0 24s10.8 24 24 24 24-10.8 24-24S37.2 0 24 0zM10.629 37.371c-3.6-3.6-5.486-8.4-5.486-13.028l18.686 18.514c-4.8-.171-9.6-1.886-13.2-5.486zm17.485 4.972L5.657 19.886C7.543 11.486 15.086 5.143 24 5.143c6.343 0 11.829 3.086 15.257 7.714l-2.571 2.229C33.77 11.143 29.143 8.57 24 8.57c-6.686 0-12.343 4.286-14.571 10.286l19.714 19.714c4.971-1.714 8.743-6 9.943-11.142h-8.229V24h12c0 8.914-6.343 16.457-14.743 18.343z" fill="#639"/></svg>

After

Width:  |  Height:  |  Size: 921 B

View File

@@ -0,0 +1 @@
<svg width="48" height="48" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M43.395 19.862c2.308-.11 4.35 1.68 4.55 3.99.863 11.174-9.364 23.692-23.775 24.092C12.025 48.244.013 38.521.013 23.82c0-2.317 1.915-4.195 4.225-4.195a4.19 4.19 0 0 1 4.184 4.195c0 9.67 7.776 15.928 15.542 15.737 9.56-.266 15.776-8.544 15.453-15.303a4.19 4.19 0 0 1 3.978-4.392z" fill="url(#paint0_linear)"/><path d="M32.944 24.145c0-2.372 1.935-4.295 4.321-4.295h6.298c2.387 0 4.382 1.923 4.382 4.295s-1.995 4.295-4.382 4.295h-6.298c-2.386 0-4.321-1.923-4.321-4.295zm-13.215.006a4.297 4.297 0 0 1 4.291-4.301 4.297 4.297 0 0 1 4.292 4.301 4.297 4.297 0 0 1-4.292 4.301 4.297 4.297 0 0 1-4.291-4.301z" fill="#00A672"/><path fill-rule="evenodd" clip-rule="evenodd" d="M28.193 4.055a4.19 4.19 0 0 1-4.006 4.365c-9.966.415-16.05 8.248-15.753 15.685.092 2.315-1.668 4.267-3.976 4.36-2.309.092-4.34-1.777-4.431-4.092C-.456 12.253 9.635.273 23.84.037a4.188 4.188 0 0 1 4.353 4.018z" fill="#00A672"/><defs><linearGradient id="paint0_linear" x1="24.005" y1="19.625" x2="24.005" y2="47.951" gradientUnits="userSpaceOnUse"><stop stop-color="#00583E"/><stop offset="1" stop-color="#00835C"/></linearGradient></defs></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1 @@
<svg width="48" height="48" fill="none" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#clip0)"><path d="M23.829.005l-20.735 12 .002 23.964L23.878 47.92l20.736-12V11.97L23.829.004z" fill="#0E83CD"/><path d="M14.101 34.338l.002-10.362.002-10.363 1.882-1.101 1.804 1.067.019 4.235.02 4.234h12.05l.019-4.231.02-4.232 1.83-1.059 1.857 1.087V23.97l-.002 10.355-1.837 1.027-1.849-1.04-.02-4.21-.019-4.212H17.83l-.019 4.21.006 4.23-1.848 1.085-1.866-1.076z" fill="#fff"/></g><defs><clipPath id="clip0"><path fill="#fff" transform="translate(3)" d="M0 0H41.645V48H0z"/></clipPath></defs></svg>

After

Width:  |  Height:  |  Size: 591 B

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 30 KiB

View File

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" fill="none">
<rect width="48" height="48" fill="#0080FF" rx="24"/>
<path fill="#fff" d="M18.5386 21.6899h7.8153l1.8771 3.8487h-9.6924v9.6902h-3.8481v-9.6902H5v-3.8487h9.6905V12h3.8481v9.6899zm24.1057 13.5389h-4.5342L26.7809 12h4.5341l11.3293 23.2288z"/>
</svg>

After

Width:  |  Height:  |  Size: 328 B

View File

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 48 48">
<rect width="48" height="48" fill="#4180FC" rx="24"/>
<path fill="#fff" fill-rule="evenodd" d="M38.4327 17.0558l.1306.3047C39.5211 19.4721 40 21.6925 40 24c0 8.8163-7.1837 16-16 16S8 32.8163 8 24 15.1837 8 24 8c2.5905 0 5.0503.6095 7.3143 1.7415l.3047.1524-.2612.2177c-.653.5224-1.1537 1.1755-1.4802 1.9374l-.0871.2177-.1959-.0871C27.8313 11.3524 25.9592 10.917 24 10.917c-7.2272 0-13.083 5.8558-13.083 13.083S16.7728 37.083 24 37.083 37.083 31.2054 37.083 24c0-1.7197-.3265-3.4177-1.0014-5.0068l-.087-.2177.2176-.0871c.7619-.283 1.4585-.7619 2.0028-1.3714l.2177-.2612zm-3.962.3048c1.8395 0 3.3307-1.4912 3.3307-3.3306 0-1.8395-1.4912-3.3307-3.3307-3.3307-1.8394 0-3.3306 1.4912-3.3306 3.3307 0 1.8394 1.4912 3.3306 3.3306 3.3306zm-10.4708-.6531c-4.0272 0-7.2925 3.2653-7.2925 7.2926 0 4.0272 3.2653 7.2925 7.2925 7.2925 4.0272 0 7.2925-3.2653 7.2925-7.2925 0-4.0273-3.2653-7.2926-7.2925-7.2926z" clip-rule="evenodd"/>
</svg>

After

Width:  |  Height:  |  Size: 1003 B

View File

@@ -0,0 +1,19 @@
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" fill="none">
<path fill="#333" d="M0 24a24 24 0 1 0 48 0 24 24 0 0 0-48 0z"/>
<path fill="#000" d="M25.22 5.55a.52.52 0 0 0 0 .22s.23 1.56-.03 2.25l-11.35 29.5a4.22 4.22 0 0 0 7.88 3.03l11.35-29.5c.22-.57 1.48-1.7 1.48-1.7.07-.04.12-.1.15-.16v-.01l.02-.04c.3-.76-1.6-2.2-4.21-3.2-2.62-1-4.98-1.2-5.27-.45l-.02.04v.02z" opacity=".3"/>
<path fill="url(#paint0_linear)" d="M24.9 5.3a.51.51 0 0 0-.01.22s.23 1.56-.03 2.25L13.5 37.27a4.22 4.22 0 0 0 7.88 3.03l11.35-29.5c.22-.58 1.49-1.7 1.49-1.7.06-.04.1-.1.14-.16v-.01l.03-.04c.29-.76-1.6-2.2-4.22-3.2-2.62-1-4.98-1.2-5.27-.45l-.01.04v.01z"/>
<path fill="url(#paint1_linear)" d="M28.45 18.64L20.27 39.9a3.06 3.06 0 0 1-3.91 1.72 3.12 3.12 0 0 1-1.83-3.93l5.23-13.59s.65-1.05 1.93-1.8c1.29-.75 2.34-.6 3.77-1.22 1.42-.64 3-2.45 3-2.45z"/>
<path fill="#333" d="M29.33 7.92c1.62.63 3.07.79 3.24.36.16-.43-1.02-1.28-2.65-1.9-1.62-.63-3.08-.8-3.24-.37-.17.43 1.02 1.28 2.65 1.91z"/>
<path fill="#fff" d="M24.89 5.52s.23 1.57-.03 2.25L13.5 37.27a4.22 4.22 0 0 0 3.58 5.68 4.22 4.22 0 0 1-1.41-4.85L26.8 9.19s-1.52-1.42-1.91-3.67z" opacity=".3"/>
<path fill="#fff" d="M21.24 24.87a.33.33 0 1 0 0-.65.33.33 0 0 0 0 .65zM23.4 27.42a.5.5 0 1 0 0-.99.5.5 0 0 0 0 1zM20.1 30.7a.93.93 0 1 0 0-1.87.93.93 0 0 0 0 1.86zM18.6 31.98a.5.5 0 1 0 0-1 .5.5 0 0 0 0 1zM20.57 35.49a.33.33 0 1 0 0-.66.33.33 0 0 0 0 .66z" opacity=".5"/>
<defs>
<linearGradient id="paint0_linear" x1="18.32" x2="27.81" y1="22.36" y2="26.01" gradientUnits="userSpaceOnUse">
<stop stop-color="#919191"/>
<stop offset="1" stop-color="#fff"/>
</linearGradient>
<linearGradient id="paint1_linear" x1="18.08" x2="23.83" y1="28.47" y2="30.68" gradientUnits="userSpaceOnUse">
<stop stop-color="#900"/>
<stop offset="1" stop-color="#E80000"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

View File

@@ -0,0 +1,11 @@
<svg xmlns="http://www.w3.org/2000/svg" width="138" height="57">
<g fill="none" fill-rule="evenodd">
<rect width="136.5" height="55.5" x=".8" y=".8" fill="#FFF" stroke="#EAEAEA" stroke-width="1.5" rx="4.5"/>
<g stroke="#000" stroke-width="6">
<path stroke-linecap="square" d="M70.5 36V13.8"/>
<path d="M57 27.2L70.6 41 84 27.4"/>
</g>
<path stroke="#000" stroke-width="6" d="M16.4 44V19l13.9 13.8 14-14v25"/>
<path stroke="#F9AC00" stroke-width="6" d="M122.4 41.3L93.2 12m.4 29.3L122.8 12"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 539 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@@ -0,0 +1,9 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 48 48">
<rect width="48" height="48" fill="#FBC547" rx="24"/>
<path fill="#000" fill-opacity=".45" d="M6 12.53L23.65 9v2.65L6 14.29v-1.76z"/>
<path fill="#fff" d="M23.65 9l17.64 3.53v1.76l-17.64-2.64V9z"/>
<path fill="#000" fill-opacity=".45" d="M6 15.88v16.24l3.97.44V22.4l3.97 7.33 4.15-7.33V33.8l4.67.62V13.6l-5.02.7-3.8 7.33-3.8-6.18-4.14.44z"/>
<path fill="#fff" d="M41.3 15.88v16.24l-3.98.44V22.4l-3.97 7.33-4.14-7.33V33.8l-4.68.62V13.6l5.03.7 3.8 7.33 3.79-6.18 4.14.44z"/>
<path fill="#000" fill-opacity=".45" d="M6 35.47L23.65 39v-2.65L6 33.71v1.76z"/>
<path fill="#fff" d="M23.65 39l17.64-3.53v-1.76l-17.64 2.64V39z"/>
</svg>

After

Width:  |  Height:  |  Size: 715 B

View File

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" fill="none">
<rect width="48" height="48" fill="#000" rx="24"/>
<path fill="#fff" d="M36.109 17.5974C36.0934 11.1453 30.839 5.9 24.3831 5.9c-6.4659 0-11.7267 5.2609-11.7267 11.7268 0 .0202.0037.0394.0037.0596C9.2734 19.745 7 23.4594 7 27.7033 7 34.1701 12.2599 39.43 18.7267 39.43c2.0816 0 4.0338-.5516 5.7308-1.507 1.697.9554 3.6501 1.507 5.7316 1.507 6.4669 0 11.7268-5.2608 11.7268-11.7267 0-4.3054-2.3386-8.0666-5.8069-10.1059zM24.4575 35.4587c-2.122-1.5722-3.5849-3.9842-3.8731-6.7477 1.1931.4112 2.4679.6443 3.7987.6443 1.3896 0 2.7167-.2551 3.953-.7012-.2735 2.7874-1.742 5.2214-3.8786 6.8046zm-9.6406-16.5782c1.1959-.5314 2.5175-.8343 3.9098-.8343a9.5872 9.5872 0 0 1 3.8126.7875c-1.9403 1.6759-3.3307 3.9695-3.8502 6.5778-2.077-1.5253-3.5225-3.8547-3.8722-6.531zm9.5662 8.4043c-1.3372 0-2.612-.2735-3.7712-.7682.3313-2.6873 1.7704-5.0314 3.8456-6.5687 2.0586 1.5254 3.4895 3.8428 3.8364 6.5026-1.1968.5332-2.5185.8343-3.9108.8343zm1.9926-8.4521a9.6043 9.6043 0 0 1 3.8125-.7874c1.3373 0 2.6121.2735 3.7722.7682-.3267 2.6478-1.7282 4.9598-3.7529 6.4998-.5342-2.5689-1.9154-4.8248-3.8318-6.4806zm-1.9926-10.863c4.9855 0 9.1 3.7969 9.6057 8.6502-1.1931-.4102-2.4679-.6443-3.7997-.6443-2.0815 0-4.0346.5516-5.7316 1.5071-1.6961-.9555-3.6483-1.5071-5.7308-1.5071-1.3895 0-2.7167.2552-3.9529.7003.48-4.8799 4.6055-8.7062 9.6093-8.7062zm-5.6564 29.3916c-5.326 0-9.658-4.332-9.658-9.658 0-3.1371 1.5098-5.9207 3.8337-7.6866.6828 3.2867 2.7525 6.0639 5.5609 7.7169.0101 3.5308 1.5924 6.6935 4.0769 8.8393a9.5766 9.5766 0 0 1-3.8135.7884zm11.4624 0a9.587 9.587 0 0 1-3.8125-.7875c2.4918-2.1522 4.0787-5.3269 4.0787-8.8696 0-.0202-.0037-.0404-.0037-.0596 2.7599-1.6787 4.7809-4.4532 5.4316-7.7243 2.3982 1.7595 3.964 4.5881 3.964 7.783-.001 5.3251-4.333 9.658-9.6581 9.658z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" fill="none">
<circle cx="24" cy="24" r="24" fill="#2FA4E7"/>
<path fill="#fff" d="M32.55 32.91V16h-3.07L24.1 29.23h-.2L18.52 16h-3.07v16.91h2.43V20.52h.17L23 32.61h2l4.95-12.09h.17v12.39h2.43z"/>
</svg>

After

Width:  |  Height:  |  Size: 270 B

View File

@@ -0,0 +1 @@
<svg width="48" height="48" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M22.428.013c-.103.01-.431.042-.727.066C14.883.693 8.497 4.37 4.453 10.024A23.754 23.754 0 0 0 .216 20.51C.023 21.828 0 22.217 0 24.005c0 1.787.023 2.177.216 3.495 1.304 9.012 7.718 16.584 16.417 19.39 1.558.501 3.2.844 5.068 1.05.727.08 3.87.08 4.598 0 3.224-.356 5.954-1.154 8.648-2.529.412-.21.492-.267.436-.314-.038-.028-1.797-2.388-3.909-5.24l-3.838-5.184-4.809-7.117c-2.646-3.913-4.824-7.112-4.842-7.112-.019-.005-.038 3.157-.047 7.018-.014 6.76-.019 7.033-.103 7.192-.122.23-.216.324-.413.427-.15.075-.282.09-.99.09h-.812l-.216-.137a.878.878 0 0 1-.314-.342l-.099-.211.01-9.407.014-9.41.145-.184c.075-.098.235-.225.347-.286.193-.094.268-.103 1.08-.103.957 0 1.116.038 1.365.31.07.075 2.674 3.997 5.79 8.721s7.376 11.175 9.469 14.342l3.8 5.756.192-.127c1.704-1.107 3.505-2.683 4.932-4.325a23.888 23.888 0 0 0 5.65-12.268c.192-1.319.215-1.708.215-3.495 0-1.788-.023-2.177-.216-3.495-1.304-9.013-7.718-16.584-16.417-19.39C29.832.623 28.199.28 26.369.074c-.45-.047-3.551-.099-3.94-.061zm9.825 14.515a.947.947 0 0 1 .474.554c.038.122.047 2.73.038 8.608l-.014 8.436-1.488-2.28-1.492-2.28v-6.132c0-3.964.019-6.193.047-6.3a.957.957 0 0 1 .465-.592c.192-.098.262-.108 1-.108.694 0 .816.01.97.094z" fill="#000"/></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -0,0 +1,5 @@
<svg width="48" height="38" viewBox="0 0 48 38" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.7599 35.9199L14.6399 35.7999C14.3999 35.3199 14.3999 34.8399 14.3999 34.3599H2.99992L20.0399 4.11988L27.1199 16.9599L29.3999 15.2799L22.3199 2.43988C22.1999 2.19988 21.3599 0.879883 19.9199 0.879883C19.3199 0.879883 18.3599 1.11988 17.6399 2.43988L0.479919 33.0399C0.359919 33.2799 -0.360081 34.7199 0.359919 35.9199C0.599919 36.5199 1.31992 37.1199 2.87992 37.1199H17.2799C15.7199 37.1199 14.9999 36.5199 14.7599 35.9199Z" fill="#00C58E"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M47.3999 33.1598L33.5999 8.31977C33.3599 8.07977 32.6399 6.75977 31.1999 6.75977C30.5999 6.75977 29.7599 6.99977 28.9199 8.31977L27.1199 11.1998V16.9598L31.1999 9.87977L44.8799 34.3598H39.7199C39.7913 34.853 39.7075 35.3563 39.4799 35.7998V35.9198C38.7599 37.1198 37.1999 37.1198 36.9599 37.1198H45.1199C45.3599 37.1198 46.9199 37.1198 47.6399 35.9198C47.8799 35.3198 48.1199 34.3598 47.3999 33.1598Z" fill="#108775"/>
<path d="M39.84 35.9199V35.7999L39.96 35.5599C40.08 35.1999 40.2 34.7199 40.08 34.3599L39.6 33.0399L28.8 14.08L27.24 11.2H27.12L25.56 14.08L14.64 33.0399L14.28 34.3599C14.1908 34.8922 14.275 35.4391 14.52 35.9199C14.88 36.5199 15.6 37.1199 17.04 37.1199H37.2C37.56 37.1199 39.12 37.1199 39.84 35.9199ZM27.12 16.96L37.08 34.3599H17.28L27.12 16.96Z" fill="#2F495E"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@@ -0,0 +1 @@
<svg width="48" height="48" fill="none" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#clip0)"><path d="M28.8 40.371L9.6 7.113H19.2l19.201 33.258h-9.6z" fill="#FF4081"/><path d="M28.8 40.371l4.8-8.314 4.802 8.314H28.8z" fill="#fff" fill-opacity=".2"/><path d="M24 32.057l4.8 8.314 4.8-8.314H24z" fill="#fff" fill-opacity=".1"/><path d="M19.2 23.742l4.8 8.315 4.8-8.315h-9.6z" fill="#000" fill-opacity=".1"/><path d="M19.2 23.742l4.8-8.314 4.8 8.314h-9.6z" fill="#000" fill-opacity=".2"/><path d="M14.4 15.428l4.8 8.314 4.8-8.314h-9.6z" fill="#000" fill-opacity=".3"/><path d="M14.4 15.428l4.8-8.315 4.8 8.315h-9.6z" fill="#000" fill-opacity=".4"/><path d="M9.599 7.113l4.801 8.315 4.8-8.315H9.6z" fill="#000" fill-opacity=".5"/><path d="M9.599 40.371L-.002 23.742l4.8-8.314L19.2 40.37H9.599z" fill="#536DFE"/><path d="M9.599 40.371l4.801-8.314 4.8 8.314H9.6z" fill="#fff" fill-opacity=".2"/><path d="M4.799 32.057l4.8 8.314 4.801-8.314H4.8z" fill="#fff" fill-opacity=".1"/><path d="M-.002 23.742l4.8 8.315 4.8-8.315h-9.6z" fill="#000" fill-opacity=".1"/><path d="M-.002 23.742l4.8-8.314 4.8 8.314h-9.6z" fill="#000" fill-opacity=".2"/><path d="M9.599 23.742l-4.8-8.314 4.8-8.315 4.801 8.315L9.6 23.742z" fill="#303F9F"/><path d="M14.4 15.428L9.6 7.113l-4.8 8.315H14.4z" fill="#000" fill-opacity=".2"/><path d="M38.401 40.371l-4.8-8.314 4.8-8.315 4.8 8.315-4.8 8.314z" fill="#3F51B5"/><path d="M43.201 32.057l-4.8 8.314-4.8-8.314h9.6z" fill="#000" fill-opacity=".2"/><path d="M43.201 32.057L28.8 7.113h9.601l9.602 16.63-4.802 8.314z" fill="#7986CB"/><path d="M38.401 23.742l4.8 8.315 4.801-8.315h-9.6z" fill="#fff" fill-opacity=".2"/><path d="M38.401 23.742l4.8-8.314 4.801 8.314h-9.6z" fill="#fff" fill-opacity=".1"/><path d="M33.6 15.428l4.801-8.315 4.8 8.315h-9.6z" fill="#000" fill-opacity=".1"/><path d="M28.8 7.113l4.8 8.315 4.801-8.315H28.8z" fill="#000" fill-opacity=".2"/></g><defs><clipPath id="clip0"><path fill="#fff" transform="translate(0 7)" d="M0 0H48V33.375H0z"/></clipPath></defs></svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@@ -0,0 +1 @@
<svg width="48" height="48" fill="none" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#clip0)"><path d="M23.757 0l20.756 11.984V35.95L23.758 47.935 3 35.951V11.984L23.757 0z" fill="#673AB8"/><path d="M8.654 35.753c2.76 3.532 11.529.84 19.808-5.628S41.474 15.8 38.714 12.267s-11.529-.84-19.808 5.628S5.894 32.22 8.654 35.753zm1.178-.92c-.915-1.172-.515-3.472 1.229-6.366 1.836-3.048 4.952-6.413 8.766-9.393 3.814-2.98 7.833-5.19 11.235-6.234 3.23-.991 5.558-.823 6.473.348.916 1.172.516 3.471-1.228 6.366-1.836 3.048-4.952 6.413-8.766 9.393-3.814 2.98-7.833 5.19-11.235 6.233-3.23.992-5.558.824-6.474-.348z" fill="#fff"/><path d="M38.714 35.753c2.76-3.532-1.973-11.39-10.252-17.858-8.28-6.468-17.049-9.16-19.808-5.628-2.76 3.532 1.973 11.39 10.252 17.858 8.28 6.469 17.049 9.16 19.808 5.628zm-1.178-.92c-.916 1.17-3.244 1.339-6.474.347-3.402-1.044-7.42-3.254-11.235-6.233-3.814-2.98-6.93-6.345-8.766-9.393-1.744-2.895-2.144-5.194-1.229-6.366.916-1.171 3.243-1.34 6.474-.348 3.402 1.044 7.42 3.254 11.235 6.234 3.814 2.98 6.93 6.345 8.766 9.393 1.744 2.894 2.144 5.194 1.228 6.365z" fill="#fff"/><path d="M23.684 27.19a3.179 3.179 0 1 0 0-6.359 3.179 3.179 0 0 0 0 6.358z" fill="#fff"/></g><defs><clipPath id="clip0"><path fill="#fff" transform="translate(3)" d="M0 0H41.514V48H0z"/></clipPath></defs></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -0,0 +1 @@
<svg width="48" height="48" fill="none" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#clip0)"><path d="M24 28.631a4.278 4.278 0 1 0 0-8.556 4.278 4.278 0 0 0 0 8.556z" fill="#61DAFB"/><path d="M24 33.118c12.678 0 22.956-3.924 22.956-8.765 0-4.84-10.278-8.765-22.956-8.765-12.679 0-22.957 3.924-22.957 8.765 0 4.841 10.278 8.765 22.957 8.765z" stroke="#61DAFB"/><path d="M16.409 28.736c6.34 10.98 14.877 17.918 19.07 15.498 4.191-2.42 2.451-13.284-3.888-24.264C25.25 8.99 16.714 2.053 12.52 4.473 8.33 6.892 10.07 17.756 16.41 28.736z" stroke="#61DAFB"/><path d="M16.409 19.97c-6.34 10.98-8.08 21.843-3.887 24.264 4.192 2.42 12.73-4.518 19.069-15.498 6.34-10.98 8.08-21.843 3.887-24.264-4.192-2.42-12.73 4.519-19.069 15.498z" stroke="#61DAFB"/></g><defs><clipPath id="clip0"><path fill="#fff" transform="translate(0 3)" d="M0 0H48V42.706H0z"/></clipPath></defs></svg>

After

Width:  |  Height:  |  Size: 874 B

View File

@@ -0,0 +1,4 @@
<svg width="111" height="116" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 2l2-2h73c20 0 36 16 36 36v6l-2 2H89l-2-2v-6c0-7-5-12-12-12H25l-1 2v80l-2 1C10 106 0 96 0 84V2z" fill="#ED1846"/>
<path d="M45 48l-1 1c1 13 11 23 23 23h16c2 0 4 1 4 4v30l2 1c12-1 22-11 22-23v-8c0-16-12-28-28-28H45z" fill="#ED1846"/>
</svg>

After

Width:  |  Height:  |  Size: 332 B

View File

@@ -0,0 +1 @@
<svg width="50" height="50" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M25 49c13.255 0 24-10.745 24-24S38.255 1 25 1 1 11.745 1 25s10.745 24 24 24z" fill="#00838F" stroke="#00838F" stroke-width=".308"/><path fill-rule="evenodd" clip-rule="evenodd" d="M19.355 28.86l6.064-.508 1.14 2.633-3.913 3.882-3.29 4.626.433 5.617c-3.218-.786-5.361-1.56-6.43-2.324-1.068-.763-2.215-1.861-3.441-3.293l5.745-6.843h2.514l1.178-3.79z" fill="#FBB526"/><path fill-rule="evenodd" clip-rule="evenodd" d="M25.36 7.404a2.993 2.993 0 0 0-1.916 5.292v4.045h3.95v-4.15a2.993 2.993 0 0 0-2.035-5.187zm-1.318 2.992a1.317 1.317 0 1 1 2.634 0 1.317 1.317 0 0 1-2.634 0z" fill="#fff"/><path d="M27.373 37.265l-2.953 2.83 1.16 1.21 2.083-1.997 1.866.978 5.01.68.225-1.661-4.718-.64-2.673-1.4z" fill="#fff"/><path fill-rule="evenodd" clip-rule="evenodd" d="M2.736 25C2.736 12.704 12.704 2.736 25 2.736S47.264 12.704 47.264 25 37.296 47.264 25 47.264 2.736 37.296 2.736 25zM25 4.41C13.63 4.411 4.41 13.63 4.41 25a20.51 20.51 0 0 0 5.1 13.565l5.418-7.22h3.086l.255-2.69 3.259-.618v-9.62h-3.352V16.74h14.364v1.675H29.31V30.52l2.17.222 1.761 2.328h1.629l5.653 5.457A20.51 20.51 0 0 0 45.59 25c0-11.37-9.218-20.589-20.59-20.589zm7.43 30.364l-.023-.03h-2.293v-1.676h1.024l-.556-.735-4.404-.45-.974 2.587-2.52 1.545-.875-1.43 2.03-1.243 1.225-3.257.847.086-.694-1.129-5.398 1.024-.63 6.639-2.977 2.581-1.098-1.266 2.47-2.142.271-2.86h-2.088l-5.083 6.777A20.52 20.52 0 0 0 25 45.59a20.52 20.52 0 0 0 14.37-5.846l-5.178-4.998h-1.723l-.04.03zm-7.909-7.306l-1.556.296v-9.349h4.908v11.748l-1.834-2.983-.082.016v-3.993h-1.436v4.265z" fill="#fff"/></svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -0,0 +1 @@
<svg width="48" height="48" fill="none" xmlns="http://www.w3.org/2000/svg"><circle cx="24" cy="24" r="24" fill="#2A4660"/><g clip-path="url(#clip0)"><path d="M28.187 28.006h-7.993V36h7.993v-7.994zm-7.993-7.994H12.2v7.994h7.994v-7.994z" fill="#99E1F4"/><path d="M20.194 28.006H12.2V36h7.994v-7.994z" fill="#1A82E2"/><path d="M36.2 20.012h-7.994v7.994H36.2v-7.994zM28.187 12h-7.993v7.994h7.993V12z" fill="#00B2E3"/><path d="M20.194 20.012v7.994h8.012v-7.994h-8.012z" fill="#009DD9"/><path d="M36.2 12h-7.994v7.994H36.2V12z" fill="#1A82E2"/></g><defs><clipPath id="clip0"><path fill="#fff" transform="translate(12 12)" d="M0 0H24V24H0z"/></clipPath></defs></svg>

After

Width:  |  Height:  |  Size: 659 B

View File

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" fill="none">
<circle cx="24" cy="24" r="24" fill="#000"/>
<path fill="#fff" d="M20.27 29H32l-6.34 7H14l6.27-7zM40 21H15.45L9 27h24.55L40 21zM23.32 12H35l-6.3 7H17l6.32-7z"/>
</svg>

After

Width:  |  Height:  |  Size: 248 B

View File

@@ -0,0 +1,9 @@
<svg xmlns="http://www.w3.org/2000/svg" width="39" height="48" fill="none">
<mask id="a" width="39" height="48" x="0" y="0" maskUnits="userSpaceOnUse">
<path fill="#fff" d="M1.48 43.97L0 4.58A2.4 2.4 0 0 1 2.25 2.1L35.75 0a2.4 2.4 0 0 1 2.55 2.4v42.92a2.4 2.4 0 0 1-2.5 2.4L3.76 46.28a2.4 2.4 0 0 1-2.29-2.3z"/>
</mask>
<g mask="url(#a)">
<path fill="#FF4785" d="M1.47 43.97L-.01 4.58A2.4 2.4 0 0 1 2.24 2.1L35.74 0a2.4 2.4 0 0 1 2.55 2.4v42.92a2.4 2.4 0 0 1-2.5 2.4L3.75 46.28a2.4 2.4 0 0 1-2.3-2.3z"/>
<path fill="#fff" d="M28.26 5.87l.23-5.5L33.1 0l.2 5.68a.36.36 0 0 1-.58.29l-1.77-1.4-2.1 1.6a.36.36 0 0 1-.58-.3zm-5.88 12.12c0 .93 6.29.48 7.13-.17 0-6.36-3.41-9.7-9.66-9.7-6.24 0-9.74 3.4-9.74 8.48 0 8.86 11.96 9.03 11.96 13.87 0 1.35-.67 2.16-2.13 2.16-1.9 0-2.66-.97-2.57-4.28 0-.72-7.26-.94-7.48 0-.57 8.01 4.43 10.33 10.14 10.33 5.54 0 9.88-2.96 9.88-8.3 0-9.5-12.14-9.24-12.14-13.95 0-1.9 1.42-2.16 2.26-2.16.89 0 2.48.15 2.35 3.72z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 980 B

View File

@@ -0,0 +1 @@
<svg width="47" height="48" fill="none" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#clip0)"><path d="M39.792 6.09C35.507-.027 27.044-1.84 20.924 2.048L10.177 8.88a12.297 12.297 0 0 0-5.57 8.237 12.922 12.922 0 0 0 1.28 8.315 12.313 12.313 0 0 0-1.844 4.596c-.619 3.47.19 7.043 2.244 9.91 4.287 6.119 12.75 7.931 18.869 4.042l10.747-6.831a12.295 12.295 0 0 0 5.57-8.237 12.927 12.927 0 0 0-1.28-8.315A12.31 12.31 0 0 0 42.037 16c.619-3.47-.19-7.043-2.245-9.91" fill="#FF3E00"/><path d="M19.873 40.52a8.55 8.55 0 0 1-9.165-3.388 7.866 7.866 0 0 1-1.35-5.962c.062-.339.148-.674.257-1.001l.202-.616.55.404a13.881 13.881 0 0 0 4.206 2.095l.4.121-.037.398a2.4 2.4 0 0 0 .433 1.594 2.575 2.575 0 0 0 2.76 1.022 2.37 2.37 0 0 0 .66-.29l10.75-6.833a2.233 2.233 0 0 0 1.011-1.492 2.377 2.377 0 0 0-.407-1.797 2.577 2.577 0 0 0-2.76-1.022 2.37 2.37 0 0 0-.66.289L22.62 26.65c-.675.428-1.411.75-2.183.956a8.55 8.55 0 0 1-9.166-3.388 7.866 7.866 0 0 1-1.35-5.962 7.394 7.394 0 0 1 3.35-4.954l10.75-6.834a7.844 7.844 0 0 1 2.185-.957 8.55 8.55 0 0 1 9.165 3.388 7.866 7.866 0 0 1 1.35 5.962c-.062.34-.148.674-.256 1.001l-.203.616-.55-.403a13.87 13.87 0 0 0-4.206-2.096l-.4-.121.037-.398a2.404 2.404 0 0 0-.433-1.594 2.575 2.575 0 0 0-2.76-1.022 2.37 2.37 0 0 0-.66.29l-10.75 6.833a2.229 2.229 0 0 0-1.01 1.492c-.112.63.034 1.277.406 1.797a2.577 2.577 0 0 0 2.76 1.023c.234-.063.457-.16.661-.29l4.102-2.607a7.834 7.834 0 0 1 2.183-.957 8.55 8.55 0 0 1 9.165 3.388 7.865 7.865 0 0 1 1.35 5.962 7.398 7.398 0 0 1-3.35 4.955l-10.75 6.833a7.842 7.842 0 0 1-2.185.958" fill="#fff"/></g><defs><clipPath id="clip0"><path fill="#fff" transform="translate(3.84)" d="M0 0H38.4V46.08H0z"/></clipPath></defs></svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -0,0 +1 @@
<svg width="48" height="48" fill="none" xmlns="http://www.w3.org/2000/svg"><circle cx="24" cy="24" r="24" fill="#1CA1FA"/><path d="M19.77 16.09h-2.625v11.086c0 3.656 2.613 6.234 6.843 6.234 4.254 0 6.856-2.578 6.856-6.234V16.09h-2.625v10.875c0 2.414-1.535 4.113-4.23 4.113-2.684 0-4.22-1.7-4.22-4.113V16.09z" fill="#fff"/></svg>

After

Width:  |  Height:  |  Size: 328 B

View File

@@ -0,0 +1,4 @@
<svg width="48" height="48" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0 24C0 37.2548 10.7452 48 24 48C37.2548 48 48 37.2548 48 24C48 10.7452 37.2548 0 24 0C10.7452 0 0 10.7452 0 24Z" fill="#F7DF1E"/>
<path d="M27.6053 28.7181C28.5722 30.2968 29.8301 31.4571 32.0549 31.4571C33.9238 31.4571 35.1177 30.523 35.1177 29.2324C35.1177 27.6857 33.8911 27.1379 31.8339 26.2381L30.7063 25.7543C27.4514 24.3676 25.2891 22.6305 25.2891 18.9581C25.2891 15.5752 27.8667 13 31.8949 13C34.7627 13 36.8244 13.9981 38.3101 16.6114L34.7977 18.8667C34.0244 17.48 33.1901 16.9337 31.8949 16.9337C30.5737 16.9337 29.7364 17.7718 29.7364 18.8667C29.7364 20.2198 30.5745 20.7676 32.5097 21.6057L33.6373 22.0888C37.4697 23.7322 39.6335 25.4076 39.6335 29.1745C39.6335 33.2354 36.4434 35.4602 32.1592 35.4602C27.9703 35.4602 25.264 33.464 23.9398 30.8476L27.6053 28.7181ZM11.6716 29.109C12.3802 30.3661 13.0248 31.429 14.5745 31.429C16.0564 31.429 16.9912 30.8491 16.9912 28.5947V13.2575H21.5017V28.6556C21.5017 33.3261 18.7634 35.4518 14.7665 35.4518C11.155 35.4518 9.06362 33.5829 8 31.3318L11.6716 29.109Z" fill="black"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1 @@
<svg width="48" height="48" fill="none" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#clip0)"><path d="M29.54 3L24 12.7 18.456 3H-.001l24 42L47.998 3H29.54z" fill="#41B883"/><path d="M29.54 3L24 12.7 18.456 3H9.599l14.4 25.2L38.398 3H29.54z" fill="#34495E"/></g><defs><clipPath id="clip0"><path fill="#fff" transform="translate(0 3)" d="M0 0H48V42H0z"/></clipPath></defs></svg>

After

Width:  |  Height:  |  Size: 385 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

View File

@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" fill="none">
<circle cx="24" cy="24" r="24" fill="#191919"/>
<path fill="#fff" d="M17.65 33h12.7v-2.26H21v-.2l9.14-12.66V16.1h-12.2v2.26h8.9v.2l-9.18 12.66V33z"/>
</svg>

After

Width:  |  Height:  |  Size: 237 B

View File

@@ -0,0 +1,6 @@
{
"name": "@now/frameworks",
"version": "0.0.3",
"main": "frameworks.json",
"license": "UNLICENSED"
}

View File

@@ -1,6 +1,6 @@
{
"name": "@now/build-utils",
"version": "1.1.1",
"version": "1.3.2",
"license": "MIT",
"main": "./dist/index.js",
"types": "./dist/index.d.js",
@@ -32,9 +32,9 @@
"aggregate-error": "3.0.1",
"async-retry": "1.2.3",
"async-sema": "2.1.4",
"boxen": "4.2.0",
"cross-spawn": "6.0.5",
"end-of-stream": "1.4.1",
"execa": "^1.0.0",
"fs-extra": "7.0.0",
"glob": "7.1.3",
"into-stream": "5.0.0",

View File

@@ -10,26 +10,13 @@ interface ErrorResponse {
interface Options {
tag?: 'canary' | 'latest' | string;
functions?: BuilderFunctions;
}
const src = 'package.json';
const config: Config = { zeroConfig: true };
const MISSING_BUILD_SCRIPT_ERROR: ErrorResponse = {
code: 'missing_build_script',
message:
'Your `package.json` file is missing a `build` property inside the `scripts` property.' +
'\nMore details: https://zeit.co/docs/v2/platform/frequently-asked-questions#missing-build-script',
};
// Static builders are special cased in `@now/static-build`
function getBuilders({ tag }: Options = {}): Map<string, Builder> {
const withTag = tag ? `@${tag}` : '';
const config = { zeroConfig: true };
return new Map<string, Builder>([
['next', { src, use: `@now/next${withTag}`, config }],
]);
ignoreBuildScript?: boolean;
projectSettings?: {
framework?: string | null;
devCommand?: string | null;
buildCommand?: string | null;
outputDirectory?: string | null;
};
}
// Must be a function to ensure that the returned
@@ -47,11 +34,11 @@ function getApiBuilders({ tag }: Pick<Options, 'tag'> = {}): Builder[] {
];
}
function hasPublicDirectory(files: string[]) {
return files.some(name => name.startsWith('public/'));
function hasDirectory(name: string, files: string[]) {
return files.some(file => file.startsWith(`${name}/`));
}
function hasBuildScript(pkg: PackageJson | undefined) {
function hasBuildScript(pkg: PackageJson | undefined | null) {
const { scripts = {} } = pkg || {};
return Boolean(scripts && scripts['build']);
}
@@ -91,39 +78,81 @@ function getApiFunctionBuilder(
return use ? { use, src, config } : prevBuilder;
}
async function detectFrontBuilder(
pkg: PackageJson,
function detectFrontBuilder(
pkg: PackageJson | null | undefined,
builders: Builder[],
files: string[],
options: Options
): Promise<Builder> {
const { tag } = options;
): Builder {
const { tag, projectSettings = {} } = options;
const withTag = tag ? `@${tag}` : '';
for (const [dependency, builder] of getBuilders(options)) {
const deps = Object.assign({}, pkg.dependencies, pkg.devDependencies);
let { framework } = projectSettings;
// Return the builder when a dependency matches
if (deps[dependency]) {
if (options.functions) {
Object.entries(options.functions).forEach(([key, func]) => {
// When the builder is not used yet we'll use it for the frontend
if (
builders.every(
b => !(b.config && b.config.functions && b.config.functions[key])
)
) {
if (!builder.config) builder.config = {};
if (!builder.config.functions) builder.config.functions = {};
builder.config.functions[key] = { ...func };
}
});
}
const config: Config = {
zeroConfig: true,
};
return builder;
if (framework) {
config.framework = framework;
}
if (projectSettings.devCommand) {
config.devCommand = projectSettings.devCommand;
}
if (projectSettings.buildCommand) {
config.buildCommand = projectSettings.buildCommand;
}
if (projectSettings.outputDirectory) {
config.outputDirectory = projectSettings.outputDirectory;
}
if (pkg) {
const deps: PackageJson['dependencies'] = {
...pkg.dependencies,
...pkg.devDependencies,
};
if (deps['next']) {
framework = 'nextjs';
}
}
// By default we'll choose the `static-build` builder
return { src, use: `@now/static-build${withTag}`, config };
if (options.functions) {
Object.entries(options.functions).forEach(([key, func]) => {
// When the builder is not used yet we'll use it for the frontend
if (
builders.every(
b => !(b.config && b.config.functions && b.config.functions[key])
)
) {
if (!config.functions) config.functions = {};
config.functions[key] = { ...func };
}
});
}
if (framework === 'nextjs') {
return { src: 'package.json', use: `@now/next${withTag}`, config };
}
// Entrypoints for other frameworks
const entrypoints = new Set([
'package.json',
'config.yaml',
'config.toml',
'config.json',
'_config.yml',
'config.yml',
'config.rb',
]);
const source = pkg
? 'package.json'
: files.find(file => entrypoints.has(file)) || 'package.json';
return { src: source, use: `@now/static-build${withTag}`, config };
}
// Files that match a specific pattern will get ignored
@@ -139,10 +168,6 @@ export function getIgnoreApiFilter(optionsOrBuilders: Options | Builder[]) {
}
return (file: string) => {
if (!file.startsWith('api/')) {
return false;
}
if (file.includes('/.')) {
return false;
}
@@ -169,10 +194,7 @@ export function sortFiles(fileA: string, fileB: string) {
return fileA.localeCompare(fileB);
}
async function detectApiBuilders(
files: string[],
options: Options
): Promise<Builder[]> {
function detectApiBuilders(files: string[], options: Options): Builder[] {
const builds = files
.sort(sortFiles)
.filter(getIgnoreApiFilter(options))
@@ -188,10 +210,10 @@ async function detectApiBuilders(
// When a package has files that conflict with `/api` routes
// e.g. Next.js pages/api we'll check it here and return an error.
async function checkConflictingFiles(
function checkConflictingFiles(
files: string[],
builders: Builder[]
): Promise<ErrorResponse | null> {
): ErrorResponse | null {
// For Next.js
if (builders.some(b => b.use.startsWith('@now/next'))) {
const hasApiPages = files.some(file => file.startsWith('pages/api/'));
@@ -211,10 +233,10 @@ async function checkConflictingFiles(
// When e.g. Next.js receives a `functions` property it has to make sure,
// that it can handle those files, otherwise there are unused functions.
async function checkUnusedFunctionsOnFrontendBuilder(
function checkUnusedFunctionsOnFrontendBuilder(
files: string[],
builder: Builder
): Promise<ErrorResponse | null> {
): ErrorResponse | null {
const { config: { functions = undefined } = {} } = builder;
if (!functions) return null;
@@ -241,8 +263,6 @@ async function checkUnusedFunctionsOnFrontendBuilder(
}
function validateFunctions(files: string[], { functions = {} }: Options) {
const apiBuilders = getApiBuilders();
for (const [path, func] of Object.entries(functions)) {
if (path.length > 256) {
return {
@@ -312,15 +332,6 @@ function validateFunctions(files: string[], { functions = {} }: Options) {
'Function Runtimes must have a valid version, for example `now-php@1.0.0`.',
};
}
if (
apiBuilders.some(b => func.runtime && func.runtime.startsWith(b.use))
) {
return {
code: 'invalid_function_runtime',
message: `The function Runtime ${func.runtime} is not a Community Runtime and must not be specified.`,
};
}
}
if (func.includeFiles !== undefined) {
@@ -370,19 +381,21 @@ export async function detectBuilders(
}
// Detect all builders for the `api` directory before anything else
const builders = await detectApiBuilders(files, options);
const builders = detectApiBuilders(files, options);
const { projectSettings = {} } = options;
const { outputDirectory, buildCommand, framework } = projectSettings;
if (pkg && hasBuildScript(pkg)) {
const frontendBuilder = await detectFrontBuilder(pkg, builders, options);
if (hasBuildScript(pkg) || buildCommand || framework) {
const frontendBuilder = detectFrontBuilder(pkg, builders, files, options);
builders.push(frontendBuilder);
const conflictError = await checkConflictingFiles(files, builders);
const conflictError = checkConflictingFiles(files, builders);
if (conflictError) {
warnings.push(conflictError);
}
const unusedFunctionError = await checkUnusedFunctionsOnFrontendBuilder(
const unusedFunctionError = checkUnusedFunctionsOnFrontendBuilder(
files,
frontendBuilder
);
@@ -395,20 +408,30 @@ export async function detectBuilders(
};
}
} else {
if (pkg && builders.length === 0) {
if (!options.ignoreBuildScript && pkg && builders.length === 0) {
// We only show this error when there are no api builders
// since the dependencies of the pkg could be used for those
errors.push(MISSING_BUILD_SCRIPT_ERROR);
errors.push({
code: 'missing_build_script',
message:
'Your `package.json` file is missing a `build` property inside the `scripts` property.' +
'\nMore details: https://zeit.co/docs/v2/platform/frequently-asked-questions#missing-build-script',
});
return { errors, warnings, builders: null };
}
// We allow a `public` directory
// when there are no build steps
if (hasPublicDirectory(files)) {
const outDir = outputDirectory || 'public';
if (hasDirectory(outDir, files)) {
builders.push({
use: '@now/static',
src: 'public/**/*',
config,
src: `${outDir}/**/*`,
config: {
zeroConfig: true,
outputDirectory: outDir,
},
});
} else if (
builders.length > 0 &&
@@ -419,7 +442,9 @@ export async function detectBuilders(
builders.push({
use: '@now/static',
src: '!{api/**,package.json}',
config,
config: {
zeroConfig: true,
},
});
}
}

View File

@@ -0,0 +1,81 @@
import { Framework, FrameworkDetectionItem } from '@now/frameworks';
import { DetectorFilesystem } from './detectors/filesystem';
export interface DetectFrameworkOptions {
fs: DetectorFilesystem;
frameworkList: Framework[];
}
async function matches(fs: DetectorFilesystem, framework: Framework) {
const { detectors } = framework;
if (!detectors) {
return false;
}
const { every, some } = detectors;
if (every !== undefined && !Array.isArray(every)) {
return false;
}
if (some !== undefined && !Array.isArray(some)) {
return false;
}
const check = async ({ file, matchContent }: FrameworkDetectionItem) => {
if (!file) {
return false;
}
if ((await fs.exists(file)) === false) {
return false;
}
if (matchContent) {
const regex = new RegExp(matchContent, 'gm');
const content = await fs.readFile(file);
if (!regex.test(content.toString())) {
return false;
}
}
return true;
};
const result: boolean[] = [];
if (every) {
const everyResult = await Promise.all(every.map(item => check(item)));
result.push(...everyResult);
}
if (some) {
let someResult = false;
for (const item of some) {
if (await check(item)) {
someResult = true;
break;
}
}
result.push(someResult);
}
return result.every(res => res === true);
}
export async function detectFramework({
fs,
frameworkList,
}: DetectFrameworkOptions): Promise<string | null> {
for (const framework of frameworkList) {
if (await matches(fs, framework)) {
return framework.slug;
}
}
return null;
}

View File

@@ -1,5 +1,6 @@
import { parse as parsePath } from 'path';
import { Route, Builder } from './types';
import { Route, Source } from '@now/routing-utils';
import { Builder } from './types';
import { getIgnoreApiFilter, sortFiles } from './detect-builders';
function escapeName(name: string) {
@@ -40,20 +41,26 @@ function getSegmentName(segment: string): string | null {
return null;
}
function createRouteFromPath(filePath: string): Route {
function createRouteFromPath(
filePath: string,
featHandleMiss: boolean,
cleanUrls: boolean
): { route: Source; isDynamic: boolean } {
const parts = filePath.split('/');
let counter = 1;
const query: string[] = [];
let isDynamic = false;
const srcParts = parts.map((segment, index): string => {
const srcParts = parts.map((segment, i): string => {
const name = getSegmentName(segment);
const isLast = index === parts.length - 1;
const isLast = i === parts.length - 1;
if (name !== null) {
// We can't use `URLSearchParams` because `$` would get escaped
query.push(`${name}=$${counter++}`);
return `([^\\/]+)`;
isDynamic = true;
return `([^/]+)`;
} else if (isLast) {
const { name: fileName, ext } = parsePath(segment);
const isIndex = fileName === 'index';
@@ -62,27 +69,43 @@ function createRouteFromPath(filePath: string): Route {
const names = [
isIndex ? prefix : `${fileName}\\/`,
prefix + escapeName(fileName),
prefix + escapeName(fileName) + escapeName(ext),
featHandleMiss && cleanUrls
? ''
: prefix + escapeName(fileName) + escapeName(ext),
].filter(Boolean);
// Either filename with extension, filename without extension
// or nothing when the filename is `index`
// or nothing when the filename is `index`.
// When `cleanUrls: true` then do *not* add the filename with extension.
return `(${names.join('|')})${isIndex ? '?' : ''}`;
}
return segment;
});
const { name: fileName } = parsePath(filePath);
const { name: fileName, ext } = parsePath(filePath);
const isIndex = fileName === 'index';
const queryString = `${query.length ? '?' : ''}${query.join('&')}`;
const src = isIndex
? `^/${srcParts.slice(0, -1).join('/')}${srcParts.slice(-1)[0]}$`
: `^/${srcParts.join('/')}$`;
const dest = `/${filePath}${query.length ? '?' : ''}${query.join('&')}`;
return { src, dest };
let route: Source;
if (featHandleMiss) {
const extensionless = ext ? filePath.slice(0, -ext.length) : filePath;
route = {
src,
dest: `/${extensionless}${queryString}`,
check: true,
};
} else {
route = {
src,
dest: `/${filePath}${queryString}`,
};
}
return { route, isDynamic };
}
// Check if the path partially matches and has the same
@@ -192,17 +215,30 @@ function sortFilesBySegmentCount(fileA: string, fileB: string): number {
return 0;
}
interface ApiRoutesResult {
defaultRoutes: Source[] | null;
dynamicRoutes: Source[] | null;
error: { [key: string]: string } | null;
}
interface RoutesResult {
defaultRoutes: Route[] | null;
redirectRoutes: Route[] | null;
error: { [key: string]: string } | null;
}
async function detectApiRoutes(
files: string[],
builders: Builder[]
): Promise<RoutesResult> {
builders: Builder[],
featHandleMiss: boolean,
cleanUrls: boolean
): Promise<ApiRoutesResult> {
if (!files || files.length === 0) {
return { defaultRoutes: null, error: null };
return {
defaultRoutes: null,
dynamicRoutes: null,
error: null,
};
}
// The deepest routes need to be
@@ -212,12 +248,16 @@ async function detectApiRoutes(
.sort(sortFiles)
.sort(sortFilesBySegmentCount);
const defaultRoutes: Route[] = [];
const defaultRoutes: Source[] = [];
const dynamicRoutes: Source[] = [];
for (const file of sortedFiles) {
// We only consider every file in the api directory
// as we will strip extensions as well as resolving "[segments]"
if (!file.startsWith('api/')) {
if (
!file.startsWith('api/') &&
!builders.some(b => b.src === file && b.config && b.config.functions)
) {
continue;
}
@@ -226,6 +266,7 @@ async function detectApiRoutes(
if (conflictingSegment) {
return {
defaultRoutes: null,
dynamicRoutes: null,
error: {
code: 'conflicting_path_segment',
message:
@@ -247,6 +288,7 @@ async function detectApiRoutes(
return {
defaultRoutes: null,
dynamicRoutes: null,
error: {
code: 'conflicting_file_path',
message:
@@ -257,42 +299,113 @@ async function detectApiRoutes(
};
}
defaultRoutes.push(createRouteFromPath(file));
const out = createRouteFromPath(file, featHandleMiss, cleanUrls);
if (out.isDynamic) {
dynamicRoutes.push(out.route);
}
defaultRoutes.push(out.route);
}
// 404 Route to disable directory listing
if (defaultRoutes.length) {
defaultRoutes.push({
status: 404,
src: '/api(\\/.*)?$',
});
}
return { defaultRoutes, error: null };
return { defaultRoutes, dynamicRoutes, error: null };
}
function hasPublicBuilder(builders: Builder[]): boolean {
return builders.some(
function getPublicBuilder(builders: Builder[]): Builder | null {
const builder = builders.find(
builder =>
builder.use === '@now/static' &&
builder.src === 'public/**/*' &&
/^.*\/\*\*\/\*$/.test(builder.src) &&
builder.config &&
builder.config.zeroConfig === true
);
return builder || null;
}
export function detectOutputDirectory(builders: Builder[]): string | null {
// TODO: We eventually want to save the output directory to
// builder.config.outputDirectory so it is only detected once
const publicBuilder = getPublicBuilder(builders);
return publicBuilder ? publicBuilder.src.replace('/**/*', '') : null;
}
export async function detectRoutes(
files: string[],
builders: Builder[]
builders: Builder[],
featHandleMiss = false,
cleanUrls = false,
trailingSlash?: boolean
): Promise<RoutesResult> {
const routesResult = await detectApiRoutes(files, builders);
const result = await detectApiRoutes(
files,
builders,
featHandleMiss,
cleanUrls
);
const { dynamicRoutes, defaultRoutes: allRoutes, error } = result;
if (error) {
return { defaultRoutes: null, redirectRoutes: null, error };
}
const directory = detectOutputDirectory(builders);
const defaultRoutes: Route[] = [];
const redirectRoutes: Route[] = [];
if (allRoutes && allRoutes.length > 0) {
const hasApiRoutes = allRoutes.some(
r => r.dest && r.dest.startsWith('/api/')
);
if (featHandleMiss) {
defaultRoutes.push({ handle: 'miss' });
if (cleanUrls) {
const extensions = builders
.map(b => parsePath(b.src).ext)
.filter(Boolean);
if (extensions.length > 0) {
const exts = extensions.map(ext => ext.slice(1)).join('|');
const group = `(?:\\.(?:${exts}))`;
redirectRoutes.push({
src: `^/(api(?:.+)?)/index${group}?/?$`,
headers: { Location: trailingSlash ? '/$1/' : '/$1' },
status: 308,
});
redirectRoutes.push({
src: `^/api/(.+)${group}/?$`,
headers: { Location: trailingSlash ? '/api/$1/' : '/api/$1' },
status: 308,
});
}
} else {
defaultRoutes.push({
src: '^/api/(.+)\\.\\w+$',
dest: '/api/$1',
check: true,
});
}
if (dynamicRoutes) {
defaultRoutes.push(...dynamicRoutes);
}
if (hasApiRoutes) {
defaultRoutes.push({
src: '^/api(/.*)?$',
status: 404,
continue: true,
});
}
} else {
defaultRoutes.push(...allRoutes);
if (hasApiRoutes) {
defaultRoutes.push({
status: 404,
src: '^/api(/.*)?$',
});
}
}
}
if (routesResult.defaultRoutes && hasPublicBuilder(builders)) {
routesResult.defaultRoutes.push({
if (!featHandleMiss && directory) {
defaultRoutes.push({
src: '/(.*)',
dest: '/public/$1',
dest: `/${directory}/$1`,
});
}
return routesResult;
return { defaultRoutes, redirectRoutes, error };
}

View File

@@ -1,23 +0,0 @@
import { DetectorParameters, DetectorResult } from '../types';
export default async function detectAngular({
fs: { hasDependency },
}: DetectorParameters): Promise<DetectorResult> {
const hasAngular = await hasDependency('@angular/cli');
if (!hasAngular) return false;
return {
buildCommand: 'ng build',
buildDirectory: 'dist',
devCommand: 'ng serve --port $PORT',
minNodeRange: '10.x',
routes: [
{
handle: 'filesystem',
},
{
src: '/(.*)',
dest: '/index.html',
},
],
};
}

View File

@@ -1,17 +0,0 @@
import { DetectorParameters, DetectorResult } from '../types';
export default async function detectBrunch({
fs: { hasDependency, exists },
}: DetectorParameters): Promise<DetectorResult> {
const hasBrunch = await hasDependency('brunch');
if (!hasBrunch) return false;
const hasConfig = await exists('brunch-config.js');
if (!hasConfig) return false;
return {
buildCommand: 'brunch build --production',
buildDirectory: 'public',
devCommand: 'brunch watch --server --port $PORT',
};
}

View File

@@ -1,40 +0,0 @@
import { DetectorParameters, DetectorResult } from '../types';
export default async function detectCreateReactAppEjected({
fs: { hasDependency },
}: DetectorParameters): Promise<DetectorResult> {
const hasReactDevUtils = await hasDependency('react-dev-utils');
if (!hasReactDevUtils) {
return false;
}
return {
buildCommand: 'node scripts/build.js',
buildDirectory: 'build',
devCommand: 'node scripts/start.js',
devVariables: { BROWSER: 'none' },
routes: [
{
src: '/static/(.*)',
headers: { 'cache-control': 's-maxage=31536000, immutable' },
continue: true,
},
{
src: '/service-worker.js',
headers: { 'cache-control': 's-maxage=0' },
continue: true,
},
{
src: '/sockjs-node/(.*)',
dest: '/sockjs-node/$1',
},
{
handle: 'filesystem',
},
{
src: '/(.*)',
headers: { 'cache-control': 's-maxage=0' },
dest: '/index.html',
},
],
};
}

View File

@@ -1,40 +0,0 @@
import { DetectorParameters, DetectorResult } from '../types';
export default async function detectCreateReactApp({
fs: { hasDependency },
}: DetectorParameters): Promise<DetectorResult> {
const hasReactScripts = await hasDependency('react-scripts');
if (!hasReactScripts) {
return false;
}
return {
buildCommand: 'react-scripts build',
buildDirectory: 'build',
devCommand: 'react-scripts start',
devVariables: { BROWSER: 'none' },
routes: [
{
src: '/static/(.*)',
headers: { 'cache-control': 's-maxage=31536000, immutable' },
continue: true,
},
{
src: '/service-worker.js',
headers: { 'cache-control': 's-maxage=0' },
continue: true,
},
{
src: '/sockjs-node/(.*)',
dest: '/sockjs-node/$1',
},
{
handle: 'filesystem',
},
{
src: '/(.*)',
headers: { 'cache-control': 's-maxage=0' },
dest: '/index.html',
},
],
};
}

View File

@@ -1,13 +0,0 @@
import { DetectorParameters, DetectorResult } from '../types';
export default async function detectDocusaurus({
fs: { hasDependency },
}: DetectorParameters): Promise<DetectorResult> {
const hasDocusaurus = await hasDependency('docusaurus');
if (!hasDocusaurus) return false;
return {
buildCommand: 'docusaurus-build',
buildDirectory: 'build',
devCommand: 'docusaurus-start --port $PORT',
};
}

View File

@@ -1,13 +0,0 @@
import { DetectorParameters, DetectorResult } from '../types';
export default async function detectEleventy({
fs: { hasDependency },
}: DetectorParameters): Promise<DetectorResult> {
const hasEleventy = await hasDependency('@11ty/eleventy');
if (!hasEleventy) return false;
return {
buildCommand: 'npx @11ty/eleventy',
buildDirectory: '_site',
devCommand: 'npx @11ty/eleventy --serve --watch --port $PORT',
};
}

View File

@@ -1,22 +0,0 @@
import { DetectorParameters, DetectorResult } from '../types';
export default async function detectEmber({
fs: { hasDependency },
}: DetectorParameters): Promise<DetectorResult> {
const hasEmber = await hasDependency('ember-cli');
if (!hasEmber) return false;
return {
buildCommand: 'ember build',
buildDirectory: 'dist',
devCommand: 'ember serve --port $PORT',
routes: [
{
handle: 'filesystem',
},
{
src: '/(.*)',
dest: '/index.html',
},
],
};
}

View File

@@ -1,7 +1,3 @@
import yaml from 'js-yaml';
import toml from '@iarna/toml';
import { PackageJson } from '../types';
/**
* `DetectorFilesystem` is an abstract class that represents a virtual filesystem
* to perform read-only operations on in order to detect which framework is being
@@ -27,18 +23,16 @@ import { PackageJson } from '../types';
* functions. The easiest way to do this is to use the `=` syntax when defining
* methods in this class definition.
*/
export default abstract class DetectorFilesystem {
export abstract class DetectorFilesystem {
protected abstract _readFile(name: string): Promise<Buffer>;
protected abstract _exists(name: string): Promise<boolean>;
private existsCache: Map<string, Promise<boolean>>;
private readFileCache: Map<string, Promise<Buffer>>;
private readJsonCache: Map<string, Promise<any>>;
constructor() {
this.existsCache = new Map();
this.readFileCache = new Map();
this.readJsonCache = new Map();
}
public exists = async (name: string): Promise<boolean> => {
@@ -58,59 +52,4 @@ export default abstract class DetectorFilesystem {
}
return p;
};
public readJson = async <T>(name: string): Promise<T> => {
let p = this.readJsonCache.get(name);
if (!p) {
p = this.readFile(name).then(d => JSON.parse(d.toString('utf8')));
this.readJsonCache.set(name, p);
}
return p;
};
public readFileOrNull = async (name: string): Promise<Buffer | null> => {
return nullEnoent(this.readFile(name));
};
public readJsonOrNull = async <T>(name: string): Promise<T | null> => {
return nullEnoent(this.readJson<T>(name));
};
public readPackageJson = async (): Promise<PackageJson | null> => {
return await this.readJsonOrNull<PackageJson>('package.json');
};
public readConfigFile = async <T>(...names: string[]): Promise<T | null> => {
for (const name of names) {
const data = await this.readFileOrNull(name);
if (data) {
const str = data.toString('utf8');
if (name.endsWith('.json')) {
return JSON.parse(str);
} else if (name.endsWith('.toml')) {
return (toml.parse(str) as unknown) as T;
} else if (name.endsWith('.yaml') || name.endsWith('.yml')) {
return yaml.safeLoad(str, { filename: name });
}
}
}
return null;
};
public hasDependency = async (name: string): Promise<boolean> => {
const pkg = await this.readPackageJson();
const { dependencies = {}, devDependencies = {} } = pkg || {};
return name in dependencies || name in devDependencies;
};
}
async function nullEnoent<T>(p: Promise<T>): Promise<T | null> {
try {
return await p;
} catch (err) {
if (err.code === 'ENOENT') {
return null;
}
throw err;
}
}

View File

@@ -1,16 +0,0 @@
import { DetectorParameters, DetectorResult } from '../types';
export default async function detectGatsby({
fs: { hasDependency },
}: DetectorParameters): Promise<DetectorResult> {
const hasGatsby = await hasDependency('gatsby');
if (!hasGatsby) {
return false;
}
return {
buildCommand: 'gatsby build',
buildDirectory: 'public',
devCommand: 'gatsby develop -p $PORT',
cachePattern: '.cache/**',
};
}

View File

@@ -1,15 +0,0 @@
import { DetectorParameters, DetectorResult } from '../types';
export default async function detectGridsome({
fs: { hasDependency },
}: DetectorParameters): Promise<DetectorResult> {
const hasGridsome = await hasDependency('gridsome');
if (!hasGridsome) {
return false;
}
return {
buildCommand: 'gridsome build',
buildDirectory: 'dist',
devCommand: 'gridsome develop -p $PORT',
};
}

View File

@@ -1,13 +0,0 @@
import { DetectorParameters, DetectorResult } from '../types';
export default async function detectHexo({
fs: { hasDependency },
}: DetectorParameters): Promise<DetectorResult> {
const hasHexo = await hasDependency('hexo');
if (!hasHexo) return false;
return {
buildCommand: 'hexo generate',
buildDirectory: 'public',
devCommand: 'hexo server --port $PORT',
};
}

View File

@@ -1,26 +0,0 @@
import { DetectorParameters, DetectorResult } from '../types';
/**
* https://gohugo.io/getting-started/configuration/#configuration-file
*/
interface HugoConfig {
publishDir?: string;
}
export default async function detectHugo({
fs: { readConfigFile },
}: DetectorParameters): Promise<DetectorResult> {
const config = await readConfigFile<HugoConfig>(
'config.toml',
'config.yaml',
'config.json'
);
if (!config) {
return false;
}
return {
buildCommand: 'hugo',
buildDirectory: config.publishDir || 'public',
devCommand: 'hugo server -D -w -p $PORT',
};
}

View File

@@ -1,85 +0,0 @@
import AggregateError from 'aggregate-error';
import { Detector, DetectorParameters, DetectorResult } from '../types';
import angular from './angular';
import brunch from './brunch';
import createReactApp from './create-react-app';
import createReactAppEjected from './create-react-app-ejected';
import docusaurus from './docusaurus';
import eleventy from './eleventy';
import ember from './ember';
import gatsby from './gatsby';
import gridsome from './gridsome';
import hexo from './hexo';
import hugo from './hugo';
import jekyll from './jekyll';
import middleman from './middleman';
import next from './next';
import polymer from './polymer';
import preact from './preact';
import saber from './saber';
import sapper from './sapper';
import stencil from './stencil';
import svelte from './svelte';
import umi from './umi';
import vue from './vue';
export const pkgDetectors: Detector[] = [
angular,
brunch,
createReactApp,
createReactAppEjected,
docusaurus,
eleventy,
ember,
gatsby,
gridsome,
hexo,
next,
polymer,
preact,
saber,
sapper,
stencil,
svelte,
umi,
vue,
];
export const detectors: Detector[] = [hugo, jekyll, middleman];
export function firstTruthy<T>(promises: Promise<T>[]) {
return new Promise<T>((resolve, reject) => {
const errors: Array<Error> = [];
let unresolved = promises.length;
for (const p of promises) {
p.then(v => {
if (v || --unresolved === 0) {
resolve(v);
}
}).catch(err => {
errors.push(err);
if (--unresolved === 0) {
reject(new AggregateError(errors));
}
});
}
});
}
export async function detectDefaults(
params: DetectorParameters
): Promise<DetectorResult> {
// The `package.json` detectors are run first, since they share the common
// file read of `package.json` and are the most popular frameworks
let d: Detector[] = params.pkgDetectors || pkgDetectors;
let result: DetectorResult = await firstTruthy(
d.map(detector => detector(params))
);
if (!result) {
// If no `package.json` framework was detected then check the non-pkg ones
d = params.detectors || detectors;
result = await firstTruthy(d.map(detector => detector(params)));
}
return result;
}

View File

@@ -1,22 +0,0 @@
import { DetectorParameters, DetectorResult } from '../types';
/**
* https://jekyllrb.com/docs/configuration/options/
*/
interface JekyllConfig {
destination?: string;
}
export default async function detectJekyll({
fs: { readConfigFile },
}: DetectorParameters): Promise<DetectorResult> {
const config = await readConfigFile<JekyllConfig>('_config.yml');
if (!config) {
return false;
}
return {
buildCommand: 'jekyll build',
buildDirectory: config.destination || '_site',
devCommand: 'bundle exec jekyll serve --watch --port $PORT',
};
}

View File

@@ -1,14 +0,0 @@
import { DetectorParameters, DetectorResult } from '../types';
export default async function detectMiddleman({
fs: { exists },
}: DetectorParameters): Promise<DetectorResult> {
const hasConfig = await exists('config.rb');
if (!hasConfig) return false;
return {
buildCommand: 'bundle exec middleman build',
buildDirectory: 'build',
devCommand: 'bundle exec middleman server -p $PORT',
};
}

View File

@@ -1,13 +0,0 @@
import { DetectorParameters, DetectorResult } from '../types';
export default async function detectNext({
fs: { hasDependency },
}: DetectorParameters): Promise<DetectorResult> {
const hasNext = await hasDependency('next');
if (!hasNext) return false;
return {
buildCommand: 'next build',
buildDirectory: 'build',
devCommand: 'next -p $PORT',
};
}

View File

@@ -1,22 +0,0 @@
import { DetectorParameters, DetectorResult } from '../types';
export default async function detectPolymer({
fs: { hasDependency },
}: DetectorParameters): Promise<DetectorResult> {
const hasPolymer = await hasDependency('polymer-cli');
if (!hasPolymer) return false;
return {
buildCommand: 'polymer build',
buildDirectory: 'build',
devCommand: 'polymer serve --port $PORT',
routes: [
{
handle: 'filesystem',
},
{
src: '/(.*)',
dest: '/index.html',
},
],
};
}

View File

@@ -1,22 +0,0 @@
import { DetectorParameters, DetectorResult } from '../types';
export default async function detectPreact({
fs: { hasDependency },
}: DetectorParameters): Promise<DetectorResult> {
const hasPreact = await hasDependency('preact-cli');
if (!hasPreact) return false;
return {
buildCommand: 'preact build',
buildDirectory: 'build',
devCommand: 'preact watch --port $PORT',
routes: [
{
handle: 'filesystem',
},
{
src: '/(.*)',
dest: '/index.html',
},
],
};
}

View File

@@ -1,27 +0,0 @@
import { DetectorParameters, DetectorResult } from '../types';
export default async function detectSaber({
fs: { hasDependency },
}: DetectorParameters): Promise<DetectorResult> {
const hasSaber = await hasDependency('saber');
if (!hasSaber) return false;
return {
buildCommand: 'saber build',
buildDirectory: 'public',
devCommand: 'saber --port $PORT',
routes: [
{
src: '/_saber/.*',
headers: { 'cache-control': 'max-age=31536000, immutable' },
},
{
handle: 'filesystem',
},
{
src: '.*',
status: 404,
dest: '404.html',
},
],
};
}

View File

@@ -1,13 +0,0 @@
import { DetectorParameters, DetectorResult } from '../types';
export default async function detectSapper({
fs: { hasDependency },
}: DetectorParameters): Promise<DetectorResult> {
const hasSapper = await hasDependency('sapper');
if (!hasSapper) return false;
return {
buildCommand: 'sapper export',
buildDirectory: '__sapper__/export',
devCommand: 'sapper dev --port $PORT',
};
}

View File

@@ -1,22 +0,0 @@
import { DetectorParameters, DetectorResult } from '../types';
export default async function detectStencil({
fs: { hasDependency },
}: DetectorParameters): Promise<DetectorResult> {
const hasStencil = await hasDependency('@stencil/core');
if (!hasStencil) return false;
return {
buildCommand: 'stencil build',
buildDirectory: 'www',
devCommand: 'stencil build --dev --watch --serve --port $PORT',
routes: [
{
handle: 'filesystem',
},
{
src: '/(.*)',
dest: '/index.html',
},
],
};
}

View File

@@ -1,22 +0,0 @@
import { DetectorParameters, DetectorResult } from '../types';
export default async function detectSvelte({
fs: { hasDependency },
}: DetectorParameters): Promise<DetectorResult> {
const hasSvelte = await hasDependency('sirv-cli');
if (!hasSvelte) return false;
return {
buildCommand: 'rollup -c',
buildDirectory: 'public',
devCommand: 'sirv public --single --dev --port $PORT',
routes: [
{
handle: 'filesystem',
},
{
src: '/(.*)',
dest: '/index.html',
},
],
};
}

View File

@@ -1,22 +0,0 @@
import { DetectorParameters, DetectorResult } from '../types';
export default async function detectUmiJS({
fs: { hasDependency },
}: DetectorParameters): Promise<DetectorResult> {
const hasUmi = await hasDependency('umi');
if (!hasUmi) return false;
return {
buildCommand: 'umi build',
buildDirectory: 'dist',
devCommand: 'umi dev --port $PORT',
routes: [
{
handle: 'filesystem',
},
{
src: '/(.*)',
dest: '/index.html',
},
],
};
}

View File

@@ -1,32 +0,0 @@
import { DetectorParameters, DetectorResult } from '../types';
export default async function detectVue({
fs: { hasDependency },
}: DetectorParameters): Promise<DetectorResult> {
const hasVue = await hasDependency('@vue/cli-service');
if (!hasVue) return false;
return {
buildCommand: 'vue-cli-service build',
buildDirectory: 'dist',
devCommand: 'vue-cli-service serve --port $PORT',
routes: [
{
src: '^/[^/]*\\.(js|txt|ico|json)',
headers: { 'cache-control': 'max-age=300' },
continue: true,
},
{
src: '^/(img|js|css|fonts|media)/.*',
headers: { 'cache-control': 'max-age=31536000, immutable' },
continue: true,
},
{
handle: 'filesystem',
},
{
src: '^.*',
dest: '/index.html',
},
],
};
}

View File

@@ -0,0 +1,18 @@
/**
* This error should be thrown from a Builder in
* order to stop the build and print a message.
* This is necessary to avoid printing a stack trace.
*/
export class NowBuildError extends Error {
public code: string;
constructor({ message, code }: Props) {
super(message);
this.code = code;
}
}
interface Props {
message: string;
code: string;
}

View File

@@ -1,4 +1,5 @@
import path from 'path';
import debug from '../debug';
import FileFsRef from '../file-fs-ref';
import { File, Files, Meta } from '../types';
import { remove, mkdirp, readlink, symlink } from 'fs-extra';
@@ -39,8 +40,12 @@ export default async function download(
basePath: string,
meta?: Meta
): Promise<DownloadedFiles> {
const { isDev = false, skipDownload = false, filesChanged = null, filesRemoved = null } =
meta || {};
const {
isDev = false,
skipDownload = false,
filesChanged = null,
filesRemoved = null,
} = meta || {};
if (isDev || skipDownload) {
// In `now dev`, the `download()` function is a no-op because
@@ -48,11 +53,14 @@ export default async function download(
// source files are already available.
return files as DownloadedFiles;
}
debug('Downloading deployment source files...');
const start = Date.now();
const files2: DownloadedFiles = {};
const filenames = Object.keys(files);
await Promise.all(
Object.keys(files).map(async name => {
filenames.map(async name => {
// If the file does not exist anymore, remove it.
if (Array.isArray(filesRemoved) && filesRemoved.includes(name)) {
await removeFile(basePath, name);
@@ -71,5 +79,8 @@ export default async function download(
})
);
const duration = Date.now() - start;
debug(`Downloaded ${filenames.length} source files: ${duration}ms`);
return files2;
}

View File

@@ -1,56 +1,104 @@
import { intersects } from 'semver';
import boxen from 'boxen';
import { NodeVersion } from '../types';
import { NowBuildError } from '../errors';
import debug from '../debug';
const supportedOptions: NodeVersion[] = [
const allOptions: NodeVersion[] = [
{ major: 12, range: '12.x', runtime: 'nodejs12.x' },
{ major: 10, range: '10.x', runtime: 'nodejs10.x' },
{ major: 8, range: '8.10.x', runtime: 'nodejs8.10' },
{
major: 8,
range: '8.10.x',
runtime: 'nodejs8.10',
discontinueDate: new Date('2020-01-06'),
},
];
// This version should match Fargate's default in the PATH
// Today that is Node 8
export const defaultSelection = supportedOptions.find(
o => o.major === 8
) as NodeVersion;
const pleaseSet =
'Please set "engines": { "node": "' +
getLatestNodeVersion().range +
'" } in your `package.json` file to upgrade to Node.js ' +
getLatestNodeVersion().major;
const upstreamProvider =
'This change is the result of a decision made by an upstream infrastructure provider (AWS).' +
'\nRead more: https://docs.aws.amazon.com/lambda/latest/dg/runtime-support-policy.html';
export function getOldestNodeVersion(): NodeVersion {
return allOptions[allOptions.length - 1];
}
export function getLatestNodeVersion(): NodeVersion {
return allOptions[0];
}
export async function getSupportedNodeVersion(
engineRange?: string,
silent?: boolean
isAuto?: boolean
): Promise<NodeVersion> {
let selection = defaultSelection;
let selection = getOldestNodeVersion();
if (!engineRange) {
if (!silent) {
debug(
'Missing `engines` in `package.json`, using default range: ' +
selection.range
);
}
} else {
const found = supportedOptions.some(o => {
if (engineRange) {
const found = allOptions.some(o => {
// the array is already in order so return the first
// match which will be the newest version of node
selection = o;
return intersects(o.range, engineRange);
});
if (found) {
if (!silent) {
debug(
'Found `engines` in `package.json`, selecting range: ' +
selection.range
);
}
} else {
if (!silent) {
throw new Error(
'Found `engines` in `package.json` with an unsupported node range: ' +
engineRange +
'\nPlease use one of the following supported ranges: ' +
JSON.stringify(supportedOptions.map(o => o.range))
);
}
if (!found) {
const intro =
isAuto || !engineRange
? 'This project is using an invalid version of Node.js and must be changed.'
: 'Found `engines` in `package.json` with an invalid Node.js version range: ' +
engineRange;
throw new NowBuildError({
code: 'NOW_BUILD_UTILS_NODE_VERSION_INVALID',
message: intro + '\n' + pleaseSet,
});
}
}
if (isDiscontinued(selection)) {
const intro =
isAuto || !engineRange
? 'This project is using a discontinued version of Node.js and must be upgraded.'
: 'Found `engines` in `package.json` with a discontinued Node.js version range: ' +
engineRange;
throw new NowBuildError({
code: 'NOW_BUILD_UTILS_NODE_VERSION_DISCONTINUED',
message: intro + '\n' + pleaseSet + '\n' + upstreamProvider,
});
}
debug(
isAuto || !engineRange
? 'Using default Node.js range: ' + selection.range
: (engineRange ? 'Found' : 'Missing') +
' `engines` in `package.json`, selecting range: ' +
selection.range
);
if (selection.discontinueDate) {
const d = selection.discontinueDate.toISOString().split('T')[0];
console.warn(
boxen(
'NOTICE' +
'\n' +
`\nNode.js version ${selection.range} has reached end-of-life.` +
`\nAs a result, deployments created on or after ${d} will fail to build.` +
'\n' +
pleaseSet +
'\n' +
upstreamProvider,
{ padding: 1 }
)
);
}
return selection;
}
function isDiscontinued({ discontinueDate }: NodeVersion): boolean {
const today = Date.now();
return discontinueDate !== undefined && discontinueDate.getTime() <= today;
}

View File

@@ -0,0 +1,37 @@
import yaml from 'js-yaml';
import toml from '@iarna/toml';
import { readFile } from 'fs-extra';
async function readFileOrNull(file: string) {
try {
const data = await readFile(file);
return data;
} catch (err) {
if (err.code !== 'ENOENT') {
throw err;
}
}
return null;
}
export async function readConfigFile<T>(files: string | string[]) {
files = Array.isArray(files) ? files : [files];
for (const name of files) {
const data = await readFileOrNull(name);
if (data) {
const str = data.toString('utf8');
if (name.endsWith('.json')) {
return JSON.parse(str);
} else if (name.endsWith('.toml')) {
return (toml.parse(str) as unknown) as T;
} else if (name.endsWith('.yaml') || name.endsWith('.yml')) {
return yaml.safeLoad(str, { filename: name });
}
}
}
return null;
}

View File

@@ -7,7 +7,7 @@ import { SpawnOptions } from 'child_process';
import { deprecate } from 'util';
import { cpus } from 'os';
import { Meta, PackageJson, NodeVersion, Config } from '../types';
import { getSupportedNodeVersion } from './node-version';
import { getSupportedNodeVersion, getLatestNodeVersion } from './node-version';
export function spawnAsync(
command: string,
@@ -39,6 +39,66 @@ export function spawnAsync(
});
}
export function execAsync(
command: string,
args: string[],
opts: SpawnOptions = {}
) {
return new Promise<{ stdout: string; stderr: string; code: number }>(
(resolve, reject) => {
opts.stdio = 'pipe';
const stdoutList: Buffer[] = [];
const stderrList: Buffer[] = [];
const child = spawn(command, args, opts);
child.stderr!.on('data', data => {
stderrList.push(data);
});
child.stdout!.on('data', data => {
stdoutList.push(data);
});
child.on('error', reject);
child.on('close', (code, signal) => {
if (code !== 0) {
return reject(
new Error(
`Program "${command}" exited with non-zero exit code ${code} ${signal}.`
)
);
}
return resolve({
code,
stdout: Buffer.concat(stdoutList).toString(),
stderr: Buffer.concat(stderrList).toString(),
});
});
}
);
}
export function spawnCommand(command: string, options: SpawnOptions = {}) {
if (process.platform === 'win32') {
return spawn('cmd.exe', ['/C', command], options);
}
return spawn('sh', ['-c', command], options);
}
export async function execCommand(command: string, options: SpawnOptions = {}) {
if (process.platform === 'win32') {
await spawnAsync('cmd.exe', ['/C', command], options);
} else {
await spawnAsync('sh', ['-c', command], options);
}
return true;
}
async function chmodPlusX(fsPath: string) {
const s = await fs.stat(fsPath);
const newMode = s.mode | 64 | 8 | 1; // eslint-disable-line no-bitwise
@@ -80,22 +140,30 @@ export function getSpawnOptions(
export async function getNodeVersion(
destPath: string,
minNodeVersion?: string,
config?: Config
config?: Config,
meta?: Meta
): Promise<NodeVersion> {
if (meta && meta.isDev) {
// Use the system-installed version of `node` in PATH for `now dev`
const latest = getLatestNodeVersion();
return { ...latest, runtime: 'nodejs' };
}
const { packageJson } = await scanParentDirs(destPath, true);
let range: string | undefined;
let silent = false;
let isAuto = false;
if (packageJson && packageJson.engines && packageJson.engines.node) {
range = packageJson.engines.node;
} else if (minNodeVersion) {
range = minNodeVersion;
silent = true;
isAuto = true;
} else if (config && config.nodeVersion) {
range = config.nodeVersion;
isAuto = true;
} else if (config && config.zeroConfig) {
// Use latest node version zero config detected
range = '10.x';
silent = true;
isAuto = true;
}
return getSupportedNodeVersion(range, silent);
return getSupportedNodeVersion(range, isAuto);
}
async function scanParentDirs(destPath: string, readPackageJson = false) {

View File

@@ -3,12 +3,15 @@ import FileFsRef from './file-fs-ref';
import FileRef from './file-ref';
import { Lambda, createLambda, getLambdaOptionsFromFunction } from './lambda';
import { Prerender } from './prerender';
import download, { DownloadedFiles } from './fs/download';
import download, { DownloadedFiles, isSymbolicLink } from './fs/download';
import getWriteableDirectory from './fs/get-writable-directory';
import glob from './fs/glob';
import rename from './fs/rename';
import {
execAsync,
spawnAsync,
execCommand,
spawnCommand,
installDependencies,
runPackageJsonScript,
runNpmInstall,
@@ -18,11 +21,9 @@ import {
getNodeVersion,
getSpawnOptions,
} from './fs/run-user-scripts';
import { getLatestNodeVersion } from './fs/node-version';
import streamToBuffer from './fs/stream-to-buffer';
import shouldServe from './should-serve';
import { detectBuilders } from './detect-builders';
import { detectRoutes } from './detect-routes';
import DetectorFilesystem from './detectors/filesystem';
import debug from './debug';
export {
@@ -30,7 +31,6 @@ export {
FileFsRef,
FileRef,
Lambda,
DetectorFilesystem,
createLambda,
Prerender,
download,
@@ -38,22 +38,32 @@ export {
getWriteableDirectory,
glob,
rename,
execAsync,
spawnAsync,
installDependencies,
runPackageJsonScript,
execCommand,
spawnCommand,
runNpmInstall,
runBundleInstall,
runPipInstall,
runShellScript,
getNodeVersion,
getLatestNodeVersion,
getSpawnOptions,
streamToBuffer,
shouldServe,
detectBuilders,
detectRoutes,
debug,
isSymbolicLink,
getLambdaOptionsFromFunction,
};
export { detectDefaults } from './detectors';
export { detectRoutes, detectOutputDirectory } from './detect-routes';
export { detectBuilders } from './detect-builders';
export { detectFramework } from './detect-framework';
export { DetectorFilesystem } from './detectors/filesystem';
export { readConfigFile } from './fs/read-config-file';
export * from './schemas';
export * from './types';
export * from './errors';

View File

@@ -0,0 +1,61 @@
export const functionsSchema = {
type: 'object',
minProperties: 1,
maxProperties: 50,
additionalProperties: false,
patternProperties: {
'^.{1,256}$': {
type: 'object',
additionalProperties: false,
properties: {
runtime: {
type: 'string',
maxLength: 256,
},
memory: {
// Number between 128 and 3008 in steps of 64
enum: Object.keys(Array.from({ length: 50 }))
.slice(2, 48)
.map(x => Number(x) * 64),
},
maxDuration: {
type: 'number',
minimum: 1,
maximum: 900,
},
includeFiles: {
type: 'string',
maxLength: 256,
},
excludeFiles: {
type: 'string',
maxLength: 256,
},
},
},
},
};
export const buildsSchema = {
type: 'array',
minItems: 0,
maxItems: 128,
items: {
type: 'object',
additionalProperties: false,
required: ['use'],
properties: {
src: {
type: 'string',
minLength: 1,
maxLength: 4096,
},
use: {
type: 'string',
minLength: 3,
maxLength: 256,
},
config: { type: 'object' },
},
},
};

View File

@@ -1,6 +1,5 @@
import FileRef from './file-ref';
import FileFsRef from './file-fs-ref';
import DetectorFilesystem from './detectors/filesystem';
export interface Env {
[name: string]: string | undefined;
@@ -21,18 +20,6 @@ export interface Files {
[filePath: string]: File;
}
export interface Route {
src?: string;
dest?: string;
handle?: string;
type?: string;
headers?: {
[key: string]: string;
};
continue?: boolean;
status?: number;
}
export interface Config {
[key: string]:
| string
@@ -52,6 +39,11 @@ export interface Config {
zeroConfig?: boolean;
import?: { [key: string]: string };
functions?: BuilderFunctions;
outputDirectory?: string;
buildCommand?: string;
devCommand?: string;
framework?: string;
nodeVersion?: string;
}
export interface Meta {
@@ -304,6 +296,7 @@ export interface NodeVersion {
major: number;
range: string;
runtime: string;
discontinueDate?: Date;
}
export interface Builder {
@@ -342,29 +335,3 @@ export interface NowHeaderKeyValue {
key: string;
value: string;
}
export type Detector = (params: DetectorParameters) => Promise<DetectorResult>;
export interface DetectorParameters {
fs: DetectorFilesystem;
detectors?: Detector[];
pkgDetectors?: Detector[];
}
export interface DetectorOutput {
buildCommand: string;
buildDirectory: string;
buildVariables?: Env;
devCommand?: string;
devVariables?: Env;
minNodeRange?: string;
cachePattern?: string;
routes?: Route[];
cleanUrls?: boolean;
rewrites?: NowRewrite[];
redirects?: NowRedirect[];
headers?: NowHeader[];
trailingSlash?: boolean;
}
export type DetectorResult = DetectorOutput | false;

File diff suppressed because it is too large Load Diff

View File

@@ -1,108 +0,0 @@
import assert from 'assert';
import { join } from 'path';
import { readFile, pathExists } from 'fs-extra';
import { detectDefaults, DetectorFilesystem } from '../src';
import { firstTruthy } from '../src/detectors';
class LocalFilesystem extends DetectorFilesystem {
private dir: string;
constructor(dir: string) {
super();
this.dir = dir;
}
_exists(name: string): Promise<boolean> {
return pathExists(join(this.dir, name));
}
_readFile(name: string): Promise<Buffer> {
return readFile(join(this.dir, name));
}
}
test('firstTruthy() - truthy', async () => {
const result = await firstTruthy([(async () => 0)(), (async () => 1)()]);
assert.equal(result, 1);
});
test('firstTruthy() - falsy', async () => {
const result = await firstTruthy([(async () => 0)(), (async () => 0)()]);
assert.equal(result, 0);
});
test('firstTruthy() - one throws', async () => {
const result = await firstTruthy([
(async () => {
throw new Error('bad');
})(),
(async () => 1)(),
]);
assert.equal(result, 1);
});
test('firstTruthy() - all throws', async () => {
let errors;
try {
await firstTruthy([
(async () => {
throw new Error('bad 1');
})(),
(async () => {
throw new Error('bad 2');
})(),
]);
} catch (_err) {
errors = _err;
}
assert(errors);
assert.equal(errors.name, 'AggregateError');
const arr = Array.from(errors) as Error[];
assert.equal(arr[0].message, 'bad 1');
assert.equal(arr[1].message, 'bad 2');
});
test('detectDefaults() - angular', async () => {
const dir = join(__dirname, 'fixtures', '03-zero-config-angular');
const fs = new LocalFilesystem(dir);
const result = await detectDefaults({ fs });
if (!result) throw new Error('Expected result');
assert.equal(result.buildDirectory, 'dist');
assert.deepEqual(result.buildCommand, 'ng build');
});
test('detectDefaults() - brunch', async () => {
const dir = join(__dirname, 'fixtures', '04-zero-config-brunch');
const fs = new LocalFilesystem(dir);
const result = await detectDefaults({ fs });
if (!result) throw new Error('Expected result');
assert.equal(result.buildDirectory, 'public');
assert.deepEqual(result.buildCommand, 'brunch build --production');
});
test('detectDefaults() - hugo', async () => {
const dir = join(__dirname, 'fixtures', '06-zero-config-hugo');
const fs = new LocalFilesystem(dir);
const result = await detectDefaults({ fs });
if (!result) throw new Error('Expected result');
assert.equal(result.buildDirectory, 'public');
assert.deepEqual(result.buildCommand, 'hugo');
});
test('detectDefaults() - jekyll', async () => {
const dir = join(__dirname, 'fixtures', '07-zero-config-jekyll');
const fs = new LocalFilesystem(dir);
const result = await detectDefaults({ fs });
if (!result) throw new Error('Expected result');
assert.equal(result.buildDirectory, '_site');
assert.deepEqual(result.buildCommand, 'jekyll build');
});
test('detectDefaults() - middleman', async () => {
const dir = join(__dirname, 'fixtures', '08-zero-config-middleman');
const fs = new LocalFilesystem(dir);
const result = await detectDefaults({ fs });
if (!result) throw new Error('Expected result');
assert.equal(result.buildDirectory, 'build');
assert.deepEqual(result.buildCommand, 'bundle exec middleman build');
});

View File

@@ -0,0 +1,141 @@
import path from 'path';
import { readFileSync } from 'fs-extra';
import { Framework } from '@now/frameworks';
import { detectFramework, DetectorFilesystem } from '../src';
const frameworkList = JSON.parse(
readFileSync(
path.join(__dirname, '..', '..', 'frameworks', 'frameworks.json')
).toString()
) as Framework[];
class VirtualFilesystem extends DetectorFilesystem {
private files: Map<string, Buffer>;
constructor(files: { [key: string]: string | Buffer }) {
super();
this.files = new Map();
Object.entries(files).map(([key, value]) => {
const buffer = typeof value === 'string' ? Buffer.from(value) : value;
this.files.set(key, buffer);
});
}
async _exists(name: string): Promise<boolean> {
return this.files.has(name);
}
async _readFile(name: string): Promise<Buffer> {
const file = this.files.get(name);
if (file === undefined) {
throw new Error('File does not exist');
}
if (typeof file === 'string') {
return Buffer.from(file);
}
return file;
}
}
describe('#detectFramework', () => {
it('Do not detect anything', async () => {
const fs = new VirtualFilesystem({
'README.md': '# hi',
'api/cheese.js': 'export default (req, res) => res.end("cheese");',
});
expect(await detectFramework({ fs, frameworkList })).toBe(null);
});
it('Detect Next.js', async () => {
const fs = new VirtualFilesystem({
'package.json': JSON.stringify({
dependencies: {
next: '9.0.0',
},
}),
});
expect(await detectFramework({ fs, frameworkList })).toBe('nextjs');
});
it('Detect Nuxt.js', async () => {
const fs = new VirtualFilesystem({
'package.json': JSON.stringify({
dependencies: {
nuxt: '1.0.0',
},
}),
});
expect(await detectFramework({ fs, frameworkList })).toBe('nuxtjs');
});
it('Detect Gatsby', async () => {
const fs = new VirtualFilesystem({
'package.json': JSON.stringify({
dependencies: {
gatsby: '1.0.0',
},
}),
});
expect(await detectFramework({ fs, frameworkList })).toBe('gatsby');
});
it('Detect Hugo #1', async () => {
const fs = new VirtualFilesystem({
'config.yaml': 'config',
});
expect(await detectFramework({ fs, frameworkList })).toBe('hugo');
});
it('Detect Hugo #2', async () => {
const fs = new VirtualFilesystem({
'config.json': 'config',
});
expect(await detectFramework({ fs, frameworkList })).toBe('hugo');
});
it('Detect Hugo #3', async () => {
const fs = new VirtualFilesystem({
'config.toml': 'config',
});
expect(await detectFramework({ fs, frameworkList })).toBe('hugo');
});
it('Detect Jekyll', async () => {
const fs = new VirtualFilesystem({
'_config.yml': 'config',
});
expect(await detectFramework({ fs, frameworkList })).toBe('jekyll');
});
it('Detect Middleman', async () => {
const fs = new VirtualFilesystem({
'config.rb': 'config',
});
expect(await detectFramework({ fs, frameworkList })).toBe('middleman');
});
it('Detect Scully', async () => {
const fs = new VirtualFilesystem({
'package.json': JSON.stringify({
dependencies: {
'@angular/cli': 'latest',
'@scullyio/init': 'latest',
},
}),
});
expect(await detectFramework({ fs, frameworkList })).toBe('scully');
});
});

View File

@@ -1,13 +1,10 @@
const path = require('path');
const fs = require('fs-extra');
const execa = require('execa');
const assert = require('assert');
const { createZip } = require('../dist/lambda');
const { glob, download, detectBuilders, detectRoutes } = require('../');
const {
getSupportedNodeVersion,
defaultSelection,
} = require('../dist/fs/node-version');
const { glob, spawnAsync, download } = require('../');
const { getSupportedNodeVersion } = require('../dist/fs/node-version');
const { getNodeVersion, getLatestNodeVersion } = require('../dist');
it('should re-create symlinks properly', async () => {
const files = await glob('**', path.join(__dirname, 'symlinks'));
@@ -39,7 +36,7 @@ it('should create zip files with symlinks properly', async () => {
await fs.mkdirp(outDir);
await fs.writeFile(outFile, await createZip(files));
await execa('unzip', [outFile], { cwd: outDir });
await spawnAsync('unzip', [outFile], { cwd: outDir });
const [linkStat, aStat] = await Promise.all([
fs.lstat(path.join(outDir, 'link.txt')),
@@ -50,15 +47,31 @@ it('should create zip files with symlinks properly', async () => {
});
it('should only match supported node versions', async () => {
expect(await getSupportedNodeVersion('10.x')).toHaveProperty('major', 10);
expect(await getSupportedNodeVersion('8.10.x')).toHaveProperty('major', 8);
expect(getSupportedNodeVersion('8.11.x')).rejects.toThrow();
expect(getSupportedNodeVersion('6.x')).rejects.toThrow();
expect(getSupportedNodeVersion('999.x')).rejects.toThrow();
expect(getSupportedNodeVersion('foo')).rejects.toThrow();
expect(await getSupportedNodeVersion('')).toBe(defaultSelection);
expect(await getSupportedNodeVersion(null)).toBe(defaultSelection);
expect(await getSupportedNodeVersion(undefined)).toBe(defaultSelection);
expect(await getSupportedNodeVersion('10.x', false)).toHaveProperty(
'major',
10
);
expect(await getSupportedNodeVersion('12.x', false)).toHaveProperty(
'major',
12
);
expect(getSupportedNodeVersion('8.11.x', false)).rejects.toThrow();
expect(getSupportedNodeVersion('6.x', false)).rejects.toThrow();
expect(getSupportedNodeVersion('999.x', false)).rejects.toThrow();
expect(getSupportedNodeVersion('foo', false)).rejects.toThrow();
expect(await getSupportedNodeVersion('10.x', true)).toHaveProperty(
'major',
10
);
expect(await getSupportedNodeVersion('12.x', true)).toHaveProperty(
'major',
12
);
expect(getSupportedNodeVersion('8.11.x', true)).rejects.toThrow();
expect(getSupportedNodeVersion('6.x', true)).rejects.toThrow();
expect(getSupportedNodeVersion('999.x', true)).rejects.toThrow();
expect(getSupportedNodeVersion('foo', true)).rejects.toThrow();
});
it('should match all semver ranges', async () => {
@@ -79,6 +92,47 @@ it('should match all semver ranges', async () => {
expect(await getSupportedNodeVersion('^10.5.0')).toHaveProperty('major', 10);
});
it('should select correct node version in getNodeVersion()', async () => {
expect(
await getNodeVersion('/tmp', undefined, { nodeVersion: '12.x' })
).toHaveProperty('major', 12);
expect(
await getNodeVersion('/tmp', undefined, { nodeVersion: '10.x' })
).toHaveProperty('major', 10);
expect(
await getNodeVersion('/tmp', '10.x', { nodeVersion: '12.x' })
).toHaveProperty('major', 10);
});
it('should ignore node version in now dev getNodeVersion()', async () => {
expect(
await getNodeVersion(
'/tmp',
undefined,
{ nodeVersion: '1' },
{ isDev: true }
)
).toHaveProperty('runtime', 'nodejs');
});
it('should get latest node version', async () => {
expect(await getLatestNodeVersion()).toHaveProperty('major', 12);
});
it('should throw for discontinued versions', async () => {
// Mock a future date so that Node 8 becomes discontinued
const realDateNow = Date.now.bind(global.Date);
global.Date.now = () => new Date('2020-02-14').getTime();
expect(getSupportedNodeVersion('', false)).rejects.toThrow();
expect(getSupportedNodeVersion('8.10.x', false)).rejects.toThrow();
expect(getSupportedNodeVersion('', true)).rejects.toThrow();
expect(getSupportedNodeVersion('8.10.x', true)).rejects.toThrow();
global.Date.now = realDateNow;
});
it('should support require by path for legacy builders', () => {
const index = require('@now/build-utils');
@@ -108,783 +162,3 @@ it('should support require by path for legacy builders', () => {
expect(FileRef2).toBe(index.FileRef);
expect(Lambda2).toBe(index.Lambda);
});
describe('Test `detectBuilders`', () => {
it('package.json + no build', async () => {
const pkg = { dependencies: { next: '9.0.0' } };
const files = ['package.json', 'pages/index.js', 'public/index.html'];
const { builders, errors } = await detectBuilders(files, pkg);
expect(builders).toBe(null);
expect(errors.length).toBe(1);
});
it('package.json + no build + next', async () => {
const pkg = {
scripts: { build: 'next build' },
dependencies: { next: '9.0.0' },
};
const files = ['package.json', 'pages/index.js'];
const { builders, errors } = await detectBuilders(files, pkg);
expect(builders[0].use).toBe('@now/next');
expect(errors).toBe(null);
});
it('package.json + no build + next', async () => {
const pkg = {
scripts: { build: 'next build' },
devDependencies: { next: '9.0.0' },
};
const files = ['package.json', 'pages/index.js'];
const { builders, errors } = await detectBuilders(files, pkg);
expect(builders[0].use).toBe('@now/next');
expect(errors).toBe(null);
});
it('package.json + no build', async () => {
const pkg = {};
const files = ['package.json'];
const { builders, errors } = await detectBuilders(files, pkg);
expect(builders).toBe(null);
expect(errors.length).toBe(1);
});
it('static file', async () => {
const files = ['index.html'];
const { builders, errors } = await detectBuilders(files);
expect(builders).toBe(null);
expect(errors).toBe(null);
});
it('no package.json + public', async () => {
const files = ['api/users.js', 'public/index.html'];
const { builders, errors } = await detectBuilders(files);
expect(builders[1].use).toBe('@now/static');
expect(errors).toBe(null);
});
it('no package.json + no build + raw static + api', async () => {
const files = ['api/users.js', 'index.html'];
const { builders, errors } = await detectBuilders(files);
expect(builders[0].use).toBe('@now/node');
expect(builders[0].src).toBe('api/users.js');
expect(builders[1].use).toBe('@now/static');
expect(builders[1].src).toBe('!{api/**,package.json}');
expect(builders.length).toBe(2);
expect(errors).toBe(null);
});
it('package.json + no build + root + api', async () => {
const files = ['index.html', 'api/[endpoint].js', 'static/image.png'];
const { builders, errors } = await detectBuilders(files);
expect(builders[0].use).toBe('@now/node');
expect(builders[0].src).toBe('api/[endpoint].js');
expect(builders[1].use).toBe('@now/static');
expect(builders[1].src).toBe('!{api/**,package.json}');
expect(builders.length).toBe(2);
expect(errors).toBe(null);
});
it('api + ignore files', async () => {
const files = [
'api/_utils/handler.js',
'api/[endpoint]/.helper.js',
'api/[endpoint]/[id].js',
];
const { builders } = await detectBuilders(files);
expect(builders[0].use).toBe('@now/node');
expect(builders[0].src).toBe('api/[endpoint]/[id].js');
expect(builders.length).toBe(1);
});
it('api + next + public', async () => {
const pkg = {
scripts: { build: 'next build' },
devDependencies: { next: '9.0.0' },
};
const files = ['package.json', 'api/endpoint.js', 'public/index.html'];
const { builders } = await detectBuilders(files, pkg);
expect(builders[0].use).toBe('@now/node');
expect(builders[0].src).toBe('api/endpoint.js');
expect(builders[1].use).toBe('@now/next');
expect(builders[1].src).toBe('package.json');
expect(builders.length).toBe(2);
});
it('api + next + raw static', async () => {
const pkg = {
scripts: { build: 'next build' },
devDependencies: { next: '9.0.0' },
};
const files = ['package.json', 'api/endpoint.js', 'index.html'];
const { builders } = await detectBuilders(files, pkg);
expect(builders[0].use).toBe('@now/node');
expect(builders[0].src).toBe('api/endpoint.js');
expect(builders[1].use).toBe('@now/next');
expect(builders[1].src).toBe('package.json');
expect(builders.length).toBe(2);
});
it('api + raw static', async () => {
const files = ['api/endpoint.js', 'index.html', 'favicon.ico'];
const { builders } = await detectBuilders(files);
expect(builders[0].use).toBe('@now/node');
expect(builders[0].src).toBe('api/endpoint.js');
expect(builders[1].use).toBe('@now/static');
expect(builders[1].src).toBe('!{api/**,package.json}');
expect(builders.length).toBe(2);
});
it('api + public', async () => {
const files = [
'api/endpoint.js',
'public/index.html',
'public/favicon.ico',
'README.md',
];
const { builders } = await detectBuilders(files);
expect(builders[0].use).toBe('@now/node');
expect(builders[0].src).toBe('api/endpoint.js');
expect(builders[1].use).toBe('@now/static');
expect(builders[1].src).toBe('public/**/*');
expect(builders.length).toBe(2);
});
it('just public', async () => {
const files = ['public/index.html', 'public/favicon.ico', 'README.md'];
const { builders } = await detectBuilders(files);
expect(builders[0].src).toBe('public/**/*');
expect(builders.length).toBe(1);
});
it('next + public', async () => {
const pkg = {
scripts: { build: 'next build' },
devDependencies: { next: '9.0.0' },
};
const files = ['package.json', 'public/index.html', 'README.md'];
const { builders } = await detectBuilders(files, pkg);
expect(builders[0].use).toBe('@now/next');
expect(builders[0].src).toBe('package.json');
expect(builders.length).toBe(1);
});
it('nuxt', async () => {
const pkg = {
scripts: { build: 'nuxt build' },
dependencies: { nuxt: '2.8.1' },
};
const files = ['package.json', 'pages/index.js'];
const { builders } = await detectBuilders(files, pkg);
expect(builders[0].use).toBe('@now/static-build');
expect(builders[0].src).toBe('package.json');
expect(builders.length).toBe(1);
});
it('nuxt + tag canary', async () => {
const pkg = {
scripts: { build: 'nuxt build' },
dependencies: { nuxt: '2.8.1' },
};
const files = ['package.json', 'pages/index.js'];
const { builders } = await detectBuilders(files, pkg, { tag: 'canary' });
expect(builders[0].use).toBe('@now/static-build@canary');
expect(builders[0].src).toBe('package.json');
expect(builders.length).toBe(1);
});
it('package.json with no build + api', async () => {
const pkg = { dependencies: { next: '9.0.0' } };
const files = ['package.json', 'api/[endpoint].js'];
const { builders } = await detectBuilders(files, pkg);
expect(builders[0].use).toBe('@now/node');
expect(builders[0].src).toBe('api/[endpoint].js');
expect(builders.length).toBe(1);
});
it('package.json with no build + public directory', async () => {
const pkg = { dependencies: { next: '9.0.0' } };
const files = ['package.json', 'public/index.html'];
const { builders, errors } = await detectBuilders(files, pkg);
expect(builders).toBe(null);
expect(errors.length).toBe(1);
});
it('no package.json + api', async () => {
const files = ['api/[endpoint].js', 'api/[endpoint]/[id].js'];
const { builders } = await detectBuilders(files);
expect(builders.length).toBe(2);
});
it('no package.json + no api', async () => {
const files = ['index.html'];
const { builders, errors } = await detectBuilders(files);
expect(builders).toBe(null);
expect(errors).toBe(null);
});
it('package.json + api + canary', async () => {
const pkg = {
scripts: { build: 'next build' },
dependencies: { next: '9.0.0' },
};
const files = [
'pages/index.js',
'api/[endpoint].js',
'api/[endpoint]/[id].js',
];
const { builders } = await detectBuilders(files, pkg, { tag: 'canary' });
expect(builders[0].use).toBe('@now/node@canary');
expect(builders[1].use).toBe('@now/node@canary');
expect(builders[2].use).toBe('@now/next@canary');
expect(builders.length).toBe(3);
});
it('package.json + api + latest', async () => {
const pkg = {
scripts: { build: 'next build' },
dependencies: { next: '9.0.0' },
};
const files = [
'pages/index.js',
'api/[endpoint].js',
'api/[endpoint]/[id].js',
];
const { builders } = await detectBuilders(files, pkg, { tag: 'latest' });
expect(builders[0].use).toBe('@now/node@latest');
expect(builders[1].use).toBe('@now/node@latest');
expect(builders[2].use).toBe('@now/next@latest');
expect(builders.length).toBe(3);
});
it('package.json + api + random tag', async () => {
const pkg = {
scripts: { build: 'next build' },
dependencies: { next: '9.0.0' },
};
const files = [
'pages/index.js',
'api/[endpoint].js',
'api/[endpoint]/[id].js',
];
const { builders } = await detectBuilders(files, pkg, { tag: 'haha' });
expect(builders[0].use).toBe('@now/node@haha');
expect(builders[1].use).toBe('@now/node@haha');
expect(builders[2].use).toBe('@now/next@haha');
expect(builders.length).toBe(3);
});
it('next.js pages/api + api', async () => {
const pkg = {
scripts: { build: 'next build' },
dependencies: { next: '9.0.0' },
};
const files = ['api/user.js', 'pages/api/user.js'];
const { warnings, errors, builders } = await detectBuilders(files, pkg);
expect(errors).toBe(null);
expect(warnings[0]).toBeDefined();
expect(warnings[0].code).toBe('conflicting_files');
expect(builders).toBeDefined();
expect(builders.length).toBe(2);
expect(builders[0].use).toBe('@now/node');
expect(builders[1].use).toBe('@now/next');
});
it('many static files + one api file', async () => {
const files = Array.from({ length: 5000 }).map((_, i) => `file${i}.html`);
files.push('api/index.ts');
const { builders } = await detectBuilders(files);
expect(builders.length).toBe(2);
expect(builders[0].use).toBe('@now/node');
expect(builders[0].src).toBe('api/index.ts');
expect(builders[1].use).toBe('@now/static');
expect(builders[1].src).toBe('!{api/**,package.json}');
});
it('functions with nextjs', async () => {
const pkg = {
scripts: { build: 'next build' },
dependencies: { next: '9.0.0' },
};
const functions = {
'pages/api/teams/**': {
memory: 128,
maxDuration: 10,
},
};
const files = [
'package.json',
'pages/index.js',
'pages/api/teams/members.ts',
];
const { builders, errors } = await detectBuilders(files, pkg, {
functions,
});
expect(errors).toBe(null);
expect(builders.length).toBe(1);
expect(builders[0]).toEqual({
src: 'package.json',
use: '@now/next',
config: {
zeroConfig: true,
functions: {
'pages/api/teams/**': {
memory: 128,
maxDuration: 10,
},
},
},
});
});
it('extend with functions', async () => {
const pkg = {
scripts: { build: 'next build' },
dependencies: { next: '9.0.0' },
};
const functions = {
'api/users/*.ts': {
runtime: 'my-custom-runtime-package@1.0.0',
},
'api/teams/members.ts': {
memory: 128,
maxDuration: 10,
},
};
const files = [
'package.json',
'pages/index.js',
'api/users/[id].ts',
'api/teams/members.ts',
];
const { builders } = await detectBuilders(files, pkg, { functions });
expect(builders.length).toBe(3);
expect(builders[0]).toEqual({
src: 'api/teams/members.ts',
use: '@now/node',
config: {
zeroConfig: true,
functions: {
'api/teams/members.ts': {
memory: 128,
maxDuration: 10,
},
},
},
});
expect(builders[1]).toEqual({
src: 'api/users/[id].ts',
use: 'my-custom-runtime-package@1.0.0',
config: {
zeroConfig: true,
functions: {
'api/users/*.ts': {
runtime: 'my-custom-runtime-package@1.0.0',
},
},
},
});
expect(builders[2]).toEqual({
src: 'package.json',
use: '@now/next',
config: {
zeroConfig: true,
},
});
});
it('invalid function key', async () => {
const functions = { ['a'.repeat(1000)]: { memory: 128 } };
const files = ['pages/index.ts'];
const { builders, errors } = await detectBuilders(files, null, {
functions,
});
expect(builders).toBe(null);
expect(errors.length).toBe(1);
expect(errors[0].code).toBe('invalid_function_glob');
});
it('invalid function maxDuration', async () => {
const functions = { 'pages/index.ts': { maxDuration: -1 } };
const files = ['pages/index.ts'];
const { builders, errors } = await detectBuilders(files, null, {
functions,
});
expect(builders).toBe(null);
expect(errors.length).toBe(1);
expect(errors[0].code).toBe('invalid_function_duration');
});
it('invalid function memory', async () => {
const functions = { 'pages/index.ts': { memory: 200 } };
const files = ['pages/index.ts'];
const { builders, errors } = await detectBuilders(files, null, {
functions,
});
expect(builders).toBe(null);
expect(errors.length).toBe(1);
expect(errors[0].code).toBe('invalid_function_memory');
});
it('missing runtime version', async () => {
const functions = { 'pages/index.ts': { runtime: 'haha' } };
const files = ['pages/index.ts'];
const { builders, errors } = await detectBuilders(files, null, {
functions,
});
expect(builders).toBe(null);
expect(errors.length).toBe(1);
expect(errors[0].code).toBe('invalid_function_runtime');
});
it('use a custom runtime', async () => {
const functions = { 'api/user.php': { runtime: 'now-php@0.0.5' } };
const files = ['api/user.php'];
const { builders, errors } = await detectBuilders(files, null, {
functions,
});
expect(errors).toBe(null);
expect(builders.length).toBe(1);
expect(builders[0].use).toBe('now-php@0.0.5');
});
it('use a custom runtime but without a source', async () => {
const functions = { 'api/user.php': { runtime: 'now-php@0.0.5' } };
const files = ['api/team.js'];
const { errors } = await detectBuilders(files, null, {
functions,
});
expect(errors.length).toBe(1);
expect(errors[0].code).toBe('invalid_function_source');
});
it('do not allow empty functions', async () => {
const functions = { 'api/user.php': {} };
const files = ['api/user.php'];
const { errors } = await detectBuilders(files, null, {
functions,
});
expect(errors.length).toBe(1);
expect(errors[0].code).toBe('invalid_function');
});
it('do not allow null functions', async () => {
const functions = { 'api/user.php': null };
const files = ['api/user.php'];
const { errors } = await detectBuilders(files, null, {
functions,
});
expect(errors.length).toBe(1);
expect(errors[0].code).toBe('invalid_function');
});
it('Do not allow functions that are not used by @now/next', async () => {
const pkg = {
scripts: { build: 'next build' },
dependencies: { next: '9.0.0' },
};
const functions = { 'test.js': { memory: 1024 } };
const files = ['pages/index.js', 'test.js'];
const { errors } = await detectBuilders(files, pkg, { functions });
expect(errors).toBeDefined();
expect(errors[0].code).toBe('unused_function');
});
it('Do not allow function non Community Runtimes', async () => {
const functions = {
'api/test.js': { memory: 128, runtime: '@now/node@1.0.0' },
};
const files = ['api/test.js'];
const { errors } = await detectBuilders(files, null, { functions });
expect(errors).toBeDefined();
expect(errors[0].code).toBe('invalid_function_runtime');
});
it('Must include includeFiles config property', async () => {
const functions = {
'api/test.js': { includeFiles: 'text/include.txt' },
};
const files = ['api/test.js'];
const { builders, errors } = await detectBuilders(files, null, {
functions,
});
expect(errors).toBe(null);
expect(builders).not.toBe(null);
expect(builders[0].use).toBe('@now/node');
expect(builders[0].config).toMatchObject({
functions,
zeroConfig: true,
includeFiles: 'text/include.txt',
});
});
it('Must include excludeFiles config property', async () => {
const functions = {
'api/test.js': { excludeFiles: 'text/exclude.txt' },
};
const files = ['api/test.js'];
const { builders, errors } = await detectBuilders(files, null, {
functions,
});
expect(errors).toBe(null);
expect(builders).not.toBe(null);
expect(builders[0].use).toBe('@now/node');
expect(builders[0].config).toMatchObject({
functions,
zeroConfig: true,
excludeFiles: 'text/exclude.txt',
});
});
it('Must include excludeFiles and includeFiles config property', async () => {
const functions = {
'api/test.js': {
excludeFiles: 'text/exclude.txt',
includeFiles: 'text/include.txt',
},
};
const files = ['api/test.js'];
const { builders, errors } = await detectBuilders(files, null, {
functions,
});
expect(errors).toBe(null);
expect(builders).not.toBe(null);
expect(builders[0].use).toBe('@now/node');
expect(builders[0].config).toMatchObject({
functions,
zeroConfig: true,
excludeFiles: 'text/exclude.txt',
includeFiles: 'text/include.txt',
});
});
it('Must fail for includeFiles config property', async () => {
const functions = {
'api/test.js': { includeFiles: { test: 1 } },
};
const files = ['api/test.js'];
const { errors } = await detectBuilders(files, null, { functions });
expect(errors).not.toBe(null);
expect(errors[0].code).toBe('invalid_function_property');
});
it('Must fail for excludeFiles config property', async () => {
const functions = {
'api/test.js': { excludeFiles: { test: 1 } },
};
const files = ['api/test.js'];
const { errors } = await detectBuilders(files, null, { functions });
expect(errors).not.toBe(null);
expect(errors[0].code).toBe('invalid_function_property');
});
it('Must fail when function patterns start with a slash', async () => {
const functions = {
'/api/test.js': { memory: 128 },
};
const files = ['api/test.js', '/api/test.js'];
const { errors } = await detectBuilders(files, null, { functions });
expect(errors).not.toBe(null);
expect(errors[0].code).toBe('invalid_function_source');
});
});
it('Test `detectRoutes`', async () => {
{
const files = ['api/user.go', 'api/team.js', 'api/package.json'];
const { builders } = await detectBuilders(files);
const { defaultRoutes } = await detectRoutes(files, builders);
expect(defaultRoutes.length).toBe(3);
expect(defaultRoutes[0].dest).toBe('/api/team.js');
expect(defaultRoutes[1].dest).toBe('/api/user.go');
expect(defaultRoutes[2].dest).not.toBeDefined();
expect(defaultRoutes[2].status).toBe(404);
}
{
const files = ['api/user.go', 'api/user.js'];
const { builders } = await detectBuilders(files);
const { error } = await detectRoutes(files, builders);
expect(error.code).toBe('conflicting_file_path');
}
{
const files = ['api/[user].go', 'api/[team]/[id].js'];
const { builders } = await detectBuilders(files);
const { error } = await detectRoutes(files, builders);
expect(error.code).toBe('conflicting_file_path');
}
{
const files = ['api/[team]/[team].js'];
const { builders } = await detectBuilders(files);
const { error } = await detectRoutes(files, builders);
expect(error.code).toBe('conflicting_path_segment');
}
{
const files = ['api/date/index.js', 'api/date/index.go'];
const { builders } = await detectBuilders(files);
const { defaultRoutes, error } = await detectRoutes(files, builders);
expect(defaultRoutes).toBe(null);
expect(error.code).toBe('conflicting_file_path');
}
{
const files = ['api/[endpoint].js', 'api/[endpoint]/[id].js'];
const { builders } = await detectBuilders(files);
const { defaultRoutes } = await detectRoutes(files, builders);
expect(defaultRoutes.length).toBe(3);
}
{
const files = [
'public/index.html',
'api/[endpoint].js',
'api/[endpoint]/[id].js',
];
const { builders } = await detectBuilders(files);
const { defaultRoutes } = await detectRoutes(files, builders);
expect(defaultRoutes[2].status).toBe(404);
expect(defaultRoutes[2].src).toBe('/api(\\/.*)?$');
expect(defaultRoutes[3].src).toBe('/(.*)');
expect(defaultRoutes[3].dest).toBe('/public/$1');
expect(defaultRoutes.length).toBe(4);
}
{
const pkg = {
scripts: { build: 'next build' },
devDependencies: { next: '9.0.0' },
};
const files = ['public/index.html', 'api/[endpoint].js'];
const { builders } = await detectBuilders(files, pkg);
const { defaultRoutes } = await detectRoutes(files, builders);
expect(defaultRoutes[1].status).toBe(404);
expect(defaultRoutes[1].src).toBe('/api(\\/.*)?$');
expect(defaultRoutes.length).toBe(2);
}
{
const files = ['public/index.html'];
const { builders } = await detectBuilders(files);
const { defaultRoutes } = await detectRoutes(files, builders);
expect(defaultRoutes.length).toBe(1);
}
{
const files = ['api/date/index.js', 'api/date.js'];
const { builders } = await detectBuilders(files);
const { defaultRoutes } = await detectRoutes(files, builders);
expect(defaultRoutes.length).toBe(3);
expect(defaultRoutes[0].src).toBe(
'^/api/date(\\/|\\/index|\\/index\\.js)?$'
);
expect(defaultRoutes[0].dest).toBe('/api/date/index.js');
expect(defaultRoutes[1].src).toBe('^/api/(date\\/|date|date\\.js)$');
expect(defaultRoutes[1].dest).toBe('/api/date.js');
}
{
const files = ['api/date.js', 'api/[date]/index.js'];
const { builders } = await detectBuilders(files);
const { defaultRoutes } = await detectRoutes(files, builders);
expect(defaultRoutes.length).toBe(3);
expect(defaultRoutes[0].src).toBe(
'^/api/([^\\/]+)(\\/|\\/index|\\/index\\.js)?$'
);
expect(defaultRoutes[0].dest).toBe('/api/[date]/index.js?date=$1');
expect(defaultRoutes[1].src).toBe('^/api/(date\\/|date|date\\.js)$');
expect(defaultRoutes[1].dest).toBe('/api/date.js');
}
{
const files = [
'api/index.ts',
'api/index.d.ts',
'api/users/index.ts',
'api/users/index.d.ts',
'api/food.ts',
'api/ts/gold.ts',
];
const { builders } = await detectBuilders(files);
const { defaultRoutes } = await detectRoutes(files, builders);
expect(builders.length).toBe(4);
expect(builders[0].use).toBe('@now/node');
expect(builders[1].use).toBe('@now/node');
expect(builders[2].use).toBe('@now/node');
expect(builders[3].use).toBe('@now/node');
expect(defaultRoutes.length).toBe(5);
}
{
// use a custom runtime
const functions = { 'api/user.php': { runtime: 'now-php@0.0.5' } };
const files = ['api/user.php'];
const { builders } = await detectBuilders(files, null, { functions });
const { defaultRoutes } = await detectRoutes(files, builders);
expect(defaultRoutes.length).toBe(2);
expect(defaultRoutes[0].dest).toBe('/api/user.php');
}
});

View File

@@ -3,6 +3,7 @@ const { mkdirp, copyFile } = require('fs-extra');
const {
glob,
debug,
download,
shouldServe,
createLambda,
@@ -14,7 +15,6 @@ exports.analyze = ({ files, entrypoint }) => files[entrypoint].digest;
exports.version = 3;
exports.build = async ({ workPath, files, entrypoint, meta, config }) => {
console.log('downloading files...');
const outDir = await getWritableDirectory();
await download(files, workPath, meta);

View File

@@ -1,6 +1,6 @@
{
"name": "@now/cgi",
"version": "1.0.1-canary.0",
"version": "1.0.1",
"license": "MIT",
"repository": {
"type": "git",

View File

@@ -6,7 +6,7 @@
To install the latest version of Now CLI, visit [zeit.co/download](https://zeit.co/download) or run this command:
```bash
```sh
npm i -g now
```

View File

@@ -1,6 +1,6 @@
{
"name": "now",
"version": "16.6.3",
"version": "16.7.2-canary.3",
"preferGlobal": true,
"license": "Apache-2.0",
"description": "The command-line interface for Now",
@@ -146,7 +146,6 @@
"ora": "3.4.0",
"pcre-to-regexp": "1.0.0",
"pluralize": "7.0.0",
"pre-commit": "1.2.2",
"printf": "0.2.5",
"progress": "2.0.3",
"promisepipe": "3.0.0",

View File

@@ -38,7 +38,6 @@ import {
} from '../../util/errors-ts';
import { SchemaValidationFailed } from '../../util/errors';
import purchaseDomainIfAvailable from '../../util/domains/purchase-domain-if-available';
import handleCertError from '../../util/certs/handle-cert-error';
import isWildcardAlias from '../../util/alias/is-wildcard-alias';
import shouldDeployDir from '../../util/deploy/should-deploy-dir';
@@ -382,15 +381,13 @@ export default async function main(
return 1;
}
const deploymentResponse = handleCertError(
output,
await getDeploymentByIdOrHost(now, contextName, deployment.id, 'v10')
const deploymentResponse = await getDeploymentByIdOrHost(
now,
contextName,
deployment.id,
'v10'
);
if (deploymentResponse === 1) {
return deploymentResponse;
}
if (
deploymentResponse instanceof DeploymentNotFound ||
deploymentResponse instanceof DeploymentPermissionDenied ||
@@ -400,10 +397,6 @@ export default async function main(
return 1;
}
if (handleCertError(output, deployment) === 1) {
return 1;
}
if (deployment === null) {
error('Uploading failed. Please try again.');
return 1;

View File

@@ -70,7 +70,6 @@ import {
InvalidRegionOrDCForScale,
} from '../../util/errors';
import { SchemaValidationFailed } from '../../util/errors';
import handleCertError from '../../util/certs/handle-cert-error';
import readPackage from '../../util/read-package';
interface Env {
@@ -801,11 +800,6 @@ async function sync({
createArgs
);
const handledResult = handleCertError(output, deployment);
if (handledResult === 1) {
return handledResult;
}
if (
deployment instanceof DomainNotFound ||
deployment instanceof NotDomainOwner ||

View File

@@ -17,9 +17,7 @@ export default async function dev(
args: string[],
output: Output
) {
output.dim(
`Now CLI ${pkg.version} dev (beta) — https://zeit.co/feedback/dev`
);
output.dim(`Now CLI ${pkg.version} dev (beta) — https://zeit.co/feedback`);
const [dir = '.'] = args;
const cwd = path.resolve(dir);

View File

@@ -10,6 +10,7 @@ import formatDate from '../../util/format-date';
import formatNSTable from '../../util/format-ns-table';
import getDomainByName from '../../util/domains/get-domain-by-name';
import getScope from '../../util/get-scope';
import getDomainPrice from '../../util/domains/get-domain-price';
type Options = {
'--debug': boolean;
@@ -23,7 +24,7 @@ export default async function inspect(
) {
const {
authConfig: { token },
config
config,
} = ctx;
const { currentTeam } = config;
const { apiUrl } = ctx;
@@ -61,7 +62,12 @@ export default async function inspect(
}
output.debug(`Fetching domain info`);
const domain = await getDomainByName(client, contextName, domainName);
const [domain, renewalPrice] = await Promise.all([
getDomainByName(client, contextName, domainName),
getDomainPrice(client, domainName, 'renewal')
.then(res => (res instanceof Error ? null : res.price))
.catch(() => null),
]);
if (domain instanceof DomainNotFound) {
output.error(
`Domain not found by "${domainName}" under ${chalk.bold(contextName)}`
@@ -104,24 +110,35 @@ export default async function inspect(
` ${chalk.cyan('Bought At')}\t\t\t${formatDate(domain.boughtAt)}\n`
);
output.print(
` ${chalk.cyan('Transferred At')}\t\t${formatDate(domain.transferredAt)}\n`
` ${chalk.cyan('Transferred At')}\t\t${formatDate(
domain.transferredAt
)}\n`
);
output.print(
` ${chalk.cyan('Expires At')}\t\t\t${formatDate(domain.expiresAt)}\n`
);
output.print(
` ${chalk.cyan('NS Verified At')}\t\t${formatDate(domain.nsVerifiedAt)}\n`
` ${chalk.cyan('NS Verified At')}\t\t${formatDate(
domain.nsVerifiedAt
)}\n`
);
output.print(
` ${chalk.cyan('TXT Verified At')}\t\t${formatDate(domain.txtVerifiedAt)}\n`
` ${chalk.cyan('TXT Verified At')}\t\t${formatDate(
domain.txtVerifiedAt
)}\n`
);
output.print(` ${chalk.cyan('CDN Enabled')}\t\t${true}\n`);
if (renewalPrice && domain.boughtAt) {
output.print(
` ${chalk.cyan('Renewal Price')}\t\t$${renewalPrice} USD\n`
);
}
output.print(` ${chalk.cyan('CDN Enabled')}\t\t\t${true}\n`);
output.print('\n');
output.print(chalk.bold(' Nameservers\n\n'));
output.print(
`${formatNSTable(domain.intendedNameservers, domain.nameservers, {
extraSpace: ' '
extraSpace: ' ',
})}\n`
);
output.print('\n');
@@ -129,7 +146,7 @@ export default async function inspect(
output.print(chalk.bold(' Verification Record\n\n'));
output.print(
`${dnsTable([['_now', 'TXT', domain.verificationRecord]], {
extraSpace: ' '
extraSpace: ' ',
})}\n`
);
output.print('\n');

View File

@@ -18,7 +18,10 @@ import getMinFromArgs from '../util/scale/get-min-from-args';
import patchDeploymentScale from '../util/scale/patch-deployment-scale';
import waitVerifyDeploymentScale from '../util/scale/wait-verify-deployment-scale';
import { handleError } from '../util/error';
import { VerifyScaleTimeout, DeploymentTypeUnsupported } from '../util/errors-ts';
import {
VerifyScaleTimeout,
DeploymentTypeUnsupported,
} from '../util/errors-ts';
import {
DeploymentNotFound,
DeploymentPermissionDenied,
@@ -28,7 +31,7 @@ import {
InvalidMaxForScale,
InvalidMinForScale,
InvalidScaleMinMaxRelation,
NotSupportedMinScaleSlots
NotSupportedMinScaleSlots,
} from '../util/errors-ts';
import { InvalidAllForScale, InvalidRegionOrDCForScale } from '../util/errors';
import handleCertError from '../util/certs/handle-cert-error';
@@ -56,7 +59,9 @@ const help = () => {
${chalk.dim('Examples:')}
${chalk.gray('')} Enable your deployment in all datacenters (min: 0, max: auto)
${chalk.gray(
''
)} Enable your deployment in all datacenters (min: 0, max: auto)
${chalk.cyan('$ now scale my-deployment-123.now.sh all')}
@@ -87,7 +92,7 @@ export default async function main(ctx) {
argv = getArgs(ctx.argv.slice(2), {
'--verify-timeout': Number,
'--no-verify': Boolean,
'-n': '--no-verify'
'-n': '--no-verify',
});
} catch (err) {
handleError(err);
@@ -100,7 +105,10 @@ export default async function main(ctx) {
}
// Prepare the context
const { authConfig: { token }, config } = ctx;
const {
authConfig: { token },
config,
} = ctx;
const { currentTeam } = config;
const { apiUrl } = ctx;
const debug = argv['--debug'];
@@ -155,8 +163,7 @@ export default async function main(ctx) {
}
if (dcs instanceof InvalidRegionOrDCForScale) {
output.error(
`The value "${dcs.meta
.regionOrDC}" is not a valid region or DC identifier`
`The value "${dcs.meta.regionOrDC}" is not a valid region or DC identifier`
);
now.close();
return 1;
@@ -165,8 +172,7 @@ export default async function main(ctx) {
const min = getMinFromArgs(argv._);
if (min instanceof InvalidMinForScale) {
output.error(
`Invalid <min> parameter "${min.meta
.value}". A number or "auto" were expected`
`Invalid <min> parameter "${min.meta.value}". A number or "auto" were expected`
);
now.close();
return 1;
@@ -175,24 +181,21 @@ export default async function main(ctx) {
const max = getMaxFromArgs(argv._);
if (max instanceof InvalidMinForScale) {
output.error(
`Invalid <min> parameter "${max.meta
.value}". A number or "auto" were expected`
`Invalid <min> parameter "${max.meta.value}". A number or "auto" were expected`
);
now.close();
return 1;
}
if (max instanceof InvalidArgsForMinMaxScale) {
output.error(
`Invalid number of arguments: expected <min> ("${max.meta
.min}") and [max]`
`Invalid number of arguments: expected <min> ("${max.meta.min}") and [max]`
);
now.close();
return 1;
}
if (max instanceof InvalidMaxForScale) {
output.error(
`Invalid <max> parameter "${max.meta
.value}". A number or "auto" were expected`
`Invalid <max> parameter "${max.meta.value}". A number or "auto" were expected`
);
now.close();
return 1;
@@ -239,7 +242,7 @@ export default async function main(ctx) {
return 1;
}
if (deployment.version === 2) {
output.error('Cannot scale a deployment containing builds');
output.error('Cannot scale a Now 2.0 deployment');
now.close();
return 1;
}
@@ -262,14 +265,15 @@ export default async function main(ctx) {
deployment.url
);
if (result instanceof ForbiddenScaleMinInstances) {
output.error(`You can't scale to more than ${result.meta.max} min instances with your current plan.`);
output.error(
`You can't scale to more than ${result.meta.max} min instances with your current plan.`
);
now.close();
return 1;
}
if (result instanceof ForbiddenScaleMaxInstances) {
output.error(
`You can't scale to more than ${result.meta
.max} max instances with your current plan.`
`You can't scale to more than ${result.meta.max} max instances with your current plan.`
);
now.close();
return 1;

View File

@@ -82,16 +82,6 @@ export default async function processDeployment({
`Total files ${event.payload.total.size}, ${event.payload.missing.length} changed`
);
if (!quiet) {
log(
`Synced ${pluralize(
'file',
event.payload.missing.length,
true
)} ${uploadStamp()}`
);
}
const missingSize = event.payload.missing
.map((sha: string) => event.payload.total.get(sha).data.length)
.reduce((a: number, b: number) => a + b, 0);
@@ -121,6 +111,13 @@ export default async function processDeployment({
now._host = event.payload.url;
if (!quiet) {
log(
`Synced ${pluralize(
'file',
event.payload.missing.length,
true
)} ${uploadStamp()}`
);
const version = isLegacy ? `${chalk.grey('[v1]')} ` : '';
log(`https://${event.payload.url} ${version}${deployStamp()}`);
} else {
@@ -128,7 +125,10 @@ export default async function processDeployment({
}
if (queuedSpinner === null) {
queuedSpinner = wait('Queued...');
queuedSpinner =
event.payload.readyState === 'QUEUED'
? wait('Queued...')
: wait('Building...');
}
}
@@ -200,15 +200,6 @@ export default async function processDeployment({
debug(
`Total files ${event.payload.total.size}, ${event.payload.missing.length} changed`
);
if (!quiet) {
log(
`Synced ${pluralize(
'file',
event.payload.missing.length,
true
)} ${uploadStamp()}`
);
}
const missingSize = event.payload.missing
.map((sha: string) => event.payload.total.get(sha).data.length)
@@ -239,6 +230,13 @@ export default async function processDeployment({
now._host = event.payload.url;
if (!quiet) {
log(
`Synced ${pluralize(
'file',
event.payload.missing.length,
true
)} ${uploadStamp()}`
);
const version = isLegacy ? `${chalk.grey('[v1]')} ` : '';
log(`${event.payload.url} ${version}${deployStamp()}`);
} else {

View File

@@ -1,4 +1,3 @@
import chalk from 'chalk';
import execa from 'execa';
import semver from 'semver';
import pipe from 'promisepipe';
@@ -8,7 +7,6 @@ import { extract } from 'tar-fs';
import { createHash } from 'crypto';
import { createGunzip } from 'zlib';
import { join, resolve } from 'path';
import { funCacheDir } from '@zeit/fun';
import { PackageJson } from '@now/build-utils';
import XDGAppPaths from 'xdg-app-paths';
import {
@@ -17,7 +15,6 @@ import {
readFile,
readJSON,
writeFile,
remove,
} from 'fs-extra';
import pkg from '../../../package.json';
@@ -296,6 +293,7 @@ export async function updateBuilders(
if (!builderDir) {
builderDir = await builderDirPromise;
}
const packages = Array.from(packagesSet);
const yarnPath = join(yarnDir, 'yarn');
const buildersPkgPath = join(builderDir, 'package.json');

View File

@@ -526,9 +526,12 @@ export default class DevServer {
// no builds -> zero config
if (!config.builds || config.builds.length === 0) {
const { projectSettings } = config;
const { builders, warnings, errors } = await detectBuilders(files, pkg, {
tag: getDistTag(cliVersion) === 'canary' ? 'canary' : 'latest',
functions: config.functions,
...(projectSettings ? { projectSettings } : {}),
});
if (errors) {
@@ -541,10 +544,11 @@ export default class DevServer {
}
if (builders) {
const { defaultRoutes, error: routesError } = await detectRoutes(
files,
builders
);
const {
defaultRoutes,
redirectRoutes,
error: routesError,
} = await detectRoutes(files, builders);
config.builds = config.builds || [];
config.builds.push(...builders);
@@ -553,8 +557,12 @@ export default class DevServer {
this.output.error(routesError.message);
await this.exit();
} else {
config.routes = config.routes || [];
config.routes.push(...(defaultRoutes as RouteConfig[]));
const routes: RouteConfig[] = [];
const { routes: nowConfigRoutes } = config;
routes.push(...(redirectRoutes || []));
routes.push(...(nowConfigRoutes || []));
routes.push(...(defaultRoutes || []));
config.routes = routes;
}
}
}

View File

@@ -8,62 +8,10 @@ import {
trailingSlashSchema,
} from '@now/routing-utils';
import { NowConfig } from './types';
import { functionsSchema, buildsSchema } from '@now/build-utils';
const ajv = new Ajv();
const buildsSchema = {
type: 'array',
minItems: 0,
maxItems: 128,
items: {
type: 'object',
additionalProperties: false,
required: ['use'],
properties: {
src: {
type: 'string',
minLength: 1,
maxLength: 4096,
},
use: {
type: 'string',
minLength: 3,
maxLength: 256,
},
config: { type: 'object' },
},
},
};
const functionsSchema = {
type: 'object',
minProperties: 1,
maxProperties: 50,
additionalProperties: false,
patternProperties: {
'^.{1,256}$': {
type: 'object',
additionalProperties: false,
properties: {
runtime: {
type: 'string',
maxLength: 256,
},
memory: {
enum: Object.keys(Array.from({ length: 50 }))
.slice(2, 48)
.map(x => Number(x) * 64),
},
maxDuration: {
type: 'number',
minimum: 1,
maximum: 900,
},
},
},
},
};
const validateBuilds = ajv.compile(buildsSchema);
const validateRoutes = ajv.compile(routesSchema);
const validateCleanUrls = ajv.compile(cleanUrlsSchema);

View File

@@ -1097,7 +1097,7 @@ export class LambdaSizeExceededError extends NowError<
size
).toLowerCase()}) exceeds the maximum size limit (${bytes(
maxLambdaSize
).toLowerCase()}). Learn more: https://zeit.co/docs/v2/deployments/concepts/lambdas/#maximum-bundle-size`,
).toLowerCase()}).`,
meta: { size, maxLambdaSize },
});
}

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