Compare commits

...

75 Commits

Author SHA1 Message Date
Joe Haddad
fb4d4b5953 Publish Stable
- @now/build-utils@2.1.0
 - @now/next@2.4.0
 - @now/routing-utils@1.7.0
2020-02-28 10:19:47 -05:00
Joe Haddad
de3701c045 Publish Canary
- @now/ruby@1.0.3-canary.1
2020-02-28 10:18:46 -05:00
m5o
9f9b7934cb [now-ruby] Fix ruby test indentation (#3854)
* fix ruby indentation example
  * 💅 indent with 2 spaces for consistency
2020-02-28 14:34:47 +00:00
Steven
bcded1dd17 Publish Canary
- @now/build-utils@2.0.1-canary.3
 - @now/next@2.3.19-canary.2
 - @now/python@1.1.5-canary.1
2020-02-28 08:57:36 -05:00
Steven
8503af75ba [now-python] Fix space encoding 2020-02-28 08:35:27 -05:00
Joe Haddad
158a50f1aa [now-next] Allow Immutable Fallback Artifact (#3850)
* [now-next] Allow Immutable Fallback Artifact

* trigger
2020-02-27 22:00:09 -05:00
Steven
61da552dd6 [now-build-utils] Add test for NODE_ENV behavior (#3852)
This PR adds a test for #3847.
2020-02-27 21:47:27 +00:00
Steven
fa838eecac Publish Canary
- @now/go@1.0.5-canary.0
 - @now/next@2.3.19-canary.1
 - @now/node@1.4.2-canary.0
 - @now/python@1.1.5-canary.0
 - @now/ruby@1.0.3-canary.0
 - @now/static-build@0.14.13-canary.1
2020-02-27 15:52:36 -05:00
Steven
71b6a58783 [all] Exclude @now/build-utils in bundled builder to fix tests (#3848)
This fixes a bug in our `@now/build-utils` tests that pair the current build-utils with a stable builder. Since ncc was bundling `@now/build-utils`, we weren't able to configure a different version and these tests were not actually testing the correct version of build-utils.

A nice side-effect is that each builder will be about 50% smaller (compared by measuring `dist`).
2020-02-27 15:48:03 -05:00
Joe Haddad
22dd78e286 Publish Canary
- @now/build-utils@2.0.1-canary.2
 - @now/next@2.3.19-canary.0
2020-02-27 12:35:52 -05:00
Joe Haddad
e63fcf2630 [now-next] Add Support for Prerender v2 (#3845)
* [now-next] Add Support for Prerender v2

* Copy test suite

* Test that fallback doesn't work for fallback: false

* record omitted lambdas

* Improve test case

* improve omitted routes logic

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2020-02-27 12:33:31 -05:00
Steven
98e1553c2e [now-build-utils] Install all deps regardless of NODE_ENV (#3847)
Some build utilities and SSG Frameworks instruct users to set `NODE_ENV=production` which typically means updating `now.json` to the following:

```json
{
  "build": {
    "env": {
      "NODE_ENV": "production"
    }
  }
}
```

The problem is that this environment variable is assigned during `npm install` or `yarn install` which is the equivalent of running install with the `--production` flag. This flag prevents `devDependencies` from installing. This is almost never what the user intends so they have to remove `now.json` and instead updating their build script to `NODE_ENV=production yarn build`.

This PR improves the experience by deleting `NODE_ENV` during the install step.
2020-02-27 12:14:06 -05:00
Steven
4dc506f17a Publish Canary
- @now/build-utils@2.0.1-canary.1
 - now@17.0.5-canary.5
 - @now/routing-utils@1.6.1-canary.1
2020-02-27 08:05:05 -05:00
Steven
3b396f29e9 [now-build-utils][now-routing-utils] Fix appendRoutesToPhase() when input is null (#3843)
This PR fixes `@now/routing-utils` when the input routes are null. It used to return the empty array but now it will still append.

I also added many more tests to `@now/build-utils` when `featureHandleMiss: true` and refactored the code a bit to make dynamic routes and api routes a little more clear.
2020-02-26 23:30:50 +00:00
JJ Kasper
1f128e69e6 Publish Stable
- @now/next@2.3.18
2020-02-26 15:56:41 -06:00
JJ Kasper
f1487c92cb Publish Canary
- now@17.0.5-canary.4
 - @now/next@2.3.18-canary.0
2020-02-26 15:51:27 -06:00
JJ Kasper
45066cdf44 [now-next] Add /_next/data routes for getServerProps pages (#3771)
This adds the `/_next/data` routes for `getServerProps` pages if they exist

x-ref: https://github.com/zeit/next.js/pull/10077
x-ref: https://github.com/zeit/next.js/pull/10622
2020-02-26 21:47:51 +00:00
Ana Trajkovska
7dde9c8207 Publish Canary
- now@17.0.5-canary.3
 - now-client@7.0.1-canary.1
2020-02-26 08:00:09 +01:00
Ana Trajkovska
fd964f825d Handle deployment cancellation (#3823)
Co-authored-by: Max <8418866+rdev@users.noreply.github.com>
2020-02-26 07:21:27 +01:00
Steven
1656c9874e Publish Canary
- @now/build-utils@2.0.1-canary.0
 - now@17.0.5-canary.2
 - @now/routing-utils@1.6.1-canary.0
2020-02-25 17:32:37 -05:00
Steven
d999a3b2ad [now-routing-utils][now-build-utils] Refactor zero-config rewrites (#3832)
This PR refactors the rewrites (the dynamic routes as well as the route that prevents directory listing for zero config deployments) so they are not in the `handle: miss` phase.

This is necessary because the behavior of `handle: miss` will change in an upcoming release.

The solution is to separate these into `rewriteRoutes` that can then be merged properly with the user's routes. They will be appended to the `handle: filesystem` phase (or add the phase if it doesn't exist).
2020-02-25 22:30:36 +00:00
Joe Haddad
cfb7c9e632 Publish Stable
- @now/next@2.3.17
2020-02-25 15:19:05 -05:00
Joe Haddad
06e8472cf7 Publish Canary
- now@17.0.5-canary.1
 - @now/next@2.3.17-canary.0
 - @now/static-build@0.14.13-canary.0
2020-02-25 14:57:42 -05:00
Joe Haddad
92404135d8 [now-next] Always Emit Prerenders (#3837)
This ensures we always emit Prerender objects for bypass tokens.
2020-02-25 19:51:07 +00:00
Nathan Rajlich
8b5cc23d7c [now-cli] Remove v1 "static build" integration tests (#3833)
* [now-cli] Remove v1 "static build" integration tests

These are the last remaining v1 static type deployments being created.

* Remove from `integration.js` as well

Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
2020-02-24 17:19:22 -08:00
Shu Uesugi
e10b42bfdc Rename zeit.co/new → zeit.co/import (#3834)
* zeit.co/new → zeit.co/import

* Update docs URL
2020-02-25 01:35:12 +01:00
M. Heide
36f7ec4836 [examples] Fix Go build if Windows Git is configured to checkout CRLF line endings (#3821)
Fixes #3820
2020-02-24 19:53:15 +00:00
Joe Haddad
f89d1c463e Remove Backticks from URL Output (#3830)
![image](https://user-images.githubusercontent.com/616428/75176976-44434880-5703-11ea-8ca5-cb49e4a921cf.png)

![image](https://user-images.githubusercontent.com/616428/75176982-473e3900-5703-11ea-90f6-b31844a486ce.png)
2020-02-24 19:22:58 +00:00
Steven
5dc652eba9 Publish Canary
- now@17.0.5-canary.0
 - now-client@7.0.1-canary.0
2020-02-24 12:53:13 -05:00
Steven
821b2bd50b [now-client] Fix root directory with trailing slash (#3827)
There was a bug in `now-client` when deploying a directory that ends with a slash, for example `/Users/styfle/Code/myapp/` instead of the usual `/Users/styfle/Code/myapp`.

This never affected `now-cli` until we added support for defining the `rootDirectory` which allows the user to type whatever they wish in the Project Settings.

The fix is to use `path.relative()` instead of substring.
2020-02-24 17:45:10 +00:00
Steven
8d5f6f1fa3 Publish Stable
- @now/frameworks@0.0.10
 - @now/build-utils@2.0.0
 - now@17.0.4
 - @now/go@1.0.4
 - @now/next@2.3.16
 - @now/python@1.1.4
 - @now/routing-utils@1.6.0
2020-02-21 18:09:20 -05:00
Steven
617f610c07 [tests] Update cancel workflow (#3817)
Update to latest version, [0.2.0](https://github.com/styfle/cancel-workflow-action/releases/tag/0.2.0), which will fix cancelling on push.

Also this action is available in the [marketplace](https://github.com/marketplace/actions/cancel-workflow-action).
2020-02-21 18:00:27 -05:00
Steven
3229ba0106 Publish Canary
- @now/go@1.0.4-canary.3
 - @now/python@1.1.4-canary.1
2020-02-21 17:27:20 -05:00
Steven
d16a6e4716 [now-go] Fix path segments in now dev (#3816)
The combination of file renaming and brackets doesn't work well for go build so we need to add the file extension back before building.

I also simplified the `.now/cache/folder` logic because it should be the same whether `builds` is defined or not (aka zero config).
2020-02-21 22:25:44 +00:00
Steven
4e5156fb0b [now-python] Fix path segments in now dev (#3815)
The combination of file renaming and brackets doesn't work well for python imports so we need too add the file extension back before importing the python module.

I also simplified the `.now/cache/folder` logic because it should be the same whether `builds` is defined or not (aka zero config).
2020-02-21 20:45:41 +00:00
Joe Haddad
3c013cc36b Publish Canary
- @now/build-utils@2.0.0-canary.2
 - @now/next@2.3.16-canary.1
2020-02-21 11:06:44 -05:00
Joe Haddad
1ed83135be Add Bypass Token to Next.js Builder (#3811)
This pull request adds the bypass token to returned `Prerender` output objects.

There's no tests as this doesn't exist in production yet.
2020-02-21 16:05:22 +00:00
Joe Haddad
0e71ff2df1 [now-build-utils] Add bypassToken to Prerender for iSSG (#3810)
This pull request adds a new `bypassToken` field to the `Prerender` output.

The field is required to be at least 128 bits for security reasons!
2020-02-20 01:59:45 +00:00
JJ Kasper
d8e98ee476 Publish Canary
- @now/next@2.3.16-canary.0
 - @now/routing-utils@1.5.4-canary.0
2020-02-19 16:23:25 -06:00
JJ Kasper
1bc1e8a9b1 [now-routing-utils] Update to not pass used segments in redirect query (#3809)
This updates to not pass segments already used in a redirect's destination query since these values are most likely unwanted and can still be manually added if desired. This change does not affect rewrites and we still pass through all segments in the query
2020-02-19 22:13:36 +00:00
JJ Kasper
274fdeb49a Publish Stable
- @now/next@2.3.15
2020-02-19 15:02:21 -06:00
JJ Kasper
d15c90b42f Publish Canary
- now@17.0.4-canary.3
 - @now/next@2.3.15-canary.0
2020-02-19 14:57:20 -06:00
JJ Kasper
5be2917c47 [now-next] Update 404 handling for pages/404 (#3697)
This adds handling for treating `pages/404.js` as the custom error page in Next.js to allow for more flexible auto static optimization on the 404 page. This makes sure we handle `pages/404.js` being a lambda due to `_app` having `getInitialProps` and also makes sure that visiting `/404` doesn't respond with a 200 status code

~We can add tests for this behavior after the below PR has been released in a canary of Next.js~

x-ref: https://github.com/zeit/next.js/pull/10329
x-ref: https://github.com/zeit/next.js/pull/10593
2020-02-19 20:55:26 +00:00
dependabot[bot]
5f08b24546 Bump codecov from 3.1.0 to 3.6.5 (#3807)
Bumps [codecov](https://github.com/codecov/codecov-node) from 3.1.0 to 3.6.5.
<details>
<summary>Release notes</summary>

*Sourced from [codecov's releases](https://github.com/codecov/codecov-node/releases).*

> ## v3.6.4
> Fix for Cirrus CI
> 
> ## v3.6.3
> AWS Codebuild fixes + package updates
> 
> ## v3.6.2
> command line args sanitised
> 
> ## v3.6.1
> Fix for Semaphore
> 
> ## v3.6.0
> AWS CodeBuild
> Semaphore v2
> 
> ## v3.3.0
> Added pipe `--pipe`, `-l`
</details>
<details>
<summary>Commits</summary>

- See full diff in [compare view](https://github.com/codecov/codecov-node/commits)
</details>
<details>
<summary>Maintainer changes</summary>

This version was pushed to npm by [drazisil](https://www.npmjs.com/~drazisil), a new releaser for codecov since your current version.
</details>
<br />

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=codecov&package-manager=npm_and_yarn&previous-version=3.1.0&new-version=3.6.5)](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 close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor 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>
2020-02-19 20:19:49 +00:00
Steven
cc3026ffcb [tests] Fix builder debug flag (#3805)
When testing, you can set `NOW_BUILDER_DEBUG=1` to print verbose logs from builders.

However, this was causing some tests to fail that depended on a build environment variable.

This PR fixes the assignment so that it preserves the environment variables from the tests by adding `NOW_BUILDER_DEBUG` instead of replacing.
2020-02-18 22:57:17 +00:00
JJ Kasper
8cb6e56679 Publish Stable
- @now/next@2.3.14
2020-02-17 14:28:07 -06:00
JJ Kasper
7da5ff4b1d Publish Canary
- now@17.0.4-canary.2
 - @now/next@2.3.14-canary.1
2020-02-17 11:45:53 -06:00
JJ Kasper
5d1069d464 [now-next] Make sure to 404 and clear cache header for invalid _next requests (#3801)
This handles an edge case where deeply nested dynamic routes were handling `_next` 404s that were cached forever since the immutable header we set isn't cleared after not matching on the filesystem.

I updated our cache-header fixture to check for this edge case also to make sure we don't regress on this
2020-02-17 17:42:51 +00:00
Andy
6e1a72f557 [examples] Use Full URL for Logos (#3800)
Use Full URL for Logos

[PRODUCT-1193]

[PRODUCT-1193]: https://zeit.atlassian.net/browse/PRODUCT-1193
2020-02-17 13:44:35 +00:00
dependabot[bot]
6f97a2cc7a Bump yarn from 1.17.3 to 1.22.0 (#3796)
Bumps [yarn](https://github.com/yarnpkg/yarn) from 1.17.3 to 1.22.0.
<details>
<summary>Changelog</summary>

*Sourced from [yarn's changelog](https://github.com/yarnpkg/yarn/blob/master/CHANGELOG.md).*

> # Changelog
> 
> Please add one entry in this file for each change in Yarn's behavior. Use the same format for all entries, including the third-person verb. Make sure you don't add more than one line of text to keep it clean. Thanks!
> 
> ## Master
> 
> - Passes arguments following `--` when running a workspace script (`yarn workspace pkg run command -- arg`)
> 
>   [#7776](https://github-redirect.dependabot.com/yarnpkg/yarn/pull/7776) - [**Jeff Valore**](https://twitter.com/rally25rs)
> 
> - Prints workspace names with `yarn workspaces` (silence with `-s`)
> 
>   [#7722](https://github-redirect.dependabot.com/yarnpkg/yarn/pull/7722) - [**Orta**](https://twitter.com/orta)
> 
> - Implements `yarn init --install <version>`
> 
>   [#7723](https://github-redirect.dependabot.com/yarnpkg/yarn/pull/7723) - [**Maël Nison**](https://twitter.com/arcanis)
>   
> - Implements `yarn init -2`
> 
>   [#7862](https://github-redirect.dependabot.com/yarnpkg/yarn/pull/7862) - [**Maël Nison**](https://twitter.com/arcanis)
> 
> - Implements `yarn set version <version>` as an alias for `policies set-version`
> 
>   [#7862](https://github-redirect.dependabot.com/yarnpkg/yarn/pull/7862) - [**Maël Nison**](https://twitter.com/arcanis)
> 
> - Fixes an issue where the archive paths were incorrectly sanitized
> 
>   [#7831](https://github-redirect.dependabot.com/yarnpkg/yarn/pull/7831) - [**Maël Nison**](https://twitter.com/arcanis)
> 
> - Allows some dots in binary names again
> 
>   [#7811](https://github-redirect.dependabot.com/yarnpkg/yarn/pull/7811) - [**Valery Bugakov**](https://github.com/valerybugakov)
>   
> - Better error handling on `yarn set version`
> 
>   [#7848](https://github-redirect.dependabot.com/yarnpkg/yarn/pull/7848) - [**Nick Olinger**](https://github.com/olingern)
> 
> ## 1.19.2
> 
> - Folders like `.cache` won't be pruned from the `node_modules` after each install.
> 
>   [#7699](https://github-redirect.dependabot.com/yarnpkg/yarn/pull/7699) - [**Maël Nison**](https://twitter.com/arcanis)
> 
> - Correctly installs workspace child dependencies when workspace child not symlinked to root.
> 
>   [#7289](https://github-redirect.dependabot.com/yarnpkg/yarn/pull/7289) - [**Daniel Tschinder**](https://github.com/danez)
> 
> - Makes running scripts with Plug'n Play possible on node 13.
> 
></tr></table> ... (truncated)
</details>
<details>
<summary>Commits</summary>

- [`eee67d0`](eee67d02ed) v1.22.0
- [`6971622`](69716228e9) Update CHANGELOG.md
- [`0e7133c`](0e7133ca28) Fixes arbitrary file write on fetch ([#7831](https://github-redirect.dependabot.com/yarnpkg/yarn/issues/7831))
- [`fa613f3`](fa613f3a71) handle failed policy set-version ([#7848](https://github-redirect.dependabot.com/yarnpkg/yarn/issues/7848))
- [`f381c5f`](f381c5f0ce) Implements set version ([#7862](https://github-redirect.dependabot.com/yarnpkg/yarn/issues/7862))
- [`d2c3a48`](d2c3a485e0) Configure bug report issue template ([#7844](https://github-redirect.dependabot.com/yarnpkg/yarn/issues/7844))
- [`af4c205`](af4c2056a3) Allow dots in bin names ([#7811](https://github-redirect.dependabot.com/yarnpkg/yarn/issues/7811))
- [`1b334e6`](1b334e687b) fix(workspaces): Pass args following "--" when running workspace scripts ([#7786](https://github-redirect.dependabot.com/yarnpkg/yarn/issues/7786))
- [`2c8e97e`](2c8e97eaf3) Fix suggestions for CLI ([#7808](https://github-redirect.dependabot.com/yarnpkg/yarn/issues/7808))
- [`039bafd`](039bafd74b) Fixes bin overwrites ([#7755](https://github-redirect.dependabot.com/yarnpkg/yarn/issues/7755))
- Additional commits viewable in [compare view](https://github.com/yarnpkg/yarn/compare/v1.17.3...v1.22.0)
</details>
<details>
<summary>Maintainer changes</summary>

This version was pushed to npm by [daniel15](https://www.npmjs.com/~daniel15), a new releaser for yarn since your current version.
</details>
<br />

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=yarn&package-manager=npm_and_yarn&previous-version=1.17.3&new-version=1.22.0)](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 close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor 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>
2020-02-15 01:56:34 +00:00
Steven
6e402bffc3 Publish Canary
- now@17.0.4-canary.1
 - @now/go@1.0.4-canary.2
 - @now/next@2.3.14-canary.0
2020-02-14 15:05:00 -05:00
Steven
e41d0f8e68 [now-go] Fix /api/go.sum detection (#3795)
Follow up to #3793 

The `go.mod` and `go.sum` file must both be moved.
2020-02-14 19:58:44 +00:00
Steven
1a046744f2 [now-go] Add support for root go.mod in api directory (#3793)
Some users wish to put all Go related code in the `/api` directory and the root is reserved for a frontend framework.

This PR adds support for `/api/go.mod` which will act the same as `/go.mod` by moving the file to the root.
2020-02-14 17:32:20 +00:00
Andy
a9bf011f2c [api] Add rewrite to frameworks API (#3794)
* [api] Add rewrite to frameworks API

* Adjust now.json

* Change output file
2020-02-14 00:30:58 +01:00
JJ Kasper
60c76b3290 [now-next] Add support for using the fallback file for dynamic SSG pages (#3752)
This adds support for using the fallback file for dynamic (lazy) SSG pages to allow showing a loading state while the cache is populated with data. We can add tests for this behavior once the below referenced PR is shipped on canary

x-ref: https://github.com/zeit/next.js/pull/10424

~Update: added tests now that fallback support has landed in Next.js although it appears `now-proxy` might need to be updated to revalidate the fallback correctly since the initial fallback is always being shown for lazy SSG pages with these changes~

Looks like this is working properly in `now-proxy` and we were overriding the prerender output with the static page output, thanks @juancampa for helping investigate! 🙏
2020-02-13 01:06:55 +00:00
Steven
c7ff1e7044 [now-cli] Update ZEIT Logo (#3790)
This PR updates the logo to match https://zeit.co/home
2020-02-12 10:17:54 -05:00
Andy Bitz
e2deaef54a Publish Canary
- @now/frameworks@0.0.10-canary.0
2020-02-12 14:46:11 +01:00
Andy
b2c7386c83 [frameworks] Adjust Next.js build command placeholder (#3788) 2020-02-12 14:34:09 +01:00
Steven
3dce84c3cf Publish Canary
- @now/go@1.0.4-canary.1
2020-02-11 16:46:21 -05:00
Steven
443b1ac158 [now-go] Fix path segments with square brackets (#3782)
Previously, `@now/go` would fail when using [Path Segments](https://zeit.co/docs/v2/serverless-functions/introduction#path-segments) since `go build` [doesn't support](https://stackoverflow.com/q/60140859/266535) files that begin with square bracket.

This PR changes the build logic so that the entrypoint file is renamed if if begins with a square bracket.

The output file is not renamed because v3 builders can't rename outputs which works great for this feature.
2020-02-11 21:41:57 +00:00
Andy Bitz
be3dca3d94 Publish Canary
- @now/build-utils@2.0.0-canary.1
 - now@17.0.4-canary.0
 - @now/go@1.0.4-canary.0
 - @now/python@1.1.4-canary.0
2020-02-11 16:50:13 +01:00
Andy Bitz
cb135e4329 [now-build-utils] Bump version 2020-02-11 16:50:01 +01:00
Andy
55c73b68bb [now-build-utils][now-cli] Refactor builds and routes detection (#3784)
* [now-build-utils] Refactor detect builds

* Refactor routes detection

* [now-cli] Adjust `now dev`

* Adjust tests

* Adjust integrations test

* Remove unused file

* Replace reducw with for-loop

* Add cache for absolute paths

* Filter while looping

* Add fallback for entrypoint with buildCommand
2020-02-11 16:47:39 +01:00
Steven
eb793ba139 [tests] Add windows to CI unit tests (#3727)
This adds initial support for Windows in GitHub Actions CI tests.

There is still work to be done to prevent certain tests from hanging in CI so those are skipped for now.
2020-02-11 01:16:14 +00:00
Steven
00908e8ebe [now-python] Fix path segments with square brackets (#3781)
Previously, python would fail when using [Path Segments](https://zeit.co/docs/v2/serverless-functions/introduction#path-segments) as seen in #3729.

This PR changes the import logic so that the entrypoint file is [imported as a relative file path](https://stackoverflow.com/a/67692/266535) instead of by module name.
2020-02-10 21:01:31 +00:00
Leo Lamprecht
5ce7ff86a4 Minor tweaks for CONTRIBUTING.md file (#3778)
* Minor tweaks for CONTRIBUTING.md file

* Update CONTRIBUTING.md

* Update CONTRIBUTING.md
2020-02-10 18:34:00 +01:00
Steven
4b34ee2993 [examples] Remove outdated jekyll build section from README (#3780)
We used to require a `package.json` but we have since introduced [Advanced Project Settings](https://zeit.co/blog/advanced-project-settings) which will ask the user for a build command during the first deploy.
2020-02-10 15:31:52 +00:00
Andi
646bd288ba [now-go] Update go to version 1.13.7 (#3750)
Updates go to the latest version 1.13.7 (https://golang.org/doc/devel/release.html#go1.13). This allows users to use the new error functionality that was introduced in go 1.13 (https://blog.golang.org/go1.13-errors) and also includes a couple of security fixes.

Looking at the last PR that updated the version (https://github.com/zeit/now-builders/pull/247/files) this should be as simple as updating the version number.

P.S. I tried to follow the contribution guidelines, but `yarn lint` fails with `exit code 1`/`295 problems (33 errors, 262 warnings)` and `yarn test` returns `error Command "test" not found` on master. But `yarn test-unit` shows no errors.
2020-02-08 01:47:47 +00:00
Steven
8aba6f1ff8 Publish Stable
- now@17.0.3
2020-02-07 20:01:17 -05:00
Steven
35e5e328aa Publish Canary
- now@17.0.3-canary.1
2020-02-07 19:18:47 -05:00
Andy
bdd4953d62 [now-cli] Consider root directory for now.json (#3764)
* [now-cli] Consider root directory for now.json

* Adjust message check in test

* Fallback if config does not exist as well

* Assign localConfig later and add debug

* Prefere now.json from root directory

* Comment

* Adjust test and add warning
2020-02-08 01:04:34 +01:00
Steven
e938b298e2 [now-cli] Fix port assignment for now dev (#3769)
This fixes a regression from #3749 where the PORT env var was removed. This is necessary so frameworks like create-react-app and gatsby can proxy to `now dev`.

Fixes #3761
2020-02-07 19:03:56 -05:00
Andy
b67f324e10 [api] Add hasDetectors property (#3770) 2020-02-08 00:29:11 +01:00
Andy Bitz
1dfa286af5 Publish Canary
- now@17.0.3-canary.0
2020-02-07 21:14:50 +01:00
Andy
d4391bd4cc [now-cli] Fix chalk template for legacy (#3768)
* [now-cli] Fix chalk template for legacy

* Update packages/now-cli/src/commands/deploy/legacy.ts

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

Co-authored-by: Nathan Rajlich <n@n8.io>
2020-02-07 21:14:11 +01:00
205 changed files with 4834 additions and 1953 deletions

4
.gitattributes vendored
View File

@@ -1,3 +1,7 @@
# Ignore test fixtures in GitHub Languages
# See https://github.com/github/linguist#vendored-code
packages/*/test/* linguist-vendored
# Go build fails with Windows line endings.
*.go text eol=lf
go.mod text eol=lf

View File

@@ -97,13 +97,9 @@ Sometimes you want to test changes to a Builder against an existing project, may
## Add a New Framework
You can add support for a new framework by creating a Pull Request for this repository by following the steps below.
You can add support for a new Framework by creating a Pull Request for this repository and following the steps below:
1. Add the framework to the `@now/frameworks` package.
The file is located in `packages/frameworks/frameworks.json`. You can copy the structure of an existing one and adjust the required fields. Note that the `settings` property either contains a `value` or a `placeholder`. The `value` property is used when something is not configurable, the `placeholder` is used when something is configurable and can be changed with configuration. An example would be the output directory for Hugo, it's `public` by default but can be changed through its config file, so we use `placeholder` with an explanation of what can be used.
2. Add an example to the `examples/` directory.
The name of the directory should equal the slug of the framework used in `@now/frameworks`.
The `.github/EXAMPLE_README_TEMPLATE.md` file can be used to create a README for the example.
3. Update the `@now/static-build` package
The files `packages/now-static-build/src/frameworks.ts` has to be extended. You can add default routes that will always be applied to projects that use this framework or specify some paths that will be cached to speed up the build process.
4. After your PR has been merged and released other users can use `now init` to get the example and deploy it to ZEIT Now.
1. Add the Framework to the `@now/frameworks` package: The file is located in `packages/frameworks/frameworks.json`. You can copy the structure of an existing one and adjust the required fields. Note that the `settings` property either contains a `value` or a `placeholder`. The `value` property is used when something is not configurable, the `placeholder` is used when something is configurable and can be changed with configuration. An example would be the Output Directory for Hugo, it's `public` by default but can be changed through its config file, so we use `placeholder` with an explanation of what can be used.
2. Add an example to the `examples/` directory: The name of the directory should equal the slug of the framework used in `@now/frameworks`. The `.github/EXAMPLE_README_TEMPLATE.md` file can be used to create a `README.md` file for the example.
3. Update the `@now/static-build` package: The file `packages/now-static-build/src/frameworks.ts` has to be extended. You can add default routes that will always be applied to projects that use this Framework or specify some paths that will be cached to speed up the build process.
4. After your Pull Request has been merged and released, other users can select the example on the ZEIT Now dashboard and deploy it.

View File

@@ -6,7 +6,7 @@ This directory is a brief example of a [Name](site-link) site that can be deploy
Deploy your own [Name] project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now-examples/tree/master/example-directory)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now-examples/tree/master/example-directory)
### How We Created This Example

View File

@@ -4,13 +4,14 @@ on:
branches:
- '*'
- '!master'
jobs:
cancel:
name: 'Cancel Previous Runs'
runs-on: ubuntu-latest
timeout-minutes: 3
steps:
- uses: styfle/cancel-workflow-action@master
- uses: styfle/cancel-workflow-action@0.2.0
with:
workflow_id: 435869
access_token: ${{ secrets.GITHUB_WORKFLOW_TOKEN }}

View File

@@ -15,7 +15,7 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest]
os: [ubuntu-latest, macos-latest, windows-latest]
node: [10, 12]
runs-on: ${{ matrix.os }}
steps:
@@ -23,7 +23,8 @@ jobs:
- run: git fetch origin master --depth=10
- run: git fetch origin ${{ github.ref }} --depth=10
- uses: actions/setup-node@v1
- run: yarn install && yarn run build
- run: yarn install
- run: yarn run build
- run: yarn run test-lint
- run: yarn run test-unit --clean false
- name: Upload Artifact
@@ -41,7 +42,8 @@ jobs:
- uses: actions/checkout@v2
- run: git fetch origin master --depth=10
- run: git fetch origin ${{ github.ref }} --depth=10
- run: yarn install && yarn run build
- run: yarn install
- run: yarn run build
- run: yarn test-integration-once --clean false
test-now-cli:
@@ -57,8 +59,11 @@ jobs:
- uses: actions/checkout@v2
- run: git fetch origin master --depth=10
- run: git fetch origin ${{ github.ref }} --depth=10
- run: curl -L -O https://github.com/gohugoio/hugo/releases/download/v0.56.0/hugo_0.56.0_macOS-64bit.tar.gz && tar -xzf hugo_0.56.0_macOS-64bit.tar.gz && mv ./hugo packages/now-cli/test/dev/fixtures/08-hugo/
- run: yarn install && yarn run build
- name: Install Hugo
if: matrix.os == 'macos-latest'
run: curl -L -O https://github.com/gohugoio/hugo/releases/download/v0.56.0/hugo_0.56.0_macOS-64bit.tar.gz && tar -xzf hugo_0.56.0_macOS-64bit.tar.gz && mv ./hugo packages/now-cli/test/dev/fixtures/08-hugo/
- run: yarn install
- run: yarn run build
- uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node }}
@@ -77,8 +82,11 @@ jobs:
- uses: actions/checkout@v2
- run: git fetch origin master --depth=10
- run: git fetch origin ${{ github.ref }} --depth=10
- run: curl -L -O https://github.com/gohugoio/hugo/releases/download/v0.56.0/hugo_0.56.0_macOS-64bit.tar.gz && tar -xzf hugo_0.56.0_macOS-64bit.tar.gz && mv ./hugo packages/now-cli/test/dev/fixtures/08-hugo/
- run: yarn install && yarn run build
- name: Install Hugo
if: matrix.os == 'macos-latest'
run: curl -L -O https://github.com/gohugoio/hugo/releases/download/v0.56.0/hugo_0.56.0_macOS-64bit.tar.gz && tar -xzf hugo_0.56.0_macOS-64bit.tar.gz && mv ./hugo packages/now-cli/test/dev/fixtures/08-hugo/
- run: yarn install
- run: yarn run build
- uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node }}

View File

@@ -1,4 +1,4 @@
![now](https://assets.zeit.co/image/upload/v1542240976/repositories/now-cli/now-cli-repo-banner-v3.png)
![now](https://assets.zeit.co/image/upload/v1581518533/repositories/now-cli/v4.png)
[![CI Status](https://badgen.net/github/checks/zeit/now?label=CI)](https://github.com/zeit/now/actions?workflow=CI)
[![Join the community on Spectrum](https://withspectrum.github.io/badge/badge.svg)](https://spectrum.chat/zeit)
@@ -21,7 +21,7 @@ now # Deploy to the cloud
## Documentation
For details on how to use Now CLI, check out our [documentation](https://zeit.co/docs).
For details on how to use Now CLI, check out our [documentation](https://zeit.co/docs/now-cli).
## Caught a Bug?

View File

@@ -2,17 +2,19 @@ import { NowRequest, NowResponse } from '@now/node';
import { withApiHandler } from './_lib/util/with-api-handler';
import frameworkList, { Framework } from '../packages/frameworks';
const frameworks: Framework[] = (frameworkList as Framework[]).map(
framework => {
delete framework.detectors;
const frameworks = (frameworkList as Framework[]).map(frameworkItem => {
const framework = {
...frameworkItem,
hasDetectors: Boolean(frameworkItem.detectors),
detectors: undefined,
};
if (framework.logo) {
framework.logo = `https://res.cloudinary.com/zeit-inc/image/fetch/${framework.logo}`;
}
return framework;
}
);
});
export default withApiHandler(async function(
req: NowRequest,

View File

@@ -6,7 +6,7 @@ This directory is a brief example of an [AMP](https://amp.dev/) site that can be
Deploy your own AMP project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/amp)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/amp)
_Live Example: https://amp.now-examples.now.sh_

View File

@@ -1,4 +1,4 @@
![Angular Logo](../../packages/frameworks/logos/angular.svg)
![Angular Logo](https://github.com/zeit/now/blob/master/packages/frameworks/logos/angular.svg)
# Angular Example
@@ -8,7 +8,7 @@ This directory is a brief example of an [Angular](https://angular.io/) app that
Deploy your own Angular project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/angular)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/angular)
_Live Example: https://angular.now-examples.now.sh_

View File

@@ -6,7 +6,7 @@ This directory is a brief example of a [Assemble](http://assemble.io/) app that
Deploy your own Assemble project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/assemble)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/assemble)
_Live Example: https://assemble.now-examples.now.sh_

View File

@@ -6,7 +6,7 @@ This directory is a brief example of an [Aurelia](https://aurelia.io/) app that
Deploy your own Aurelia project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/aurelia)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/aurelia)
_Live Example: https://aurelia.now-examples.now.sh_

View File

@@ -6,7 +6,7 @@ This directory is a brief example of a [Brunch](https://brunch.io/) site that ca
Deploy your own Brunch project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/brunch)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/brunch)
_Live Example: https://brunch.now-examples.now.sh_

View File

@@ -6,7 +6,7 @@ This directory is a brief example of a [Charge.js](https://charge.js.org/) site
Deploy your own Charge.js project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/charge)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/charge)
_Live Example: https://charge.now-examples.now.sh_

View File

@@ -1,4 +1,4 @@
![React Logo](../../packages/frameworks/logos/react.svg)
![React Logo](https://github.com/zeit/now/blob/master/packages/frameworks/logos/react.svg)
# React Example
@@ -8,7 +8,7 @@ This directory is a brief example of a [React](https://reactjs.org/) app with [S
Deploy your own React project, along with Serverless Functions, with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/create-react-app-functions)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/create-react-app-functions)
_Live Example: https://create-react-app.now-examples.now.sh/_

View File

@@ -6,7 +6,7 @@ This directory is a brief example of using a Custom Build script that can be dep
Deploy your own Custom Built project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/custom-build)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/custom-build)
_Live Example: https://custom-build.now-examples.now.sh_

View File

@@ -1,4 +1,4 @@
![Docusaurus Logo](../../packages/frameworks/logos/docusaurus.svg)
![Docusaurus Logo](https://github.com/zeit/now/blob/master/packages/frameworks/logos/docusaurus.svg)
# Docusaurus Example
@@ -8,7 +8,7 @@ This directory is a brief example of a [Docusaurus](https://docusaurus.io/) site
Deploy your own Docusaurus project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/docusaurus)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/docusaurus)
_Live Example: https://docusaurus.now-examples.now.sh_

View File

@@ -6,7 +6,7 @@ This directory is a brief example of a [Docz](https://www.docz.site/) site that
Deploy your own Docz project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/docz)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/docz)
_Live Example: https://docz.now-examples.now.sh_

View File

@@ -1,4 +1,4 @@
![Eleventy Logo](../../packages/frameworks/logos/eleventy.svg)
![Eleventy Logo](https://github.com/zeit/now/blob/master/packages/frameworks/logos/eleventy.svg)
# Eleventy Example
@@ -8,7 +8,7 @@ This directory is a brief example of a [Eleventy](https://www.11ty.io/) site tha
Deploy your own Eleventy project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/eleventy)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/eleventy)
_Live Example: https://eleventy.now-examples.now.sh_

View File

@@ -1,4 +1,4 @@
![Ember Logo](../../packages/frameworks/logos/ember.svg)
![Ember Logo](https://github.com/zeit/now/blob/master/packages/frameworks/logos/ember.svg)
# Ember Example
@@ -8,7 +8,7 @@ This directory is a brief example of an [Ember](https://emberjs.com/) app that c
Deploy your own Ember project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/ember)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/ember)
_Live Example: https://ember.now-examples.now.sh_

View File

@@ -6,7 +6,7 @@ This directory is a brief example of a [Foundation](https://foundation.zurb.com/
Deploy your own Foundation project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/foundation)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/foundation)
_Live Example: https://foundation.now-examples.now.sh_

View File

@@ -1,4 +1,4 @@
![Gatsby Logo](../../packages/frameworks/logos/gatsby.svg)
![Gatsby Logo](https://github.com/zeit/now/blob/master/packages/frameworks/logos/gatsby.svg)
# Gatsby Example
@@ -8,7 +8,7 @@ This directory is a brief example of a [Gatsby](https://www.gatsbyjs.org/) app w
Deploy your own Gatsby project, along with Serverless Functions, with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/gatsby)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/gatsby)
_Live Example: https://gatsby.now-examples.now.sh_

View File

@@ -1,4 +1,4 @@
![Gridsome Logo](../../packages/frameworks/logos/gridsome.svg)
![Gridsome Logo](https://github.com/zeit/now/blob/master/packages/frameworks/logos/gridsome.svg)
# Gridsome Example
@@ -8,7 +8,7 @@ This directory is a brief example of a [Gridsome](https://gridsome.org/) app tha
Deploy your own Gridsome project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/gridsome)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/gridsome)
_Live Example: https://gridsome.now-examples.now.sh_

View File

@@ -1,4 +1,4 @@
![Hexo Logo](../../packages/frameworks/logos/hexo.svg)
![Hexo Logo](https://github.com/zeit/now/blob/master/packages/frameworks/logos/hexo.svg)
# Hexo Example
@@ -8,7 +8,7 @@ This directory is a brief example of a [Hexo](https://hexo.io/) site that can be
Deploy your own Hexo project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/hexo)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/hexo)
_Live Example: https://hexo.now-examples.now.sh_

View File

@@ -6,7 +6,7 @@ This directory is a brief example of a [Hugo](https://gohugo.io/) app that can b
Deploy your own Hugo project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/hugo)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/hugo)
_Live Example: https://hugo.now-examples.now.sh_

View File

@@ -6,7 +6,7 @@ This directory is a brief example of a [HyperApp](https://github.com/jorgebucara
Deploy your own HyperApp project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/hyperapp)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/hyperapp)
_Live Example: https://hyperapp.now-examples.now.sh_

View File

@@ -6,7 +6,7 @@ This directory is a brief example of an [Ionic React](https://ionicframework.com
Deploy your own Ionic React project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/ionic-react)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/ionic-react)
_Live Example: https://ionic-react.now-examples.now.sh_

View File

@@ -6,7 +6,7 @@ This directory is a brief example of a [Jekyll](https://jekyllrb.com/) site that
Deploy your own Jekyll project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/jekyll)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/jekyll)
_Live Example: https://jekyll.now-examples.now.sh_
@@ -25,18 +25,3 @@ You can deploy your new Jekyll project with a single command from your terminal
```shell
$ now
```
### Build Command
The default build command is `jekyll build`.
If you wish to change the build command, add a `package.json` file with the following:
```json
{
"private": true,
"scripts": {
"build": "jekyll build"
}
}
```

View File

@@ -6,7 +6,7 @@ This directory is a brief example of a [Marko.js](https://markojs.com/) app that
Deploy your own Marko.js project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/marko)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/marko)
_Live Example: https://marko.now-examples.now.sh_

View File

@@ -6,7 +6,7 @@ This directory is a brief example of a [mdx-deck](https://github.com/jxnblk/mdx-
Deploy your own mdx-deck project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/mdx-deck)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/mdx-deck)
_Live Example: https://mdx-deck.now-examples.now.sh_

View File

@@ -6,7 +6,7 @@ This directory is a brief example of a [Metalsmith](https://metalsmith.io/) app
Deploy your own Metalsmith project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/metalsmith)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/metalsmith)
_Live Example: https://metalsmith.now-examples.now.sh_

View File

@@ -6,7 +6,7 @@ This directory is a brief example of a [Middleman](https://middlemanapp.com/) si
Deploy your own Middleman project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/middleman)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/middleman)
_Live Example: https://middleman.now-examples.now.sh_

View File

@@ -6,7 +6,7 @@ This directory is a brief example of a [Mithril](https://mithril.js.org/) app th
Deploy your own Mithril project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/mithril)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/mithril)
_Live Example: https://mithril.now-examples.now.sh_

View File

@@ -6,7 +6,7 @@ This directory is a brief example of a [MkDocs](https://www.mkdocs.org/) site th
Deploy your own MkDocs project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/mkdocs)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/mkdocs)
_Live Example: https://mkdocs.now-examples.now.sh_

View File

@@ -1,4 +1,4 @@
![Next.js Logo](../../packages/frameworks/logos/next.svg)
![Next.js Logo](https://github.com/zeit/now/blob/master/packages/frameworks/logos/next.svg)
# Next.js Example
@@ -8,7 +8,7 @@ This directory is a brief example of a [Next.js](https://nextjs.org) app that ca
Deploy your own Next.js project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/nextjs)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/nextjs)
_Live Example: https://nextjs.now-examples.now.sh_

View File

@@ -6,7 +6,7 @@ This directory is a brief example of a [Nuxt.js](https://nuxtjs.org) app that ca
Deploy your own Nuxt.js project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/nuxtjs)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/nuxtjs)
_Live Example: https://nuxtjs.now-examples.now.sh_

View File

@@ -6,7 +6,7 @@ This directory is a brief example of a [Pelican](https://docs.getpelican.com/en/
Deploy your own Pelican project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/pelican)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/pelican)
_Live Example: https://pelican.now-examples.now.sh_

View File

@@ -1,4 +1,4 @@
![Polymer Logo](../../packages/frameworks/logos/polymer.svg)
![Polymer Logo](https://github.com/zeit/now/blob/master/packages/frameworks/logos/polymer.svg)
# Polymer Example
@@ -8,7 +8,7 @@ This directory is a brief example of a [Polymer](https://www.polymer-project.org
Deploy your own Polymer project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/polymer)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/polymer)
_Live Example: https://polymer.now-examples.now.sh_

View File

@@ -1,4 +1,4 @@
![Preact Logo](../../packages/frameworks/logos/preact.svg)
![Preact Logo](https://github.com/zeit/now/blob/master/packages/frameworks/logos/preact.svg)
# Preact Example
@@ -8,7 +8,7 @@ This directory is a brief example of a [Preact](https://preactjs.com/) app that
Deploy your own Preact project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/preact)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/preact)
_Live Example: https://preact.now-examples.now.sh_

View File

@@ -6,7 +6,7 @@ This directory is a brief example of a [Riot.js](https://riot.js.org/) app that
Deploy your own Riot.js project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/riot)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/riot)
_Live Example: https://riot.now-examples.now.sh_

View File

@@ -1,4 +1,4 @@
![Saber Logo](../../packages/frameworks/logos/saber.svg)
![Saber Logo](https://github.com/zeit/now/blob/master/packages/frameworks/logos/saber.svg)
# Saber Example
@@ -8,7 +8,7 @@ This directory is a brief example of a [Saber](https://saber.land) site that can
Deploy your own Saber project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/saber)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/saber)
_Live Example: https://saber.now-examples.now.sh_

View File

@@ -6,7 +6,7 @@ This directory is a brief example of a [Sapper](https://sapper.svelte.dev/) app
Deploy your own Sapper project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/sapper)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/sapper)
_Live Example: https://sapper.now-examples.now.sh_

View File

@@ -6,7 +6,7 @@ This directory is a brief example of a [Stencil](https://stenciljs.com/) app tha
Deploy your own Stencil project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/stencil)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/stencil)
_Live Example: https://stencil.now-examples.now.sh_

View File

@@ -6,7 +6,7 @@ This directory is a brief example of a [Storybook](https://storybook.js.org/) ap
Deploy your own Storybook project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/storybook)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/storybook)
_Live Example: https://storybook.now-examples.now.sh_

View File

@@ -6,7 +6,7 @@ This directory is a brief example of a [Svelte](https://svelte.dev/) app with [S
Deploy your own Svelte project, along with Serverless Functions, with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/svelte)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/svelte)
_Live Example: https://svelte.now-examples.now.sh_

View File

@@ -1,4 +1,4 @@
![UmiJS Logo](../../packages/frameworks/logos/umi.svg)
![UmiJS Logo](https://github.com/zeit/now/blob/master/packages/frameworks/logos/umi.svg)
# UmiJS Example
@@ -8,7 +8,7 @@ This directory is a brief example of a [UmiJS](https://umijs.org/) app that can
Deploy your own UmiJS project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/umijs)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/umijs)
_Live Example: https://umijs.now-examples.now.sh_

View File

@@ -6,7 +6,7 @@ This directory is a brief example of a vanilla site that can be deployed with ZE
Deploy your own vanilla website, along with Serverless Functions, with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/vanilla)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/vanilla)
_Live Example: https://vanilla.now-examples.now.sh_

View File

@@ -1,4 +1,4 @@
![Vue.js Logo](../../packages/frameworks/logos/vue.svg)
![Vue.js Logo](https://github.com/zeit/now/blob/master/packages/frameworks/logos/vue.svg)
# Vue.js Example
@@ -8,7 +8,7 @@ This directory is a brief example of a [Vue.js](https://vuejs.org/) app that can
Deploy your own Vue.js project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/vue)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/vue)
_Live Example: https://vue.now-examples.now.sh_

View File

@@ -6,7 +6,7 @@ This directory is a brief example of a [VuePress](https://vuepress.vuejs.org/) a
Deploy your own VuePress project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/vuepress)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/vuepress)
_Live Example: https://vuepress.now-examples.now.sh_

View File

@@ -6,7 +6,7 @@ This directory is a brief example of a [Zola](https://www.getzola.org/) site tha
Deploy your own Zola project with ZEIT Now.
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/new/project?template=https://github.com/zeit/now/tree/master/examples/zola)
[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/now/tree/master/examples/zola)
_Live Example: https://zola.now-examples.now.sh_

View File

@@ -1,9 +1,8 @@
{
"redirects": [
"rewrites": [
{
"source": "/",
"destination": "https://zeit.co/new",
"statusCode": 307
"destination": "/api/frameworks"
}
],
"env": {

View File

@@ -17,7 +17,7 @@
},
"settings": {
"buildCommand": {
"placeholder": "`next build` or `build` from `package.json`"
"placeholder": "`build` from `package.json` or `next build`"
},
"devCommand": {
"value": "next dev --port $PORT"

View File

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

View File

@@ -1,6 +1,6 @@
{
"name": "@now/build-utils",
"version": "1.3.9",
"version": "2.1.0",
"license": "MIT",
"main": "./dist/index.js",
"types": "./dist/index.d.js",

File diff suppressed because it is too large Load Diff

View File

@@ -1,432 +0,0 @@
import { parse as parsePath, extname } from 'path';
import { Route, Source } from '@now/routing-utils';
import { Builder } from './types';
import { getIgnoreApiFilter, sortFiles } from './detect-builders';
function escapeName(name: string) {
const special = '[]^$.|?*+()'.split('');
for (const char of special) {
name = name.replace(new RegExp(`\\${char}`, 'g'), `\\${char}`);
}
return name;
}
function joinPath(...segments: string[]) {
const joinedPath = segments.join('/');
return joinedPath.replace(/\/{2,}/g, '/');
}
function concatArrayOfText(texts: string[]): string {
if (texts.length <= 2) {
return texts.join(' and ');
}
const last = texts.pop();
return `${texts.join(', ')}, and ${last}`;
}
// Takes a filename or foldername, strips the extension
// gets the part between the "[]" brackets.
// It will return `null` if there are no brackets
// and therefore no segment.
function getSegmentName(segment: string): string | null {
const { name } = parsePath(segment);
if (name.startsWith('[') && name.endsWith(']')) {
return name.slice(1, -1);
}
return null;
}
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, i): string => {
const name = getSegmentName(segment);
const isLast = i === parts.length - 1;
if (name !== null) {
// We can't use `URLSearchParams` because `$` would get escaped
query.push(`${name}=$${counter++}`);
isDynamic = true;
return `([^/]+)`;
} else if (isLast) {
const { name: fileName, ext } = parsePath(segment);
const isIndex = fileName === 'index';
const prefix = isIndex ? '\\/' : '';
const names = [
isIndex ? prefix : `${fileName}\\/`,
prefix + escapeName(fileName),
featHandleMiss && cleanUrls
? ''
: prefix + escapeName(fileName) + escapeName(ext),
].filter(Boolean);
// Either filename with extension, filename without extension
// 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, 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('/')}$`;
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
// name for the path segment at the same position
function partiallyMatches(pathA: string, pathB: string): boolean {
const partsA = pathA.split('/');
const partsB = pathB.split('/');
const long = partsA.length > partsB.length ? partsA : partsB;
const short = long === partsA ? partsB : partsA;
let index = 0;
for (const segmentShort of short) {
const segmentLong = long[index];
const nameLong = getSegmentName(segmentLong);
const nameShort = getSegmentName(segmentShort);
// If there are no segments or the paths differ we
// return as they are not matching
if (segmentShort !== segmentLong && (!nameLong || !nameShort)) {
return false;
}
if (nameLong !== nameShort) {
return true;
}
index += 1;
}
return false;
}
// Counts how often a path occurs when all placeholders
// got resolved, so we can check if they have conflicts
function pathOccurrences(filePath: string, files: string[]): string[] {
const getAbsolutePath = (unresolvedPath: string): string => {
const { dir, name } = parsePath(unresolvedPath);
const parts = joinPath(dir, name).split('/');
return parts.map(part => part.replace(/\[.*\]/, '1')).join('/');
};
const currentAbsolutePath = getAbsolutePath(filePath);
return files.reduce((prev: string[], file: string): string[] => {
const absolutePath = getAbsolutePath(file);
if (absolutePath === currentAbsolutePath) {
prev.push(file);
} else if (partiallyMatches(filePath, file)) {
prev.push(file);
}
return prev;
}, []);
}
// Checks if a placeholder with the same name is used
// multiple times inside the same path
function getConflictingSegment(filePath: string): string | null {
const segments = new Set<string>();
for (const segment of filePath.split('/')) {
const name = getSegmentName(segment);
if (name !== null && segments.has(name)) {
return name;
}
if (name) {
segments.add(name);
}
}
return null;
}
function sortFilesBySegmentCount(fileA: string, fileB: string): number {
const lengthA = fileA.split('/').length;
const lengthB = fileB.split('/').length;
if (lengthA > lengthB) {
return -1;
}
if (lengthA < lengthB) {
return 1;
}
// Paths that have the same segment length but
// less placeholders are preferred
const countSegments = (prev: number, segment: string) =>
getSegmentName(segment) ? prev + 1 : 0;
const segmentLengthA = fileA.split('/').reduce(countSegments, 0);
const segmentLengthB = fileB.split('/').reduce(countSegments, 0);
if (segmentLengthA > segmentLengthB) {
return 1;
}
if (segmentLengthA < segmentLengthB) {
return -1;
}
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[],
featHandleMiss: boolean,
cleanUrls: boolean
): Promise<ApiRoutesResult> {
if (!files || files.length === 0) {
return {
defaultRoutes: null,
dynamicRoutes: null,
error: null,
};
}
// The deepest routes need to be
// the first ones to get handled
const sortedFiles = files
.filter(getIgnoreApiFilter(builders))
.sort(sortFiles)
.sort(sortFilesBySegmentCount);
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/') &&
!builders.some(b => b.src === file && b.config && b.config.functions)
) {
continue;
}
const conflictingSegment = getConflictingSegment(file);
if (conflictingSegment) {
return {
defaultRoutes: null,
dynamicRoutes: null,
error: {
code: 'conflicting_path_segment',
message:
`The segment "${conflictingSegment}" occurs more than ` +
`one time in your path "${file}". Please make sure that ` +
`every segment in a path is unique`,
},
};
}
const occurrences = pathOccurrences(file, sortedFiles).filter(
name => name !== file
);
if (occurrences.length > 0) {
const messagePaths = concatArrayOfText(
occurrences.map(name => `"${name}"`)
);
return {
defaultRoutes: null,
dynamicRoutes: null,
error: {
code: 'conflicting_file_path',
message:
`Two or more files have conflicting paths or names. ` +
`Please make sure path segments and filenames, without their extension, are unique. ` +
`The path "${file}" has conflicts with ${messagePaths}`,
},
};
}
const out = createRouteFromPath(file, featHandleMiss, cleanUrls);
if (out.isDynamic) {
dynamicRoutes.push(out.route);
}
defaultRoutes.push(out.route);
}
return { defaultRoutes, dynamicRoutes, error: null };
}
function getPublicBuilder(builders: Builder[]): Builder | null {
const builder = builders.find(
builder =>
builder.use === '@now/static' &&
/^.*\/\*\*\/\*$/.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 function detectApiDirectory(builders: Builder[]): string | null {
// TODO: We eventually want to save the api directory to
// builder.config.apiDirectory so it is only detected once
const found = builders.some(
b => b.config && b.config.zeroConfig && b.src.startsWith('api/')
);
return found ? 'api' : null;
}
export function detectApiExtensions(builders: Builder[]): Set<string> {
return new Set<string>(
builders
.filter(
b =>
b.config && b.config.zeroConfig && b.src && b.src.startsWith('api/')
)
.map(b => extname(b.src))
.filter(Boolean)
);
}
export async function detectRoutes(
files: string[],
builders: Builder[],
featHandleMiss = false,
cleanUrls = false,
trailingSlash?: boolean
): Promise<RoutesResult> {
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' });
const extSet = detectApiExtensions(builders);
if (extSet.size > 0) {
const exts = Array.from(extSet)
.map(ext => ext.slice(1))
.join('|');
const extGroup = `(?:\\.(?:${exts}))`;
if (cleanUrls) {
redirectRoutes.push({
src: `^/(api(?:.+)?)/index${extGroup}?/?$`,
headers: { Location: trailingSlash ? '/$1/' : '/$1' },
status: 308,
});
redirectRoutes.push({
src: `^/api/(.+)${extGroup}/?$`,
headers: { Location: trailingSlash ? '/api/$1/' : '/api/$1' },
status: 308,
});
} else {
defaultRoutes.push({
src: `^/api/(.+)${extGroup}$`,
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 (!featHandleMiss && directory) {
defaultRoutes.push({
src: '/(.*)',
dest: `/${directory}/$1`,
});
}
return { defaultRoutes, redirectRoutes, error };
}

View File

@@ -206,10 +206,10 @@ export async function runNpmInstall(
debug(`Installing to ${destPath}`);
const { hasPackageLockJson } = await scanParentDirs(destPath);
const opts = { cwd: destPath, ...spawnOpts } || {
cwd: destPath,
env: process.env,
};
const opts: SpawnOptions = { cwd: destPath, ...spawnOpts };
const env = opts.env || { ...process.env };
delete env.NODE_ENV;
opts.env = env;
if (hasPackageLockJson) {
commandArgs = args.filter(a => a !== '--prefer-offline');
@@ -239,10 +239,7 @@ export async function runBundleInstall(
}
assert(path.isAbsolute(destPath));
const opts = { cwd: destPath, ...spawnOpts } || {
cwd: destPath,
env: process.env,
};
const opts = { cwd: destPath, ...spawnOpts };
await spawnAsync(
'bundle',
@@ -270,10 +267,7 @@ export async function runPipInstall(
}
assert(path.isAbsolute(destPath));
const opts = { cwd: destPath, ...spawnOpts } || {
cwd: destPath,
env: process.env,
};
const opts = { cwd: destPath, ...spawnOpts };
await spawnAsync(
'pip3',

View File

@@ -64,12 +64,11 @@ export {
};
export {
detectRoutes,
detectBuilders,
detectOutputDirectory,
detectApiDirectory,
detectApiExtensions,
} from './detect-routes';
export { detectBuilders } from './detect-builders';
} from './detect-builders';
export { detectFramework } from './detect-framework';
export { DetectorFilesystem } from './detectors/filesystem';
export { readConfigFile } from './fs/read-config-file';

View File

@@ -4,20 +4,28 @@ import FileRef from './file-ref';
import { Lambda } from './lambda';
interface PrerenderOptions {
expiration: number;
expiration: number | false;
lambda: Lambda;
fallback: FileBlob | FileFsRef | FileRef | null;
group?: number;
bypassToken?: string | null /* optional to be non-breaking change */;
}
export class Prerender {
public type: 'Prerender';
public expiration: number;
public expiration: number | false;
public lambda: Lambda;
public fallback: FileBlob | FileFsRef | FileRef | null;
public group?: number;
public bypassToken: string | null;
constructor({ expiration, lambda, fallback, group }: PrerenderOptions) {
constructor({
expiration,
lambda,
fallback,
group,
bypassToken,
}: PrerenderOptions) {
this.type = 'Prerender';
this.expiration = expiration;
this.lambda = lambda;
@@ -32,6 +40,22 @@ export class Prerender {
}
this.group = group;
if (bypassToken == null) {
this.bypassToken = null;
} else if (typeof bypassToken === 'string') {
if (bypassToken.length < 32) {
// Enforce 128 bits of entropy for safety reasons (UUIDv4 size)
throw new Error(
'The `bypassToken` argument for `Prerender` must be 32 characters or more.'
);
}
this.bypassToken = bypassToken;
} else {
throw new Error(
'The `bypassToken` argument for `Prerender` must be a `string`.'
);
}
if (typeof fallback === 'undefined') {
throw new Error(
'The `fallback` argument for `Prerender` needs to be a `FileBlob`, `FileFsRef`, `FileRef`, or null.'

View File

@@ -0,0 +1,21 @@
function checkPkgOrThrow(pkgname) {
try {
const dep = require(pkgname);
if (!dep) {
throw new Error('Undefined');
}
} catch (e) {
console.error(`Expected package "${pkgname}" to be installed.`);
process.exit(1);
}
}
// We expect both `dependencies` and `devDependencies` to be installed
// even when NODE_ENV=production.
checkPkgOrThrow('tls-check');
checkPkgOrThrow('exeggcute');
// This is to satisfy `@now/static-build` which needs a `dist` directory.
const { exec } = require('exeggcute');
exec('mkdir dist', __dirname);
exec('echo "node-env:RANDOMNESS_PLACEHOLDER" > dist/index.html', __dirname);

View File

@@ -0,0 +1,6 @@
{
"version": 2,
"builds": [{ "src": "package.json", "use": "@now/static-build" }],
"build": { "env": { "NODE_ENV": "production" } },
"probes": [{ "path": "/", "mustContain": "node-env:RANDOMNESS_PLACEHOLDER" }]
}

View File

@@ -0,0 +1,12 @@
{
"private": true,
"scripts": {
"build": "node build.js"
},
"dependencies": {
"tls-check": "1.0.0"
},
"devDependencies": {
"exeggcute": "1.0.0"
}
}

View File

@@ -4,7 +4,7 @@ const {
packAndDeploy,
testDeployment,
} = require('../../../test/lib/deployment/test-deployment');
const { glob, detectBuilders, detectRoutes } = require('../');
const { glob, detectBuilders } = require('../');
jest.setTimeout(4 * 60 * 1000);
@@ -110,8 +110,7 @@ it('Test `detectBuilders` and `detectRoutes`', async () => {
},
];
const { builders } = await detectBuilders(files, pkg);
const { defaultRoutes } = await detectRoutes(files, builders);
const { builders, defaultRoutes } = await detectBuilders(files, pkg);
const nowConfig = { builds: builders, routes: defaultRoutes, probes };
await fs.writeFile(
@@ -126,7 +125,7 @@ it('Test `detectBuilders` and `detectRoutes`', async () => {
expect(deployment).toBeDefined();
});
it('Test `detectBuilders` and `detectRoutes` with `index` files', async () => {
it('Test `detectBuilders` with `index` files', async () => {
const fixture = path.join(__dirname, 'fixtures', '02-zero-config-api');
const pkg = await fs.readJSON(path.join(fixture, 'package.json'));
const fileList = await glob('**', fixture);
@@ -192,8 +191,7 @@ it('Test `detectBuilders` and `detectRoutes` with `index` files', async () => {
},
];
const { builders } = await detectBuilders(files, pkg);
const { defaultRoutes } = await detectRoutes(files, builders);
const { builders, defaultRoutes } = await detectBuilders(files, pkg);
const nowConfig = { builds: builders, routes: defaultRoutes, probes };
await fs.writeFile(

File diff suppressed because it is too large Load Diff

View File

@@ -11,6 +11,10 @@ const {
} = require('../dist');
it('should re-create symlinks properly', async () => {
if (process.platform === 'win32') {
console.log('Skipping test on windows');
return;
}
const files = await glob('**', path.join(__dirname, 'symlinks'));
assert.equal(Object.keys(files).length, 2);
@@ -29,6 +33,10 @@ it('should re-create symlinks properly', async () => {
});
it('should create zip files with symlinks properly', async () => {
if (process.platform === 'win32') {
console.log('Skipping test on windows');
return;
}
const files = await glob('**', path.join(__dirname, 'symlinks'));
assert.equal(Object.keys(files).length, 2);

View File

@@ -1,4 +1,4 @@
![now](https://assets.zeit.co/image/upload/v1542240976/repositories/now-cli/now-cli-repo-banner-v3.png)
![now](https://assets.zeit.co/image/upload/v1581518533/repositories/now-cli/v4.png)
[![Join the community on Spectrum](https://withspectrum.github.io/badge/badge.svg)](https://spectrum.chat/zeit)

View File

@@ -1,6 +1,6 @@
{
"name": "now",
"version": "17.0.2",
"version": "17.0.5-canary.5",
"preferGlobal": true,
"license": "Apache-2.0",
"description": "The command-line interface for Now",
@@ -12,7 +12,7 @@
},
"scripts": {
"preinstall": "node ./scripts/preinstall.js",
"test-unit": "nyc ava test/*unit.js --serial --fail-fast --verbose",
"test-unit": "nyc ava test/unit.js test/dev-builder.unit.js test/dev-router.unit.js test/dev-server.unit.js --serial --fail-fast --verbose",
"test-integration": "ava test/integration.js --serial --fail-fast",
"test-integration-v1": "ava test/integration-v1.js --serial --fail-fast",
"test-integration-now-dev": "ava test/dev/integration.js --serial --fail-fast --verbose",
@@ -109,7 +109,7 @@
"chalk": "2.4.2",
"chokidar": "2.1.6",
"clipboardy": "2.1.0",
"codecov": "3.1.0",
"codecov": "3.6.5",
"cpy": "7.2.0",
"credit-card": "3.0.1",
"date-fns": "1.29.0",
@@ -179,6 +179,6 @@
"which-promise": "1.0.0",
"write-json-file": "2.2.0",
"xdg-app-paths": "5.1.0",
"yarn": "1.17.3"
"yarn": "1.22.0"
}
}

View File

@@ -186,7 +186,7 @@ export default async ctx => {
contextName,
output,
stats,
localConfig || {},
localConfig,
parts.latestArgs
);
}

View File

@@ -53,6 +53,7 @@ import { inputRootDirectory } from '../../util/input/input-root-directory';
import validatePaths, {
validateRootDirectory,
} from '../../util/validate-paths';
import { readLocalConfig } from '../../util/config/files';
const addProcessEnv = async (log, env) => {
let val;
@@ -238,13 +239,6 @@ export default async function main(
const { isFile, path } = pathValidation;
const autoConfirm = argv['--confirm'] || isFile;
// build `meta`
const meta = Object.assign(
{},
parseMeta(localConfig.meta),
parseMeta(argv['--meta'])
);
// --no-scale
if (argv['--no-scale']) {
warn(`The option --no-scale is only supported on Now 1.0 deployments`);
@@ -260,7 +254,125 @@ export default async function main(
);
}
if (localConfig && localConfig.name) {
const client = new Client({
apiUrl: ctx.apiUrl,
token: ctx.authConfig.token,
debug: debugEnabled,
});
// retrieve `project` and `org` from .now
const link = await getLinkedProject(output, client, path);
if (link.status === 'error') {
return link.exitCode;
}
let { org, project, status } = link;
let newProjectName = null;
let rootDirectory = project ? project.rootDirectory : null;
if (status === 'not_linked') {
const shouldStartSetup =
autoConfirm ||
(await confirm(
`Set up and deploy ${chalk.cyan(`${toHumanPath(path)}`)}?`,
true
));
if (!shouldStartSetup) {
output.print(`Aborted. Project not set up.\n`);
return 0;
}
org = await selectOrg(
output,
'Which scope do you want to deploy to?',
client,
ctx.config.currentTeam,
autoConfirm
);
// We use `localConfig` here to read the name
// even though the `now.json` file can change
// afterwards, this is fine since the property
// will be deprecated and can be replaced with
// user input.
const detectedProjectName = getProjectName({
argv,
nowConfig: localConfig || {},
isFile,
paths,
});
const projectOrNewProjectName = await inputProject(
output,
client,
org,
detectedProjectName,
autoConfirm
);
if (typeof projectOrNewProjectName === 'string') {
newProjectName = projectOrNewProjectName;
rootDirectory = await inputRootDirectory(path, output, autoConfirm);
} else {
project = projectOrNewProjectName;
rootDirectory = project.rootDirectory;
// we can already link the project
await linkFolderToProject(
output,
path,
{
projectId: project.id,
orgId: org.id,
},
project.name,
org.slug
);
status = 'linked';
}
}
const sourcePath = rootDirectory ? join(path, rootDirectory) : path;
if (
rootDirectory &&
(await validateRootDirectory(
output,
path,
sourcePath,
project
? `To change your project settings, go to https://zeit.co/${org.slug}/${project.name}/settings`
: ''
)) === false
) {
return 1;
}
// If Root Directory is used we'll try to read the config
// from there instead and use it if it exists.
if (rootDirectory) {
const rootDirectoryConfig = readLocalConfig(sourcePath);
if (rootDirectoryConfig) {
debug(`Read local config from root directory (${rootDirectory})`);
localConfig = rootDirectoryConfig;
} else if (localConfig) {
output.print(
`${prependEmoji(
`The ${highlight(
'now.json'
)} file should be inside of the provided root directory.`,
emoji('warning')
)}\n`
);
}
}
localConfig = localConfig || {};
if (localConfig.name) {
output.print(
`${prependEmoji(
`The ${code('name')} property in ${highlight(
@@ -310,6 +422,13 @@ export default async function main(
}
}
// build `meta`
const meta = Object.assign(
{},
parseMeta(localConfig.meta),
parseMeta(argv['--meta'])
);
// Merge dotenv config, `env` from now.json, and `--env` / `-e` arguments
const deploymentEnv = Object.assign(
{},
@@ -367,97 +486,6 @@ export default async function main(
target = 'production';
}
const client = new Client({
apiUrl: ctx.apiUrl,
token: ctx.authConfig.token,
debug: debugEnabled,
});
// retrieve `project` and `org` from .now
const link = await getLinkedProject(output, client, path);
if (link.status === 'error') {
return link.exitCode;
}
let { org, project, status } = link;
let newProjectName = null;
let rootDirectory = project ? project.rootDirectory : null;
if (status === 'not_linked') {
const shouldStartSetup =
autoConfirm ||
(await confirm(
`Set up and deploy ${chalk.cyan(`${toHumanPath(path)}`)}?`,
true
));
if (!shouldStartSetup) {
output.print(`Aborted. Project not set up.\n`);
return 0;
}
org = await selectOrg(
output,
'Which scope do you want to deploy to?',
client,
ctx.config.currentTeam,
autoConfirm
);
const detectedProjectName = getProjectName({
argv,
nowConfig: localConfig,
isFile,
paths,
});
const projectOrNewProjectName = await inputProject(
output,
client,
org,
detectedProjectName,
autoConfirm
);
if (typeof projectOrNewProjectName === 'string') {
newProjectName = projectOrNewProjectName;
rootDirectory = await inputRootDirectory(path, output, autoConfirm);
} else {
project = projectOrNewProjectName;
rootDirectory = project.rootDirectory;
// we can already link the project
await linkFolderToProject(
output,
path,
{
projectId: project.id,
orgId: org.id,
},
project.name,
org.slug
);
status = 'linked';
}
}
const sourcePath = rootDirectory ? join(path, rootDirectory) : path;
if (
rootDirectory &&
(await validateRootDirectory(
output,
path,
sourcePath,
project
? `To change your project settings, go to https://zeit.co/${org.slug}/${project.name}/settings`
: ''
)) === false
) {
return 1;
}
const currentTeam = org.type === 'team' ? org.id : undefined;
const now = new Now({ apiUrl, token, debug: debugEnabled, currentTeam });
let deployStamp = stamp();
@@ -538,6 +566,11 @@ export default async function main(
return 1;
}
if (deployment.readyState === 'CANCELED') {
output.log('The deployment has been canceled');
return 1;
}
const deploymentResponse = await getDeploymentByIdOrHost(
now,
contextName,
@@ -624,7 +657,12 @@ export default async function main(
output.error('Build failed');
output.error(
`Check your logs at ${now.url}/_logs or run ${code(
`now logs ${now.url}`
`now logs ${now.url}`,
{
// Backticks are interpreted as part of the URL, causing CMD+Click
// behavior to fail in editors like VSCode.
backticks: false,
}
)}`
);

View File

@@ -852,7 +852,7 @@ async function sync({
const { url } = now;
const dcs =
deploymentType !== 'static' && deployment.scale
? chalk` ({bold ${Object.keys(deployment.scale).join(', ')})`
? ` (${ chalk.bold(Object.keys(deployment.scale).join(', ')) })`
: '';
if (isTTY) {

View File

@@ -202,6 +202,13 @@ export default async function processDeployment({
}
}
if (event.type === 'canceled') {
if (buildSpinner) {
buildSpinner();
}
return event.payload;
}
if (event.type === 'ready') {
if (queuedSpinner) {
queuedSpinner();

View File

@@ -7,7 +7,6 @@ import { delimiter, dirname, join } from 'path';
import { fork, ChildProcess } from 'child_process';
import { createFunction } from '@zeit/fun';
import { Builder, File, Lambda, FileBlob, FileFsRef } from '@now/build-utils';
import which from 'which';
import plural from 'pluralize';
import minimatch from 'minimatch';
import _treeKill from 'tree-kill';
@@ -44,12 +43,6 @@ interface BuildMessageResult extends BuildMessage {
const treeKill = promisify(_treeKill);
let nodeBinPromise: Promise<string>;
async function getNodeBin(): Promise<string> {
return which.sync('node', { nothrow: true }) || process.execPath;
}
async function createBuildProcess(
match: BuildMatch,
buildEnv: EnvConfig,
@@ -57,13 +50,8 @@ async function createBuildProcess(
output: Output,
yarnPath?: string
): Promise<ChildProcess> {
if (!nodeBinPromise) {
nodeBinPromise = getNodeBin();
}
const [execPath, modulePath] = await Promise.all([
nodeBinPromise,
builderModulePathPromise,
]);
const { execPath } = process;
const modulePath = await builderModulePathPromise;
// Ensure that `node` is in the builder's `PATH`
let PATH = `${dirname(execPath)}${delimiter}${process.env.PATH}`;

View File

@@ -133,6 +133,9 @@ export async function devRouter(
);
if (missResult.found) {
return missResult;
} else {
reqPathname = destPath;
continue;
}
} else {
if (routeConfig.status && phase === 'miss') {

View File

@@ -12,7 +12,11 @@ import serveHandler from 'serve-handler';
import { watch, FSWatcher } from 'chokidar';
import { parse as parseDotenv } from 'dotenv';
import { basename, dirname, extname, join } from 'path';
import { getTransformedRoutes, HandleValue } from '@now/routing-utils';
import {
getTransformedRoutes,
appendRoutesToPhase,
HandleValue,
} from '@now/routing-utils';
import directoryTemplate from 'serve-handler/src/directory';
import getPort from 'get-port';
import { ChildProcess } from 'child_process';
@@ -24,7 +28,6 @@ import {
FileFsRef,
PackageJson,
detectBuilders,
detectRoutes,
detectApiDirectory,
detectApiExtensions,
spawnCommand,
@@ -548,10 +551,20 @@ export default class DevServer {
const featHandleMiss = true; // enable for zero config
const { projectSettings, cleanUrls, trailingSlash } = config;
let { builders, warnings, errors } = await detectBuilders(files, pkg, {
let {
builders,
warnings,
errors,
defaultRoutes,
redirectRoutes,
rewriteRoutes,
} = await detectBuilders(files, pkg, {
tag: getDistTag(cliVersion) === 'canary' ? 'canary' : 'latest',
functions: config.functions,
...(projectSettings ? { projectSettings } : {}),
featHandleMiss,
cleanUrls,
trailingSlash,
});
if (errors) {
@@ -568,34 +581,23 @@ export default class DevServer {
builders = builders.filter(filterFrontendBuilds);
}
const {
defaultRoutes,
redirectRoutes,
error: routesError,
} = await detectRoutes(
files,
builders,
featHandleMiss,
cleanUrls,
trailingSlash
);
config.builds = config.builds || [];
config.builds.push(...builders);
if (routesError) {
this.output.error(routesError.message);
await this.exit();
} else {
const routes: RouteConfig[] = [];
const { routes: nowConfigRoutes } = config;
routes.push(...(redirectRoutes || []));
routes.push(...(nowConfigRoutes || []));
routes.push(
...appendRoutesToPhase({
routes: nowConfigRoutes,
newRoutes: rewriteRoutes,
phase: 'filesystem',
})
);
routes.push(...(defaultRoutes || []));
config.routes = routes;
}
}
}
if (!config.builds || config.builds.length === 0) {
if (isInitialLoad && !this.devCommand) {
@@ -1185,6 +1187,35 @@ export default class DevServer {
}
};
/**
* This is the equivalent to now-proxy exit_with_status() function.
*/
exitWithStatus = async (
match: BuildMatch | null,
routeResult: RouteResult,
phase: HandleValue | null,
req: http.IncomingMessage,
res: http.ServerResponse,
nowRequestId: string
): Promise<boolean> => {
const { status, headers, dest } = routeResult;
const location = headers['location'] || dest;
if (status && location && (300 <= status && status <= 399)) {
this.output.debug(`Route found with redirect status code ${status}`);
await this.sendRedirect(req, res, nowRequestId, location, status);
return true;
}
if (!match && status && phase !== 'miss') {
this.output.debug(`Route found with with status code ${status}`);
await this.sendError(req, res, nowRequestId, '', status);
return true;
}
return false;
};
/**
* Serve project directory as a Now v2 deployment.
*/
@@ -1268,6 +1299,19 @@ export default class DevServer {
this
);
if (
await this.exitWithStatus(
match,
routeResult,
phase,
req,
res,
nowRequestId
)
) {
return;
}
if (!match && missRoutes.length > 0) {
// Since there was no build match, enter the miss phase
routeResult = await devRouter(
@@ -1286,6 +1330,18 @@ export default class DevServer {
routeResult.dest,
this
);
if (
await this.exitWithStatus(
match,
routeResult,
phase,
req,
res,
nowRequestId
)
) {
return;
}
} else if (match && hitRoutes.length > 0) {
// Since there was a build match, enter the hit phase.
// The hit phase must not set status code.
@@ -1304,28 +1360,6 @@ export default class DevServer {
statusCode = routeResult.status;
if (match && statusCode === 404 && routeResult.phase === 'miss') {
statusCode = undefined;
}
const location = routeResult.headers['location'] || routeResult.dest;
if (statusCode && location && (300 <= statusCode && statusCode <= 399)) {
// Equivalent to now-proxy exit_with_status() function
this.output.debug(
`Route found with redirect status code ${statusCode}`
);
await this.sendRedirect(req, res, nowRequestId, location, statusCode);
return;
}
if (!match && statusCode && routeResult.phase !== 'miss') {
// Equivalent to now-proxy exit_with_status() function
this.output.debug(`Route found with with status code ${statusCode}`);
await this.sendError(req, res, nowRequestId, '', statusCode);
return;
}
if (match) {
// end the phase
break;
@@ -1632,12 +1666,14 @@ export default class DevServer {
}
async runDevCommand() {
if (!this.devCommand) return;
const { devCommand, cwd } = this;
const cwd = this.cwd;
if (!devCommand) {
return;
}
this.output.log(
`Running Dev Command ${chalk.cyan.bold(`${this.devCommand}`)}`
`Running Dev Command ${chalk.cyan.bold(`${devCommand}`)}`
);
const port = await getPort();
@@ -1646,35 +1682,36 @@ export default class DevServer {
...process.env,
...this.buildEnv,
NOW_REGION: 'dev1',
PORT: `${port}`,
};
const devCommand = this.devCommand
// This is necesary so that the dev command in the Project
// will work cross-platform (especially Windows).
let command = devCommand
.replace(/\$PORT/g, `${port}`)
.replace(/%PORT%/g, `${port}`);
this.output.debug(
`Starting dev command with parameters : ${JSON.stringify({
cwd: this.cwd,
devCommand,
cwd,
command,
port,
})}`
);
let command = devCommand;
const isNpxAvailable = await which('npx')
.then(() => true)
.catch(() => false);
if (isNpxAvailable) {
command = `npx --no-install ${devCommand}`;
command = `npx --no-install ${command}`;
} else {
const isYarnAvailable = await which('yarn')
.then(() => true)
.catch(() => false);
if (isYarnAvailable) {
command = `yarn run --silent ${devCommand}`;
command = `yarn run --silent ${command}`;
}
}

View File

@@ -4,6 +4,7 @@ import chalk from 'chalk';
// The equivalent of <code>, for embedding anything
// you may want to take a look at ./cmd.js
export default function code(cmd: string): string {
return `${chalk.gray('`')}${chalk.bold(cmd)}${chalk.gray('`')}`;
export default function code(cmd: string, { backticks = true } = {}): string {
const tick = backticks ? chalk.gray('`') : '';
return `${tick}${chalk.bold(cmd)}${tick}`;
}

View File

@@ -5,7 +5,7 @@ import execa from 'execa';
import fs from 'fs-extra';
import fetch from 'node-fetch';
import listen from 'async-listen';
import { request, createServer } from 'http';
import { createServer } from 'http';
import createOutput from '../src/util/output';
import DevServer from '../src/util/dev/server';
import { installBuilders, getBuildUtils } from '../src/util/dev/builder-cache';
@@ -13,12 +13,28 @@ import parseListen from '../src/util/dev/parse-listen';
async function runNpmInstall(fixturePath) {
if (await fs.exists(path.join(fixturePath, 'package.json'))) {
return execa('yarn', ['install'], { cwd: fixturePath });
return execa('yarn', ['install'], { cwd: fixturePath, shell: true });
}
}
const skipOnWindows = new Set([
'now-dev-default-builds-and-routes',
'now-dev-static-routes',
'now-dev-static-build-routing',
'now-dev-directory-listing',
'now-dev-api-with-public',
'now-dev-api-with-static',
'now-dev-custom-404',
]);
function testFixture(name, fn) {
return async t => {
if (process.platform === 'win32' && skipOnWindows.has(name)) {
console.log(`Skipping test "${name}" on Windows.`);
t.is(true, true);
return;
}
let server;
const fixturePath = path.join(__dirname, 'fixtures', 'unit', name);
@@ -68,14 +84,6 @@ function validateResponseHeaders(t, res, podId = null) {
}
}
function get(url) {
return new Promise((resolve, reject) => {
request(url, resolve)
.on('error', reject)
.end();
});
}
test(
'[DevServer] Maintains query when invoking lambda',
testFixture('now-dev-query-invoke', async (t, server) => {
@@ -138,16 +146,23 @@ test(
test(
'[DevServer] Allow `cache-control` to be overwritten',
testFixture('now-dev-headers', async (t, server) => {
const res = await get(
const res = await fetch(
`${server.address}/?name=cache-control&value=immutable`
);
t.is(res.headers['cache-control'], 'immutable');
t.is(res.headers.get('cache-control'), 'immutable');
})
);
test(
'[DevServer] Sends `etag` header for static files',
testFixture('now-dev-headers', async (t, server) => {
if (process.platform === 'win32') {
console.log(
'Skipping "etag" test on windows since it yields a different result.'
);
t.is(true, true);
return;
}
const res = await fetch(`${server.address}/foo.txt`);
t.is(res.headers.get('etag'), '"d263af8ab880c0b97eb6c5c125b5d44f9e5addd9"');
t.is(await res.text(), 'hi\n');
@@ -400,12 +415,14 @@ test('[DevServer] parseListen()', t => {
t.deepEqual(parseListen('0.0.0.0'), [3000, '0.0.0.0']);
t.deepEqual(parseListen('127.0.0.1:3005'), [3005, '127.0.0.1']);
t.deepEqual(parseListen('tcp://127.0.0.1:5000'), [5000, '127.0.0.1']);
if (process.platform !== 'win32') {
t.deepEqual(parseListen('unix:/home/user/server.sock'), [
'/home/user/server.sock',
]);
t.deepEqual(parseListen('pipe:\\\\.\\pipe\\PipeName'), [
'\\\\.\\pipe\\PipeName',
]);
}
let err;
try {

View File

@@ -0,0 +1 @@
SKIP_PREFLIGHT_CHECK=true

View File

@@ -22,3 +22,4 @@ npm-debug.log*
yarn-debug.log*
yarn-error.log*
!yarn.lock
!.env

View File

@@ -1,10 +0,0 @@
{
"version": 2,
"routes": [
{ "handle": "filesystem" },
{ "src": "/([^/]+/dir/.+)", "dest": "/$1.html", "check": true },
{ "handle": "miss" },
{ "src": "/pathA(?:/.+)?", "status": 404, "continue": true },
{ "src": "/pathB(?:/.+)?", "status": 404, "continue": true }
]
}

View File

@@ -10,14 +10,14 @@
"dest": "/blog/$1",
"check": true
},
{
"handle": "miss"
},
{
"src": "/.*",
"status": 404,
"continue": true
},
{
"handle": "miss"
},
{
"src": "/(.*)",
"dest": "/src/$1",

View File

@@ -1,8 +0,0 @@
{
"version": 2,
"routes": [
{ "handle": "miss" },
{ "src": "/pathA(?:/.+)?", "status": 404, "continue": true },
{ "src": "/pathB(?:/.+)?", "status": 404, "continue": true }
]
}

View File

@@ -1,7 +0,0 @@
{
"functions": {
"server/**/*.js": {
"runtime": "@now/node@1.2.1"
}
}
}

View File

@@ -1,3 +0,0 @@
export default (req, res) => {
res.end(`current hour: ${Math.floor(Date.now() / 10000)}`);
};

View File

@@ -0,0 +1,2 @@
module.exports = (req, res) =>
res.send(req.query.username);

View File

@@ -0,0 +1 @@
module.exports = (req, res) => res.end('42');

View File

@@ -0,0 +1,2 @@
module.exports = (req, res) =>
res.send(req.query.id);

View File

@@ -0,0 +1,3 @@
{
"rewrites": [{ "source": "/rand", "destination": "/api/fourty-two" }]
}

View File

@@ -109,13 +109,14 @@ function validateResponseHeaders(t, res) {
async function exec(directory, args = []) {
return execa(binaryPath, ['dev', directory, ...args], {
reject: false,
shell: true,
env: { __NOW_SKIP_DEV_COMMAND: 1 },
});
}
async function runNpmInstall(fixturePath) {
if (await fs.exists(path.join(fixturePath, 'package.json'))) {
return execa('yarn', ['install'], { cwd: fixturePath });
return execa('yarn', ['install'], { cwd: fixturePath, shell: true });
}
}
@@ -123,6 +124,7 @@ async function getPackedBuilderPath(builderDirName) {
const packagePath = path.join(__dirname, '..', '..', '..', builderDirName);
const output = await execa('npm', ['pack'], {
cwd: packagePath,
shell: true,
});
if (output.exitCode !== 0 || output.stdout.trim() === '') {
@@ -160,6 +162,7 @@ async function testFixture(directory, opts = {}, args = []) {
{
reject: false,
detached: true,
shell: true,
stdio: 'pipe',
...opts,
env: { ...opts.env, __NOW_SKIP_DEV_COMMAND: 1 },
@@ -226,6 +229,7 @@ function testFixtureStdio(directory, fn) {
let printedOutput = false;
dev = execa(binaryPath, ['dev', dir, '-l', port], {
shell: true,
env: { __NOW_SKIP_DEV_COMMAND: 1 },
});
@@ -407,28 +411,6 @@ test(
})
);
test(
'[now dev] does not display directory listing after multiple 404',
testFixtureStdio('handle-miss-multiple-404', async (t, port) => {
t.is((await fetch(`http://localhost:${port}/pathA/dir`)).status, 404);
t.is((await fetch(`http://localhost:${port}/pathB/dir`)).status, 404);
t.is((await fetch(`http://localhost:${port}/pathC/dir`)).status, 200);
})
);
test(
'[now dev] does not display directory listing after `handle: miss` and 404',
testFixtureStdio('handle-miss-handle-filesystem-404', async (t, port) => {
t.is((await fetch(`http://localhost:${port}/pathA/dir`)).status, 404);
t.is((await fetch(`http://localhost:${port}/pathB/dir`)).status, 404);
t.is((await fetch(`http://localhost:${port}/pathC/dir`)).status, 200);
t.is((await fetch(`http://localhost:${port}/pathA/dir/one`)).status, 200);
t.is((await fetch(`http://localhost:${port}/pathB/dir/two`)).status, 200);
t.is((await fetch(`http://localhost:${port}/pathC/dir/three`)).status, 200);
})
);
test(
'[now dev] handles hit after handle: filesystem',
testFixtureStdio('handle-hit-after-fs', async (t, port) => {
@@ -479,6 +461,8 @@ test(
t.regex(await rand.text(), /random number/gm);
const rand2 = await fetchWithRetry(`http://localhost:${port}/api/rand.js`);
t.regex(await rand2.text(), /random number/gm);
const notfound = await fetch(`http://localhost:${port}/api`);
t.is(notfound.status, 404);
})
);
@@ -602,6 +586,31 @@ test('[now dev] validate env var names', async t => {
t.pass();
});
test(
'[now dev] test rewrites with segments serve correct content',
testFixtureStdio('test-rewrites-with-segments', async (t, port) => {
const users = await fetchWithRetry(
`http://localhost:${port}/api/users/first`,
3
);
t.regex(await users.text(), /first/gm);
const fourtytwo = await fetchWithRetry(
`http://localhost:${port}/api/fourty-two`,
3
);
t.regex(await fourtytwo.text(), /42/gm);
const rand = await fetchWithRetry(`http://localhost:${port}/rand`, 3);
t.regex(await rand.text(), /42/gm);
const dynamic = await fetchWithRetry(
`http://localhost:${port}/api/dynamic`,
3
);
t.regex(await dynamic.text(), /dynamic/gm);
const notfound = await fetch(`http://localhost:${port}/api`);
t.is(notfound.status, 404);
})
);
test(
'[now dev] test rewrites serve correct content',
testFixtureStdio('test-rewrites', async (t, port) => {
@@ -770,17 +779,17 @@ test('[now dev] 03-aurelia', async t => {
await tester(t);
});
// test(
// '[now dev] 04-create-react-app-node',
// testFixtureStdio('create-react-app', async(t, port) => {
// const response = await fetch(`http://localhost:${port}`);
test(
'[now dev] 04-create-react-app',
testFixtureStdio('04-create-react-app', async (t, port) => {
const response = await fetch(`http://localhost:${port}`);
// validateResponseHeaders(t, response);
validateResponseHeaders(t, response);
// const body = await response.text();
// t.regex(body, /React App/gm);
// })
// );
const body = await response.text();
t.regex(body, /React App/gm);
})
);
test('[now dev] 05-gatsby', async t => {
if (shouldSkip(t, '05-gatsby', '>^6.14.0 || ^8.10.0 || >=9.10.0')) return;

View File

@@ -156,33 +156,6 @@ RUN mkdir /public
RUN echo hello > /public/index.html
`,
},
'build-env': {
'now.json': JSON.stringify({
version: 1,
type: 'static',
build: {
env: { FOO: 'bar' },
},
}),
Dockerfile: `
FROM alpine
ARG FOO
RUN mkdir /public
RUN echo $FOO > /public/index.html
`,
},
'build-env-arg': {
'now.json': JSON.stringify({
version: 1,
type: 'static',
}),
Dockerfile: `
FROM alpine
ARG NONCE
RUN mkdir /public
RUN echo $NONCE > /public/index.html
`,
},
'build-env-debug': {
'now.json':
'{ "builds": [ { "src": "index.js", "use": "@now/node" } ], "version": 2 }',
@@ -487,6 +460,14 @@ CMD ["node", "index.js"]`,
},
'project-root-directory': {
'src/index.html': '<h1>I am a website.</h1>',
'src/now.json': JSON.stringify({
rewrites: [
{
source: '/i-do-exist',
destination: '/',
},
],
}),
},
};

View File

@@ -1859,79 +1859,6 @@ test('deploy a static build deployment', async t => {
t.is(content.trim(), 'hello');
});
test('use build-env', async t => {
const directory = fixture('build-env');
const { stdout, stderr, exitCode } = await execa(
binaryPath,
[directory, '--public', '--name', session, ...defaultArgs],
{
reject: false,
}
);
console.log(stderr);
console.log(stdout);
console.log(exitCode);
// Ensure the exit code is right
t.is(exitCode, 0);
// Test if the output is really a URL
const deploymentUrl = pickUrl(stdout);
const { href, host } = new URL(deploymentUrl);
t.is(host.split('-')[0], session);
await waitForDeployment(href);
// get the content
const response = await fetch(href);
const content = await response.text();
t.is(content.trim(), 'bar');
});
test('use `--build-env` CLI flag', async t => {
const directory = fixture('build-env-arg');
const nonce = Math.random()
.toString(36)
.substring(2);
const { stderr, stdout, exitCode } = await execa(
binaryPath,
[
directory,
'--public',
'--name',
session,
'--build-env',
`NONCE=${nonce}`,
...defaultArgs,
],
{
reject: false,
}
);
console.log(stderr);
console.log(stdout);
console.log(exitCode);
// Ensure the exit code is right
t.is(exitCode, 0, `Received:\n"${stderr}"\n"${stdout}"`);
// Test if the output is really a URL
const deploymentUrl = pickUrl(stdout);
const { href, host } = new URL(deploymentUrl);
t.is(host.split('-')[0], session);
await waitForDeployment(href);
// get the content
const response = await fetch(href);
const content = await response.text();
t.is(content.trim(), nonce);
});
test('use `--debug` CLI flag', async t => {
const directory = fixture('build-env-debug');

View File

@@ -1329,80 +1329,6 @@ test('deploying more than 1 path should fail', async t => {
t.true(stderr.trim().endsWith(`Can't deploy more than one path.`));
});
test('use build-env', async t => {
const directory = fixture('build-env');
const { stdout, stderr, exitCode } = await execa(
binaryPath,
[directory, '--public', '--name', session, ...defaultArgs, '--confirm'],
{
reject: false,
}
);
console.log(stderr);
console.log(stdout);
console.log(exitCode);
// Ensure the exit code is right
t.is(exitCode, 0);
// Test if the output is really a URL
const deploymentUrl = pickUrl(stdout);
const { href, host } = new URL(deploymentUrl);
t.is(host.split('-')[0], session);
await waitForDeployment(href);
// get the content
const response = await fetch(href);
const content = await response.text();
t.is(content.trim(), 'bar');
});
test('use `--build-env` CLI flag', async t => {
const directory = fixture('build-env-arg');
const nonce = Math.random()
.toString(36)
.substring(2);
const { stderr, stdout, exitCode } = await execa(
binaryPath,
[
directory,
'--public',
'--name',
session,
'--build-env',
`NONCE=${nonce}`,
...defaultArgs,
'--confirm',
],
{
reject: false,
}
);
console.log(stderr);
console.log(stdout);
console.log(exitCode);
// Ensure the exit code is right
t.is(exitCode, 0, `Received:\n"${stderr}"\n"${stdout}"`);
// Test if the output is really a URL
const deploymentUrl = pickUrl(stdout);
const { href, host } = new URL(deploymentUrl);
t.is(host.split('-')[0], session);
await waitForDeployment(href);
// get the content
const response = await fetch(href);
const content = await response.text();
t.is(content.trim(), nonce);
});
test('use `--debug` CLI flag', async t => {
const directory = fixture('build-env-debug');
@@ -2279,17 +2205,19 @@ test('should prefill "project name" prompt with now.json `name`', async t => {
let isDeprecated = false;
await waitForPrompt(now, chunk => {
if (chunk.includes('The `name` property in now.json is deprecated')) {
now.stderr.on('data', data => {
if (
data.toString().includes('The `name` property in now.json is deprecated')
) {
isDeprecated = true;
}
});
await waitForPrompt(now, chunk => {
return /Set up and deploy [^?]+\?/.test(chunk);
});
now.stdin.write('yes\n');
t.is(isDeprecated, true);
await waitForPrompt(now, chunk =>
chunk.includes('Which scope do you want to deploy to?')
);
@@ -2318,6 +2246,8 @@ test('should prefill "project name" prompt with now.json `name`', async t => {
const output = await now;
t.is(output.exitCode, 0, formatOutput(output));
t.is(isDeprecated, true);
// clean up
await remove(path.join(directory, 'now.json'));
});
@@ -2448,9 +2378,14 @@ test('use `rootDirectory` from project when deploying', async t => {
const secondResult = await execute([directory, '--public']);
t.is(secondResult.exitCode, 0, formatOutput(secondResult));
const pageResponse = await fetch(secondResult.stdout);
t.is(pageResponse.status, 200);
t.regex(await pageResponse.text(), /I am a website/gm);
const pageResponse1 = await fetch(secondResult.stdout);
t.is(pageResponse1.status, 200);
t.regex(await pageResponse1.text(), /I am a website/gm);
// Ensures that the `now.json` file has been applied
const pageResponse2 = await fetch(`${secondResult.stdout}/i-do-exist`);
t.is(pageResponse2.status, 200);
t.regex(await pageResponse2.text(), /I am a website/gm);
await apiFetch(`/v2/projects/${projectId}`, {
method: 'DELETE',

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