mirror of
https://github.com/LukeHagar/vercel.git
synced 2025-12-31 03:39:11 +00:00
Compare commits
39 Commits
@now/next@
...
@now/stati
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a56b32f670 | ||
|
|
aea7df85f7 | ||
|
|
c859ffc48c | ||
|
|
69ac545152 | ||
|
|
76dbcceb01 | ||
|
|
8c6d714258 | ||
|
|
55cefe988b | ||
|
|
d79611568f | ||
|
|
18f979727a | ||
|
|
96912577dc | ||
|
|
d5372f7ac8 | ||
|
|
feb5456eb6 | ||
|
|
cc0c3cfbef | ||
|
|
4fe6e94d83 | ||
|
|
ba6751f63e | ||
|
|
af105975d7 | ||
|
|
46e96d66ca | ||
|
|
9aabd26fda | ||
|
|
71c297de32 | ||
|
|
9569c1babc | ||
|
|
16a573ec6e | ||
|
|
79a6c8e1d2 | ||
|
|
e7f62d194b | ||
|
|
3c4306662e | ||
|
|
2ed4e7e9a2 | ||
|
|
d7a65cc835 | ||
|
|
0eb5dac904 | ||
|
|
9ad63f9ed2 | ||
|
|
4ad4765034 | ||
|
|
162f06e4a6 | ||
|
|
4b5b573a1e | ||
|
|
86a2640fff | ||
|
|
351a85f875 | ||
|
|
00fd570ce5 | ||
|
|
4ff1f05cf3 | ||
|
|
fb9035bc00 | ||
|
|
9258a74986 | ||
|
|
f7c21bbde6 | ||
|
|
4c6c17af8a |
@@ -7,6 +7,7 @@
|
||||
/packages/now-build-utils/src/fs/*.js
|
||||
/packages/now-node/dist/*
|
||||
/packages/now-next/dist/*
|
||||
/packages/now-next/test/fixtures/**
|
||||
/packages/now-node-bridge/*
|
||||
/packages/now-python/dist/*
|
||||
/packages/now-go/*
|
||||
|
||||
16
.kodiak.toml
Normal file
16
.kodiak.toml
Normal file
@@ -0,0 +1,16 @@
|
||||
version = 1
|
||||
|
||||
[merge]
|
||||
automerge_label = "automerge"
|
||||
blacklist_title_regex = "^WIP.*"
|
||||
blacklist_labels = ["work in progress"]
|
||||
method = "squash"
|
||||
delete_branch_on_merge = true
|
||||
block_on_reviews_requested = false
|
||||
notify_on_conflict = true
|
||||
optimistic_updates = true
|
||||
|
||||
[merge.message]
|
||||
title = "pull_request_title"
|
||||
include_pr_number = true
|
||||
body_type = "markdown"
|
||||
@@ -1,6 +1,6 @@
|
||||
# Contributing
|
||||
|
||||
When contributing to this repository, please first discuss the change you wish to make via issue or [spectrum](https://spectrum.chat/zeit) with the owners of this repository before submitting a Pull Request.
|
||||
When contributing to this repository, please first discuss the change you wish to make via [GitHub Issue](https://github.com/zeit/now-builders/issues/new) or [Spectrum](https://spectrum.chat/zeit) with the owners of this repository before submitting a Pull Request.
|
||||
|
||||
Please read our [code of conduct](CODE_OF_CONDUCT.md) and follow it in all your interactions with the project.
|
||||
|
||||
@@ -68,18 +68,29 @@ In such cases you can visit the URL of the failed deployment and append `/_logs`
|
||||
|
||||
The logs of this deployment will contain the actual error which may help you to understand what went wrong.
|
||||
|
||||
### @zeit/ncc integration
|
||||
### @zeit/node-file-trace
|
||||
|
||||
Some of the builders use `@zeit/ncc` to bundle files before deployment. If you suspect an error with the bundling mechanism, you can run the `ncc` CLI with a couple modifications to the test.
|
||||
Some of the Builders use `@zeit/node-file-trace` to tree-shake files before deployment. If you suspect an error with this tree-shaking mechanism, you can create the following script in your project:
|
||||
|
||||
For example if an error occurred in `now-node/test/fixtures/08-assets`
|
||||
|
||||
```
|
||||
cd packages/now-node/test/fixtures/08-assets
|
||||
yarn install
|
||||
echo 'require("http").createServer(module.exports).listen(3000)' >> index.js
|
||||
npx @zeit/ncc@0.20.1 build index.js --source-map
|
||||
node dist
|
||||
```js
|
||||
const trace = require('@zeit/node-file-trace');
|
||||
trace(['path/to/entrypoint.js'], {
|
||||
ts: true,
|
||||
mixedModules: true,
|
||||
})
|
||||
.then(o => console.log(o.fileList))
|
||||
.then(e => console.error(e));
|
||||
```
|
||||
|
||||
This will compile the test with the specific version of `ncc` and run the resulting file. If it fails here, then there is likely a bug in `ncc` and not the Builder.
|
||||
When you run this script, you'll see all imported files. If anything file is missing, the bug is in [@zeit/node-file-trace](https://github.com/zeit/node-file-trace) and not the Builder.
|
||||
|
||||
## Deploy a Builder with existing project
|
||||
|
||||
Sometimes you want to test changes to a Builder against an existing project, maybe with `now dev` or an actual deployment. You can avoid publishing every Builder change to npm by uploading the Builder as a tarball.
|
||||
|
||||
1. Change directory to the desired Builder `cd ./packages/now-node`
|
||||
2. Run `yarn build` to compile typescript and other build steps
|
||||
3. Run `npm pack` to create a tarball file
|
||||
4. Run `now *.tgz` to upload the tarball file and get a URL
|
||||
5. Edit any existing `now.json` project and replace `use` with the URL
|
||||
6. Run `now` or `now dev` to deploy with the experimental Builder
|
||||
|
||||
40
PUBLISHING.md
Normal file
40
PUBLISHING.md
Normal file
@@ -0,0 +1,40 @@
|
||||
# Publishing to npm
|
||||
|
||||
Always publish to the Canary Channel as soon as a PR is merged into the `canary` branch.
|
||||
|
||||
```
|
||||
yarn publish-canary
|
||||
```
|
||||
|
||||
Publish the Stable Channel weekly.
|
||||
|
||||
- Cherry pick each commit from `canary` to `master` branch
|
||||
- Verify that you are _in-sync_ with canary (with the exception of the `version` line in `package.json`)
|
||||
- Deploy the modified Builders
|
||||
|
||||
```
|
||||
# View differences excluding "Publish" commits
|
||||
git checkout canary && git pull
|
||||
git log --pretty=format:"$ad- %s [%an]" | grep -v Publish > ~/Desktop/canary.txt
|
||||
git checkout master && git pull
|
||||
git log --pretty=format:"$ad- %s [%an]" | grep -v Publish > ~/Desktop/master.txt
|
||||
diff ~/Desktop/canary.txt ~/Desktop/master.txt
|
||||
|
||||
# Cherry pick all PRs from canary into master ...
|
||||
git cherry-pick <PR501_COMMIT_SHA>
|
||||
git cherry-pick <PR502_COMMIT_SHA>
|
||||
git cherry-pick <PR503_COMMIT_SHA>
|
||||
git cherry-pick <PR504_COMMIT_SHA>
|
||||
|
||||
# Verify the only difference is "version" in package.json
|
||||
git diff origin/canary
|
||||
|
||||
# Ship it
|
||||
yarn publish-stable
|
||||
```
|
||||
|
||||
After running this publish step, GitHub Actions will take care of publishing the modified Builder packages to npm.
|
||||
|
||||
If for some reason GitHub Actions fails to publish the npm package, you may do so
|
||||
manually by running `npm publish` from the package directory. Make sure to
|
||||
use `npm publish --tag canary` if you are publishing a canary release!
|
||||
60
README.md
60
README.md
@@ -2,64 +2,18 @@
|
||||
|
||||
This is a monorepo containing the [Official Builders](https://zeit.co/docs/v2/advanced/builders) provided by the ZEIT team.
|
||||
|
||||
## Channels
|
||||
## Versioning and advanced usage
|
||||
|
||||
There are two Channels:
|
||||
See [VERSIONING.md](VERSIONING.md).
|
||||
|
||||
| Channel | Git Branch | npm dist-tag | use example |
|
||||
| ------- | ------------------------------------------------------------- | ------------ | ------------------ |
|
||||
| Canary | [canary](https://github.com/zeit/now-builders/commits/canary) | `@canary` | `@now/node@canary` |
|
||||
| Stable | [master](https://github.com/zeit/now-builders/commits/master) | `@latest` | `@now/node@latest` |
|
||||
## Publishing to npm
|
||||
|
||||
All PRs should be submitted to the `canary` branch.
|
||||
See [PUBLISHING.md](PUBLISHING.md).
|
||||
|
||||
Once a PR is merged into the `canary` branch, it should be published to npm immediately using the Canary Channel.
|
||||
## Contributing
|
||||
|
||||
### Publishing to npm
|
||||
|
||||
For the Canary Channel, publish the modified Builders to npm with the following:
|
||||
|
||||
```
|
||||
yarn publish-canary
|
||||
```
|
||||
|
||||
For the Stable Channel, you must do the following:
|
||||
|
||||
- Cherry pick each commit from canary to master
|
||||
- Verify that you are _in-sync_ with canary (with the exception of the `version` line in `package.json`)
|
||||
- Deploy the modified Builders
|
||||
|
||||
```
|
||||
# View differences excluding "Publish" commits
|
||||
git checkout canary && git pull
|
||||
git log --pretty=format:"$ad- %s [%an]" | grep -v Publish > ~/Desktop/canary.txt
|
||||
git checkout master && git pull
|
||||
git log --pretty=format:"$ad- %s [%an]" | grep -v Publish > ~/Desktop/master.txt
|
||||
diff ~/Desktop/canary.txt ~/Desktop/master.txt
|
||||
|
||||
# Cherry pick all PRs from canary into master ...
|
||||
git cherry-pick <PR501_COMMIT_SHA>
|
||||
git cherry-pick <PR502_COMMIT_SHA>
|
||||
git cherry-pick <PR503_COMMIT_SHA>
|
||||
git cherry-pick <PR504_COMMIT_SHA>
|
||||
|
||||
# Verify the only difference is "version" in package.json
|
||||
git diff origin/canary
|
||||
|
||||
# Ship it
|
||||
yarn publish-stable
|
||||
```
|
||||
|
||||
After running this publish step, GitHub Actions will take care of publishing the modified Builder packages to npm.
|
||||
|
||||
If for some reason GitHub Actions fails to publish the npm package, you may do so
|
||||
manually by running `npm publish` from the package directory. Make sure to
|
||||
use `npm publish --tag canary` if you are publishing a canary release!
|
||||
|
||||
### Contributing
|
||||
|
||||
See the [Contribution guidelines for this project](CONTRIBUTING.md), it also contains guidance on interpreting tests failures.
|
||||
See [CONTRIBUTING.md](CONTRIBUTING.md).
|
||||
|
||||
### Creating Your Own Builder
|
||||
|
||||
To create your own Builder, see [the Builder's Developer Reference](DEVELOPING_A_BUILDER.md).
|
||||
See [DEVELOPING_A_BUILDER.md](DEVELOPING_A_BUILDER.md).
|
||||
|
||||
25
VERSIONING.md
Normal file
25
VERSIONING.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# Versioning
|
||||
|
||||
Builders are released to two different channels.
|
||||
|
||||
## Channels
|
||||
|
||||
| Channel | Git Branch | npm dist-tag | use example |
|
||||
| ------- | ------------------------------------------------------------- | ------------ | ------------------ |
|
||||
| Canary | [canary](https://github.com/zeit/now-builders/commits/canary) | `@canary` | `@now/node@canary` |
|
||||
| Stable | [master](https://github.com/zeit/now-builders/commits/master) | `@latest` | `@now/node@latest` |
|
||||
|
||||
All PRs are submitted to the `canary` branch. Once a PR is merged into the `canary` branch, it should be published to npm immediately using the Canary Channel.
|
||||
|
||||
## Version Selection
|
||||
|
||||
Since Builders are published to [npmjs.com](https://npmjs.com), this makes versioning works the same for Builders as it does for any npm package. The `use` statement in [now.json](https://zeit.co/docs/v2/advanced/configuration#builds) has a similar syntax to `npm install`.
|
||||
|
||||
The following are valid examples [@now/node](https://www.npmjs.com/package/@now/node?activeTab=versions):
|
||||
|
||||
- `@now/node`
|
||||
- `@now/node@0.7.3`
|
||||
- `@now/node@canary`
|
||||
- `@now/node@0.7.2-canary.2`
|
||||
|
||||
We always recommend using the latest version by leaving off the dist-tag suffix, `@now/node` for example.
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@now/build-utils",
|
||||
"version": "0.9.11",
|
||||
"version": "0.9.13",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.js",
|
||||
|
||||
@@ -7,25 +7,12 @@ interface ErrorResponse {
|
||||
}
|
||||
|
||||
interface Options {
|
||||
tag?: 'canary' | 'latest';
|
||||
tag?: 'canary' | 'latest' | string;
|
||||
}
|
||||
|
||||
const src: string = 'package.json';
|
||||
const config: Config = { zeroConfig: true };
|
||||
|
||||
// Static builders are special cased in `@now/static-build`
|
||||
const BUILDERS = new Map<string, Builder>([
|
||||
['next', { src, use: '@now/next', config }],
|
||||
]);
|
||||
|
||||
const API_BUILDERS: Builder[] = [
|
||||
{ src: 'api/**/*.js', use: '@now/node', config },
|
||||
{ src: 'api/**/*.ts', use: '@now/node', config },
|
||||
{ src: 'api/**/*.go', use: '@now/go', config },
|
||||
{ src: 'api/**/*.py', use: '@now/python', config },
|
||||
{ src: 'api/**/*.rb', use: '@now/ruby', config },
|
||||
];
|
||||
|
||||
const MISSING_BUILD_SCRIPT_ERROR: ErrorResponse = {
|
||||
code: 'missing_build_script',
|
||||
message:
|
||||
@@ -33,6 +20,25 @@ const MISSING_BUILD_SCRIPT_ERROR: ErrorResponse = {
|
||||
'\nMore details: https://zeit.co/docs/v2/advanced/platform/frequently-asked-questions#missing-build-script',
|
||||
};
|
||||
|
||||
// Static builders are special cased in `@now/static-build`
|
||||
function getBuilders(): Map<string, Builder> {
|
||||
return new Map<string, Builder>([
|
||||
['next', { src, use: '@now/next', config }],
|
||||
]);
|
||||
}
|
||||
|
||||
// Must be a function to ensure that the returned
|
||||
// object won't be a reference
|
||||
function getApiBuilders(): Builder[] {
|
||||
return [
|
||||
{ src: 'api/**/*.js', use: '@now/node', config },
|
||||
{ src: 'api/**/*.ts', use: '@now/node', config },
|
||||
{ src: 'api/**/*.go', use: '@now/go', config },
|
||||
{ src: 'api/**/*.py', use: '@now/python', config },
|
||||
{ src: 'api/**/*.rb', use: '@now/ruby', config },
|
||||
];
|
||||
}
|
||||
|
||||
function hasPublicDirectory(files: string[]) {
|
||||
return files.some(name => name.startsWith('public/'));
|
||||
}
|
||||
@@ -43,7 +49,7 @@ function hasBuildScript(pkg: PackageJson | undefined) {
|
||||
}
|
||||
|
||||
async function detectBuilder(pkg: PackageJson): Promise<Builder> {
|
||||
for (const [dependency, builder] of BUILDERS) {
|
||||
for (const [dependency, builder] of getBuilders()) {
|
||||
const deps = Object.assign({}, pkg.dependencies, pkg.devDependencies);
|
||||
|
||||
// Return the builder when a dependency matches
|
||||
@@ -72,7 +78,7 @@ export function ignoreApiFilter(file: string) {
|
||||
|
||||
// If the file does not match any builder we also
|
||||
// don't want to create a route e.g. `package.json`
|
||||
if (API_BUILDERS.every(({ src }) => !minimatch(file, src))) {
|
||||
if (getApiBuilders().every(({ src }) => !minimatch(file, src))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -90,7 +96,7 @@ async function detectApiBuilders(files: string[]): Promise<Builder[]> {
|
||||
.sort(sortFiles)
|
||||
.filter(ignoreApiFilter)
|
||||
.map(file => {
|
||||
const result = API_BUILDERS.find(
|
||||
const result = getApiBuilders().find(
|
||||
({ src }): boolean => minimatch(file, src)
|
||||
);
|
||||
|
||||
@@ -155,7 +161,10 @@ export async function detectBuilders(
|
||||
const tag = options && options.tag;
|
||||
|
||||
if (tag) {
|
||||
builders = builders.map((builder: Builder) => {
|
||||
builders = builders.map((originBuilder: Builder) => {
|
||||
// Copy builder to make sure it is not a reference
|
||||
const builder = { ...originBuilder };
|
||||
|
||||
// @now/static has no canary builder
|
||||
if (builder.use !== '@now/static') {
|
||||
builder.use = `${builder.use}@${tag}`;
|
||||
|
||||
@@ -58,19 +58,30 @@ function createRouteFromPath(filePath: string): Route {
|
||||
} else if (isLast) {
|
||||
const { name: fileName, ext } = parsePath(segment);
|
||||
const isIndex = fileName === 'index';
|
||||
const prefix = isIndex ? '\\/' : '';
|
||||
|
||||
const names = [
|
||||
prefix,
|
||||
prefix + escapeName(fileName),
|
||||
prefix + escapeName(fileName) + escapeName(ext),
|
||||
].filter(Boolean);
|
||||
|
||||
// Either filename with extension, filename without extension
|
||||
// or nothing when the filename is `index`
|
||||
return `(${escapeName(fileName)}|${escapeName(fileName)}${escapeName(
|
||||
ext
|
||||
)})${isIndex ? '?' : ''}`;
|
||||
return `(${names.join('|')})${isIndex ? '?' : ''}`;
|
||||
}
|
||||
|
||||
return segment;
|
||||
}
|
||||
);
|
||||
|
||||
const src = `^/${srcParts.join('/')}$`;
|
||||
const { name: fileName } = parsePath(filePath);
|
||||
const isIndex = fileName === 'index';
|
||||
|
||||
const src = isIndex
|
||||
? `^/${srcParts.slice(0, -1).join('/')}${srcParts.slice(-1)[0]}$`
|
||||
: `^/${srcParts.join('/')}$`;
|
||||
|
||||
const dest = `/${filePath}${query.length ? '?' : ''}${query.join('&')}`;
|
||||
|
||||
return { src, dest };
|
||||
|
||||
1
packages/now-build-utils/test/fixtures/01-zero-config-api/.gitignore
vendored
Normal file
1
packages/now-build-utils/test/fixtures/01-zero-config-api/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
now.json
|
||||
3
packages/now-build-utils/test/fixtures/01-zero-config-api/api/[endpoint].js
vendored
Normal file
3
packages/now-build-utils/test/fixtures/01-zero-config-api/api/[endpoint].js
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = (req, res) => {
|
||||
res.end(req.query.endpoint);
|
||||
};
|
||||
3
packages/now-build-utils/test/fixtures/01-zero-config-api/api/[endpoint]/[id].js
vendored
Normal file
3
packages/now-build-utils/test/fixtures/01-zero-config-api/api/[endpoint]/[id].js
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = (req, res) => {
|
||||
res.end(`${req.query.endpoint}/${req.query.id}`);
|
||||
};
|
||||
5
packages/now-build-utils/test/fixtures/01-zero-config-api/package.json
vendored
Normal file
5
packages/now-build-utils/test/fixtures/01-zero-config-api/package.json
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"scripts": {
|
||||
"build": "mkdir -p public && echo 'hello from index.txt' > public/index.txt"
|
||||
}
|
||||
}
|
||||
1
packages/now-build-utils/test/fixtures/02-zero-config-api/.gitignore
vendored
Normal file
1
packages/now-build-utils/test/fixtures/02-zero-config-api/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
now.json
|
||||
3
packages/now-build-utils/test/fixtures/02-zero-config-api/api/date.js
vendored
Normal file
3
packages/now-build-utils/test/fixtures/02-zero-config-api/api/date.js
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = (req, res) => {
|
||||
res.end('hello from api/date.js');
|
||||
};
|
||||
3
packages/now-build-utils/test/fixtures/02-zero-config-api/api/date/index.js
vendored
Normal file
3
packages/now-build-utils/test/fixtures/02-zero-config-api/api/date/index.js
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = (req, res) => {
|
||||
res.end('hello from api/date/index.js');
|
||||
};
|
||||
3
packages/now-build-utils/test/fixtures/02-zero-config-api/api/index.js
vendored
Normal file
3
packages/now-build-utils/test/fixtures/02-zero-config-api/api/index.js
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = (req, res) => {
|
||||
res.end('hello from api/index.js');
|
||||
};
|
||||
5
packages/now-build-utils/test/fixtures/02-zero-config-api/package.json
vendored
Normal file
5
packages/now-build-utils/test/fixtures/02-zero-config-api/package.json
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"scripts": {
|
||||
"build": "mkdir -p public && echo 'hello from index.txt' > public/index.txt"
|
||||
}
|
||||
}
|
||||
@@ -4,21 +4,21 @@ const fs = require('fs-extra');
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
const execa = require('execa');
|
||||
const assert = require('assert');
|
||||
const { createZip } = require('../dist/lambda');
|
||||
const {
|
||||
glob, download, detectBuilders, detectRoutes,
|
||||
} = require('../');
|
||||
const { createZip } = require('../dist/lambda');
|
||||
const {
|
||||
getSupportedNodeVersion,
|
||||
defaultSelection,
|
||||
} = require('../dist/fs/node-version');
|
||||
|
||||
const {
|
||||
packAndDeploy,
|
||||
testDeployment,
|
||||
} = require('../../../test/lib/deployment/test-deployment.js');
|
||||
} = require('../../../test/lib/deployment/test-deployment');
|
||||
|
||||
jest.setTimeout(4 * 60 * 1000);
|
||||
|
||||
const builderUrl = '@canary';
|
||||
let buildUtilsUrl;
|
||||
|
||||
@@ -152,6 +152,11 @@ const fixturesPath = path.resolve(__dirname, 'fixtures');
|
||||
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
for (const fixture of fs.readdirSync(fixturesPath)) {
|
||||
if (fixture.includes('zero-config')) {
|
||||
// Those have separate tests
|
||||
continue; // eslint-disable-line no-continue
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-loop-func
|
||||
it(`should build ${fixture}`, async () => {
|
||||
await expect(
|
||||
@@ -446,6 +451,44 @@ it('Test `detectBuilders`', async () => {
|
||||
expect(builders[2].use).toBe('@now/next@canary');
|
||||
expect(builders.length).toBe(3);
|
||||
}
|
||||
|
||||
{
|
||||
// package.json + api + latest
|
||||
const pkg = {
|
||||
scripts: { build: 'next build' },
|
||||
dependencies: { next: '9.0.0' },
|
||||
};
|
||||
const files = [
|
||||
'pages/index.js',
|
||||
'api/[endpoint].js',
|
||||
'api/[endpoint]/[id].js',
|
||||
];
|
||||
|
||||
const { builders } = await detectBuilders(files, pkg, { tag: 'latest' });
|
||||
expect(builders[0].use).toBe('@now/node@latest');
|
||||
expect(builders[1].use).toBe('@now/node@latest');
|
||||
expect(builders[2].use).toBe('@now/next@latest');
|
||||
expect(builders.length).toBe(3);
|
||||
}
|
||||
|
||||
{
|
||||
// package.json + api + random tag
|
||||
const pkg = {
|
||||
scripts: { build: 'next build' },
|
||||
dependencies: { next: '9.0.0' },
|
||||
};
|
||||
const files = [
|
||||
'pages/index.js',
|
||||
'api/[endpoint].js',
|
||||
'api/[endpoint]/[id].js',
|
||||
];
|
||||
|
||||
const { builders } = await detectBuilders(files, pkg, { tag: 'haha' });
|
||||
expect(builders[0].use).toBe('@now/node@haha');
|
||||
expect(builders[1].use).toBe('@now/node@haha');
|
||||
expect(builders[2].use).toBe('@now/next@haha');
|
||||
expect(builders.length).toBe(3);
|
||||
}
|
||||
});
|
||||
|
||||
it('Test `detectRoutes`', async () => {
|
||||
@@ -548,7 +591,9 @@ it('Test `detectRoutes`', async () => {
|
||||
const { defaultRoutes } = await detectRoutes(files, builders);
|
||||
|
||||
expect(defaultRoutes.length).toBe(3);
|
||||
expect(defaultRoutes[0].src).toBe('^/api/date/(index|index\\.js)?$');
|
||||
expect(defaultRoutes[0].src).toBe(
|
||||
'^/api/date(\\/|\\/index|\\/index\\.js)?$',
|
||||
);
|
||||
expect(defaultRoutes[0].dest).toBe('/api/date/index.js');
|
||||
expect(defaultRoutes[1].src).toBe('^/api/(date|date\\.js)$');
|
||||
expect(defaultRoutes[1].dest).toBe('/api/date.js');
|
||||
@@ -561,7 +606,9 @@ it('Test `detectRoutes`', async () => {
|
||||
const { defaultRoutes } = await detectRoutes(files, builders);
|
||||
|
||||
expect(defaultRoutes.length).toBe(3);
|
||||
expect(defaultRoutes[0].src).toBe('^/api/([^\\/]+)/(index|index\\.js)?$');
|
||||
expect(defaultRoutes[0].src).toBe(
|
||||
'^/api/([^\\/]+)(\\/|\\/index|\\/index\\.js)?$',
|
||||
);
|
||||
expect(defaultRoutes[0].dest).toBe('/api/[date]/index.js?date=$1');
|
||||
expect(defaultRoutes[1].src).toBe('^/api/(date|date\\.js)$');
|
||||
expect(defaultRoutes[1].dest).toBe('/api/date.js');
|
||||
@@ -587,3 +634,146 @@ it('Test `detectRoutes`', async () => {
|
||||
expect(defaultRoutes.length).toBe(5);
|
||||
}
|
||||
});
|
||||
|
||||
it('Test `detectBuilders` and `detectRoutes`', async () => {
|
||||
const fixture = path.join(__dirname, 'fixtures', '01-zero-config-api');
|
||||
const pkg = await fs.readJSON(path.join(fixture, 'package.json'));
|
||||
const fileList = await glob('**', fixture);
|
||||
const files = Object.keys(fileList);
|
||||
|
||||
const probes = [
|
||||
{
|
||||
path: '/api/my-endpoint',
|
||||
mustContain: 'my-endpoint',
|
||||
status: 200,
|
||||
},
|
||||
{
|
||||
path: '/api/other-endpoint',
|
||||
mustContain: 'other-endpoint',
|
||||
status: 200,
|
||||
},
|
||||
{
|
||||
path: '/api/team/zeit',
|
||||
mustContain: 'team/zeit',
|
||||
status: 200,
|
||||
},
|
||||
{
|
||||
path: '/api/user/myself',
|
||||
mustContain: 'user/myself',
|
||||
status: 200,
|
||||
},
|
||||
{
|
||||
path: '/api/not-okay/',
|
||||
status: 404,
|
||||
},
|
||||
{
|
||||
path: '/api',
|
||||
status: 404,
|
||||
},
|
||||
{
|
||||
path: '/api/',
|
||||
status: 404,
|
||||
},
|
||||
{
|
||||
path: '/',
|
||||
mustContain: 'hello from index.txt',
|
||||
},
|
||||
];
|
||||
|
||||
const { builders } = await detectBuilders(files, pkg);
|
||||
const { defaultRoutes } = await detectRoutes(files, builders);
|
||||
|
||||
const nowConfig = { builds: builders, routes: defaultRoutes, probes };
|
||||
await fs.writeFile(
|
||||
path.join(fixture, 'now.json'),
|
||||
JSON.stringify(nowConfig, null, 2),
|
||||
);
|
||||
|
||||
const deployment = await testDeployment(
|
||||
{ builderUrl, buildUtilsUrl },
|
||||
fixture,
|
||||
);
|
||||
expect(deployment).toBeDefined();
|
||||
});
|
||||
|
||||
it('Test `detectBuilders` and `detectRoutes` 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);
|
||||
const files = Object.keys(fileList);
|
||||
|
||||
const probes = [
|
||||
{
|
||||
path: '/api/not-okay',
|
||||
status: 404,
|
||||
},
|
||||
{
|
||||
path: '/api',
|
||||
mustContain: 'hello from api/index.js',
|
||||
status: 200,
|
||||
},
|
||||
{
|
||||
path: '/api/',
|
||||
mustContain: 'hello from api/index.js',
|
||||
status: 200,
|
||||
},
|
||||
{
|
||||
path: '/api/index',
|
||||
mustContain: 'hello from api/index.js',
|
||||
status: 200,
|
||||
},
|
||||
{
|
||||
path: '/api/index.js',
|
||||
mustContain: 'hello from api/index.js',
|
||||
status: 200,
|
||||
},
|
||||
{
|
||||
path: '/api/date.js',
|
||||
mustContain: 'hello from api/date.js',
|
||||
status: 200,
|
||||
},
|
||||
{
|
||||
// Someone might expect this to be `date.js`,
|
||||
// but I doubt that there is any case were both
|
||||
// `date/index.js` and `date.js` exists,
|
||||
// so it is not special cased
|
||||
path: '/api/date',
|
||||
mustContain: 'hello from api/date/index.js',
|
||||
status: 200,
|
||||
},
|
||||
{
|
||||
path: '/api/date/',
|
||||
mustContain: 'hello from api/date/index.js',
|
||||
status: 200,
|
||||
},
|
||||
{
|
||||
path: '/api/date/index',
|
||||
mustContain: 'hello from api/date/index.js',
|
||||
status: 200,
|
||||
},
|
||||
{
|
||||
path: '/api/date/index.js',
|
||||
mustContain: 'hello from api/date/index.js',
|
||||
status: 200,
|
||||
},
|
||||
{
|
||||
path: '/',
|
||||
mustContain: 'hello from index.txt',
|
||||
},
|
||||
];
|
||||
|
||||
const { builders } = await detectBuilders(files, pkg);
|
||||
const { defaultRoutes } = await detectRoutes(files, builders);
|
||||
|
||||
const nowConfig = { builds: builders, routes: defaultRoutes, probes };
|
||||
await fs.writeFile(
|
||||
path.join(fixture, 'now.json'),
|
||||
JSON.stringify(nowConfig, null, 2),
|
||||
);
|
||||
|
||||
const deployment = await testDeployment(
|
||||
{ builderUrl, buildUtilsUrl },
|
||||
fixture,
|
||||
);
|
||||
expect(deployment).toBeDefined();
|
||||
});
|
||||
|
||||
@@ -1,2 +1,4 @@
|
||||
ncc build index.ts -o dist
|
||||
ncc build install.ts -o dist/install
|
||||
mv dist/install/index.js dist/install.js
|
||||
rm -rf dist/install
|
||||
|
||||
@@ -106,7 +106,7 @@ Learn more: https://github.com/golang/go/wiki/Modules
|
||||
if (!analyzed) {
|
||||
const err = new Error(
|
||||
`Could not find an exported function in "${entrypoint}"
|
||||
Learn more: https://zeit.co/docs/v2/deployments/official-builders/go-now-go/#entrypoint
|
||||
Learn more: https://zeit.co/docs/v2/advanced/builders/#go
|
||||
`
|
||||
);
|
||||
console.log(err.message);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@now/go",
|
||||
"version": "0.5.8",
|
||||
"version": "0.5.10",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index",
|
||||
"homepage": "https://zeit.co/docs/v2/deployments/official-builders/go-now-go",
|
||||
@@ -13,7 +13,7 @@
|
||||
"build": "./build.sh",
|
||||
"test": "./build.sh && jest",
|
||||
"prepublish": "./build.sh",
|
||||
"now-postinstall": "node dist/install/index.js"
|
||||
"now-postinstall": "node dist/install.js"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
|
||||
9
packages/now-go/test/fixtures/02-parallel/api/go-one/one.go
vendored
Normal file
9
packages/now-go/test/fixtures/02-parallel/api/go-one/one.go
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
package handler
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
// Handler is cool
|
||||
func Handler(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintf(w, "ONE:RANDOMNESS_PLACEHOLDER")
|
||||
}
|
||||
9
packages/now-go/test/fixtures/02-parallel/api/go-two/two.go
vendored
Normal file
9
packages/now-go/test/fixtures/02-parallel/api/go-two/two.go
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
package handler
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
// Handler is cool
|
||||
func Handler(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintf(w, "TWO:RANDOMNESS_PLACEHOLDER")
|
||||
}
|
||||
3
packages/now-go/test/fixtures/02-parallel/api/go.mod
vendored
Normal file
3
packages/now-go/test/fixtures/02-parallel/api/go.mod
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
module go-example
|
||||
|
||||
go 1.12
|
||||
25
packages/now-go/test/fixtures/02-parallel/now.json
vendored
Normal file
25
packages/now-go/test/fixtures/02-parallel/now.json
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"version": 2,
|
||||
"builds": [
|
||||
{
|
||||
"src": "/api/go-one/one.go",
|
||||
"use": "@now/go",
|
||||
"config": { "parallel": true }
|
||||
},
|
||||
{
|
||||
"src": "/api/go-two/two.go",
|
||||
"use": "@now/go",
|
||||
"config": { "parallel": true }
|
||||
}
|
||||
],
|
||||
"probes": [
|
||||
{
|
||||
"path": "/api/go-one/one.go",
|
||||
"mustContain": "ONE:RANDOMNESS_PLACEHOLDER"
|
||||
},
|
||||
{
|
||||
"path": "/api/go-two/two.go",
|
||||
"mustContain": "TWO:RANDOMNESS_PLACEHOLDER"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@now/next",
|
||||
"version": "0.5.9",
|
||||
"version": "0.7.0",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index",
|
||||
"homepage": "https://zeit.co/docs/v2/deployments/official-builders/next-js-now-next",
|
||||
@@ -21,6 +21,7 @@
|
||||
"@types/next-server": "8.0.0",
|
||||
"@types/resolve-from": "5.0.1",
|
||||
"@types/semver": "6.0.0",
|
||||
"@zeit/node-file-trace": "0.2.13",
|
||||
"fs-extra": "7.0.0",
|
||||
"get-port": "5.0.0",
|
||||
"resolve-from": "5.0.0",
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
import path from 'path';
|
||||
import fs from 'fs-extra';
|
||||
import path from 'path';
|
||||
import semver from 'semver';
|
||||
|
||||
function getCustomData(importName: string) {
|
||||
import { ExperimentalTraceVersion } from './utils';
|
||||
|
||||
function getCustomData(importName: string, target: string) {
|
||||
return `
|
||||
module.exports = function(...args) {
|
||||
let original = require('./${importName}');
|
||||
|
||||
const finalConfig = {};
|
||||
const target = { target: 'serverless' };
|
||||
const target = { target: '${target}' };
|
||||
|
||||
if (typeof original === 'function' && original.constructor.name === 'AsyncFunction') {
|
||||
// AsyncFunctions will become promises
|
||||
@@ -37,14 +40,26 @@ function getDefaultData() {
|
||||
return `module.exports = { target: 'serverless' };`;
|
||||
}
|
||||
|
||||
export default async function createServerlessConfig(workPath: string) {
|
||||
export default async function createServerlessConfig(
|
||||
workPath: string,
|
||||
nextVersion: string | undefined
|
||||
) {
|
||||
let target = 'serverless';
|
||||
if (nextVersion) {
|
||||
try {
|
||||
if (semver.gte(nextVersion, ExperimentalTraceVersion)) {
|
||||
target = 'experimental-serverless-trace';
|
||||
}
|
||||
} catch (_ignored) {}
|
||||
}
|
||||
|
||||
const configPath = path.join(workPath, 'next.config.js');
|
||||
const backupConfigName = `next.config.original.${Date.now()}.js`;
|
||||
const backupConfigPath = path.join(workPath, backupConfigName);
|
||||
|
||||
if (fs.existsSync(configPath)) {
|
||||
await fs.rename(configPath, backupConfigPath);
|
||||
await fs.writeFile(configPath, getCustomData(backupConfigName));
|
||||
await fs.writeFile(configPath, getCustomData(backupConfigName, target));
|
||||
} else {
|
||||
await fs.writeFile(configPath, getDefaultData());
|
||||
}
|
||||
|
||||
@@ -7,10 +7,12 @@ import {
|
||||
} from 'fs-extra';
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
import resolveFrom from 'resolve-from';
|
||||
import semver from 'semver';
|
||||
|
||||
import {
|
||||
BuildOptions,
|
||||
Config,
|
||||
createLambda,
|
||||
download,
|
||||
FileBlob,
|
||||
@@ -21,16 +23,18 @@ import {
|
||||
glob,
|
||||
Lambda,
|
||||
PrepareCacheOptions,
|
||||
Route,
|
||||
runNpmInstall,
|
||||
runPackageJsonScript,
|
||||
Route,
|
||||
} from '@now/build-utils';
|
||||
import nodeFileTrace from '@zeit/node-file-trace';
|
||||
|
||||
import createServerlessConfig from './create-serverless-config';
|
||||
import nextLegacyVersions from './legacy-versions';
|
||||
import {
|
||||
EnvConfig,
|
||||
excludeFiles,
|
||||
ExperimentalTraceVersion,
|
||||
filesFromDirectory,
|
||||
getDynamicRoutes,
|
||||
getNextConfig,
|
||||
@@ -156,7 +160,7 @@ export const build = async ({
|
||||
files,
|
||||
workPath,
|
||||
entrypoint,
|
||||
config,
|
||||
config = {} as Config,
|
||||
meta = {} as BuildParamsMeta,
|
||||
}: BuildParamsType): Promise<{
|
||||
routes: Route[];
|
||||
@@ -176,10 +180,6 @@ export const build = async ({
|
||||
const pkg = await readPackageJson(entryPath);
|
||||
const nextVersion = getNextVersion(pkg);
|
||||
|
||||
if (!meta.isDev) {
|
||||
await createServerlessConfig(workPath);
|
||||
}
|
||||
|
||||
const nodeVersion = await getNodeVersion(entryPath, undefined, config);
|
||||
const spawnOpts = getSpawnOptions(meta, nodeVersion);
|
||||
|
||||
@@ -284,6 +284,20 @@ export const build = async ({
|
||||
console.log('installing dependencies...');
|
||||
await runNpmInstall(entryPath, ['--prefer-offline'], spawnOpts);
|
||||
|
||||
let realNextVersion: string | undefined;
|
||||
try {
|
||||
realNextVersion = require(resolveFrom(entryPath, 'next/package.json'))
|
||||
.version;
|
||||
|
||||
console.log(`detected Next.js version: ${realNextVersion}`);
|
||||
} catch (_ignored) {
|
||||
console.warn(`could not identify real Next.js version, that's OK!`);
|
||||
}
|
||||
|
||||
if (!isLegacy) {
|
||||
await createServerlessConfig(workPath, realNextVersion);
|
||||
}
|
||||
|
||||
console.log('running user script...');
|
||||
const memoryToConsume = Math.floor(os.totalmem() / 1024 ** 2) - 128;
|
||||
const env = { ...spawnOpts.env } as any;
|
||||
@@ -394,14 +408,6 @@ export const build = async ({
|
||||
);
|
||||
} else {
|
||||
console.log('preparing lambda files...');
|
||||
const launcherFiles = {
|
||||
'now__bridge.js': new FileFsRef({
|
||||
fsPath: path.join(__dirname, 'now__bridge.js'),
|
||||
}),
|
||||
'now__launcher.js': new FileFsRef({
|
||||
fsPath: path.join(__dirname, 'launcher.js'),
|
||||
}),
|
||||
};
|
||||
const pagesDir = path.join(entryPath, '.next', 'serverless', 'pages');
|
||||
|
||||
const pages = await glob('**/*.js', pagesDir);
|
||||
@@ -440,18 +446,77 @@ export const build = async ({
|
||||
);
|
||||
}
|
||||
|
||||
// An optional assets folder that is placed alongside every page entrypoint
|
||||
const assets = await glob(
|
||||
'assets/**',
|
||||
path.join(entryPath, '.next', 'serverless')
|
||||
);
|
||||
|
||||
const assetKeys = Object.keys(assets);
|
||||
if (assetKeys.length > 0) {
|
||||
console.log('detected assets to be bundled with lambda:');
|
||||
assetKeys.forEach(assetFile => console.log(`\t${assetFile}`));
|
||||
// Assume tracing to be safe, bail if we know we don't need it.
|
||||
let requiresTracing = true;
|
||||
try {
|
||||
if (
|
||||
realNextVersion &&
|
||||
semver.lt(realNextVersion, ExperimentalTraceVersion)
|
||||
) {
|
||||
if (config.debug) {
|
||||
console.log(
|
||||
'Next.js version is too old for us to trace the required dependencies.\n' +
|
||||
'Assuming Next.js has handled it!'
|
||||
);
|
||||
}
|
||||
requiresTracing = false;
|
||||
}
|
||||
} catch (err) {
|
||||
if (config.debug) {
|
||||
console.log(
|
||||
'Failed to check Next.js version for tracing compatibility: ' + err
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let assets:
|
||||
| {
|
||||
[filePath: string]: FileFsRef;
|
||||
}
|
||||
| undefined;
|
||||
const tracedFiles: {
|
||||
[filePath: string]: FileFsRef;
|
||||
} = {};
|
||||
if (requiresTracing) {
|
||||
const tracingLabel = 'Tracing Next.js lambdas for external files ...';
|
||||
console.time(tracingLabel);
|
||||
|
||||
const { fileList } = await nodeFileTrace(
|
||||
Object.keys(pages).map(page => pages[page].fsPath),
|
||||
{ base: workPath }
|
||||
);
|
||||
if (config.debug) {
|
||||
console.log(`node-file-trace result for pages: ${fileList}`);
|
||||
}
|
||||
fileList.forEach(file => {
|
||||
tracedFiles[file] = new FileFsRef({
|
||||
fsPath: path.join(workPath, file),
|
||||
});
|
||||
});
|
||||
|
||||
console.timeEnd(tracingLabel);
|
||||
} else {
|
||||
// An optional assets folder that is placed alongside every page
|
||||
// entrypoint.
|
||||
// This is a legacy feature that was needed before we began tracing
|
||||
// lambdas.
|
||||
assets = await glob(
|
||||
'assets/**',
|
||||
path.join(entryPath, '.next', 'serverless')
|
||||
);
|
||||
|
||||
const assetKeys = Object.keys(assets!);
|
||||
if (assetKeys.length > 0) {
|
||||
console.log('detected (legacy) assets to be bundled with lambda:');
|
||||
assetKeys.forEach(assetFile => console.log(`\t${assetFile}`));
|
||||
console.log(
|
||||
'\nPlease upgrade to Next.js 9.1 to leverage modern asset handling.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const launcherPath = path.join(__dirname, 'templated-launcher.js');
|
||||
const launcherData = await readFile(launcherPath, 'utf8');
|
||||
await Promise.all(
|
||||
pageKeys.map(async page => {
|
||||
// These default pages don't have to be handled as they'd always 404
|
||||
@@ -465,17 +530,34 @@ export const build = async ({
|
||||
dynamicPages.push(normalizePage(pathname));
|
||||
}
|
||||
|
||||
console.log(`Creating lambda for page: "${page}"...`);
|
||||
const label = `Creating lambda for page: "${page}"...`;
|
||||
console.time(label);
|
||||
|
||||
const pageFileName = path.normalize(
|
||||
path.relative(workPath, pages[page].fsPath)
|
||||
);
|
||||
const launcher = launcherData.replace(
|
||||
/__LAUNCHER_PAGE_PATH__/g,
|
||||
JSON.stringify(requiresTracing ? `./${pageFileName}` : './page')
|
||||
);
|
||||
const launcherFiles = {
|
||||
'now__bridge.js': new FileFsRef({
|
||||
fsPath: path.join(__dirname, 'now__bridge.js'),
|
||||
}),
|
||||
'now__launcher.js': new FileBlob({ data: launcher }),
|
||||
};
|
||||
|
||||
lambdas[path.join(entryDirectory, pathname)] = await createLambda({
|
||||
files: {
|
||||
...launcherFiles,
|
||||
...assets,
|
||||
'page.js': pages[page],
|
||||
...tracedFiles,
|
||||
[requiresTracing ? pageFileName : 'page.js']: pages[page],
|
||||
},
|
||||
handler: 'now__launcher.launcher',
|
||||
runtime: nodeVersion.runtime,
|
||||
});
|
||||
console.log(`Created lambda for page: "${page}"`);
|
||||
console.timeEnd(label);
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,8 @@ if (!process.env.NODE_ENV) {
|
||||
|
||||
import { Server } from 'http';
|
||||
import { Bridge } from './now__bridge';
|
||||
const page = require('./page');
|
||||
// @ts-ignore
|
||||
const page = require(__LAUNCHER_PAGE_PATH__);
|
||||
|
||||
// page.render is for React rendering
|
||||
// page.default is for /api rendering
|
||||
@@ -356,6 +356,8 @@ function syncEnvVars(base: EnvConfig, removeEnv: EnvConfig, addEnv: EnvConfig) {
|
||||
Object.assign(base, addEnv);
|
||||
}
|
||||
|
||||
export const ExperimentalTraceVersion = `9.0.4-canary.1`;
|
||||
|
||||
export {
|
||||
excludeFiles,
|
||||
validateEntrypoint,
|
||||
|
||||
5
packages/now-next/test/fixtures/02-firebase-node-8/next.config.js
vendored
Normal file
5
packages/now-next/test/fixtures/02-firebase-node-8/next.config.js
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
generateBuildId() {
|
||||
return 'testing-build-id';
|
||||
},
|
||||
};
|
||||
8
packages/now-next/test/fixtures/02-firebase-node-8/now.json
vendored
Normal file
8
packages/now-next/test/fixtures/02-firebase-node-8/now.json
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"version": 2,
|
||||
"builds": [{ "src": "package.json", "use": "@now/next" }],
|
||||
"probes": [
|
||||
{ "path": "/nested/fb", "mustContain": "Hello Firebase: <!-- -->0" },
|
||||
{ "path": "/nested/moar/fb", "mustContain": "Hello Firebase: <!-- -->0" }
|
||||
]
|
||||
}
|
||||
11
packages/now-next/test/fixtures/02-firebase-node-8/package.json
vendored
Normal file
11
packages/now-next/test/fixtures/02-firebase-node-8/package.json
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"engines": {
|
||||
"node": "8.10.x"
|
||||
},
|
||||
"dependencies": {
|
||||
"next": "canary",
|
||||
"react": "^16.8.6",
|
||||
"react-dom": "^16.8.6",
|
||||
"firebase": "6.3.4"
|
||||
}
|
||||
}
|
||||
19
packages/now-next/test/fixtures/02-firebase-node-8/pages/nested/fb.js
vendored
Normal file
19
packages/now-next/test/fixtures/02-firebase-node-8/pages/nested/fb.js
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
import firebase from 'firebase/app';
|
||||
import 'firebase/firestore';
|
||||
|
||||
if (!firebase.apps.length) {
|
||||
firebase.initializeApp({ projectId: 'noop' });
|
||||
}
|
||||
|
||||
const store = firebase.firestore();
|
||||
|
||||
const Comp = ({ results }) => {
|
||||
return <div>Hello Firebase: {results}</div>;
|
||||
};
|
||||
|
||||
Comp.getInitialProps = async () => {
|
||||
const query = await store.collection('users').get();
|
||||
return { results: query.size };
|
||||
};
|
||||
|
||||
export default Comp;
|
||||
19
packages/now-next/test/fixtures/02-firebase-node-8/pages/nested/moar/[dynamic_fb].js
vendored
Normal file
19
packages/now-next/test/fixtures/02-firebase-node-8/pages/nested/moar/[dynamic_fb].js
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
import firebase from 'firebase/app';
|
||||
import 'firebase/firestore';
|
||||
|
||||
if (!firebase.apps.length) {
|
||||
firebase.initializeApp({ projectId: 'noop' });
|
||||
}
|
||||
|
||||
const store = firebase.firestore();
|
||||
|
||||
const Comp = ({ results }) => {
|
||||
return <div>Hello Firebase: {results}</div>;
|
||||
};
|
||||
|
||||
Comp.getInitialProps = async () => {
|
||||
const query = await store.collection('users').get();
|
||||
return { results: query.size };
|
||||
};
|
||||
|
||||
export default Comp;
|
||||
5
packages/now-next/test/fixtures/03-next-8/next.config.js
vendored
Normal file
5
packages/now-next/test/fixtures/03-next-8/next.config.js
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
generateBuildId() {
|
||||
return 'testing-build-id';
|
||||
},
|
||||
};
|
||||
8
packages/now-next/test/fixtures/03-next-8/now.json
vendored
Normal file
8
packages/now-next/test/fixtures/03-next-8/now.json
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"version": 2,
|
||||
"builds": [{ "src": "package.json", "use": "@now/next" }],
|
||||
"probes": [
|
||||
{ "path": "/hello1", "mustContain": "Hello World 1" },
|
||||
{ "path": "/nested/hello2", "mustContain": "Hello World 2" }
|
||||
]
|
||||
}
|
||||
7
packages/now-next/test/fixtures/03-next-8/package.json
vendored
Normal file
7
packages/now-next/test/fixtures/03-next-8/package.json
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"dependencies": {
|
||||
"next": "8.x.x",
|
||||
"react": "^16.8.6",
|
||||
"react-dom": "^16.8.6"
|
||||
}
|
||||
}
|
||||
7
packages/now-next/test/fixtures/03-next-8/pages/hello1.js
vendored
Normal file
7
packages/now-next/test/fixtures/03-next-8/pages/hello1.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
function A({ data }) {
|
||||
return <div>{data}</div>;
|
||||
}
|
||||
|
||||
A.getInitialProps = () => ({ data: 'Hello World 1' });
|
||||
|
||||
export default A;
|
||||
7
packages/now-next/test/fixtures/03-next-8/pages/nested/hello2.js
vendored
Normal file
7
packages/now-next/test/fixtures/03-next-8/pages/nested/hello2.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
function B({ data }) {
|
||||
return <div>{data}</div>;
|
||||
}
|
||||
|
||||
B.getInitialProps = () => ({ data: 'Hello World 2' });
|
||||
|
||||
export default B;
|
||||
5
packages/now-next/test/fixtures/04-firebase-node-10/next.config.js
vendored
Normal file
5
packages/now-next/test/fixtures/04-firebase-node-10/next.config.js
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
generateBuildId() {
|
||||
return 'testing-build-id';
|
||||
},
|
||||
};
|
||||
8
packages/now-next/test/fixtures/04-firebase-node-10/now.json
vendored
Normal file
8
packages/now-next/test/fixtures/04-firebase-node-10/now.json
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"version": 2,
|
||||
"builds": [{ "src": "package.json", "use": "@now/next" }],
|
||||
"probes": [
|
||||
{ "path": "/nested/fb", "mustContain": "Hello Firebase: <!-- -->0" },
|
||||
{ "path": "/nested/moar/fb", "mustContain": "Hello Firebase: <!-- -->0" }
|
||||
]
|
||||
}
|
||||
11
packages/now-next/test/fixtures/04-firebase-node-10/package.json
vendored
Normal file
11
packages/now-next/test/fixtures/04-firebase-node-10/package.json
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"engines": {
|
||||
"node": "10.x"
|
||||
},
|
||||
"dependencies": {
|
||||
"next": "canary",
|
||||
"react": "^16.8.6",
|
||||
"react-dom": "^16.8.6",
|
||||
"firebase": "6.3.4"
|
||||
}
|
||||
}
|
||||
19
packages/now-next/test/fixtures/04-firebase-node-10/pages/nested/fb.js
vendored
Normal file
19
packages/now-next/test/fixtures/04-firebase-node-10/pages/nested/fb.js
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
import firebase from 'firebase/app';
|
||||
import 'firebase/firestore';
|
||||
|
||||
if (!firebase.apps.length) {
|
||||
firebase.initializeApp({ projectId: 'noop' });
|
||||
}
|
||||
|
||||
const store = firebase.firestore();
|
||||
|
||||
const Comp = ({ results }) => {
|
||||
return <div>Hello Firebase: {results}</div>;
|
||||
};
|
||||
|
||||
Comp.getInitialProps = async () => {
|
||||
const query = await store.collection('users').get();
|
||||
return { results: query.size };
|
||||
};
|
||||
|
||||
export default Comp;
|
||||
19
packages/now-next/test/fixtures/04-firebase-node-10/pages/nested/moar/[dynamic_fb].js
vendored
Normal file
19
packages/now-next/test/fixtures/04-firebase-node-10/pages/nested/moar/[dynamic_fb].js
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
import firebase from 'firebase/app';
|
||||
import 'firebase/firestore';
|
||||
|
||||
if (!firebase.apps.length) {
|
||||
firebase.initializeApp({ projectId: 'noop' });
|
||||
}
|
||||
|
||||
const store = firebase.firestore();
|
||||
|
||||
const Comp = ({ results }) => {
|
||||
return <div>Hello Firebase: {results}</div>;
|
||||
};
|
||||
|
||||
Comp.getInitialProps = async () => {
|
||||
const query = await store.collection('users').get();
|
||||
return { results: query.size };
|
||||
};
|
||||
|
||||
export default Comp;
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@now/node",
|
||||
"version": "0.12.4",
|
||||
"version": "0.12.7",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index",
|
||||
"homepage": "https://zeit.co/docs/v2/deployments/official-builders/node-js-now-node",
|
||||
@@ -28,7 +28,7 @@
|
||||
"@types/etag": "1.8.0",
|
||||
"@types/test-listen": "1.1.0",
|
||||
"@zeit/ncc": "0.20.4",
|
||||
"@zeit/node-file-trace": "0.2.6",
|
||||
"@zeit/node-file-trace": "0.2.13",
|
||||
"content-type": "1.0.4",
|
||||
"cookie": "0.4.0",
|
||||
"etag": "1.8.1",
|
||||
|
||||
@@ -21,7 +21,7 @@ import {
|
||||
export { NowRequest, NowResponse } from './types';
|
||||
import { makeLauncher } from './launcher';
|
||||
import { readFileSync, lstatSync, readlinkSync, statSync } from 'fs';
|
||||
import { Compile } from './typescript';
|
||||
import { Register, register } from './typescript';
|
||||
|
||||
interface CompilerConfig {
|
||||
debug?: boolean;
|
||||
@@ -134,30 +134,20 @@ async function compile(
|
||||
|
||||
const preparedFiles: Files = {};
|
||||
|
||||
let tsCompile: Compile;
|
||||
let tsCompile: Register;
|
||||
function compileTypeScript(path: string, source: string): string {
|
||||
const relPath = relative(workPath, path);
|
||||
if (config.debug) {
|
||||
console.log('compiling typescript file ' + relPath);
|
||||
}
|
||||
if (!tsCompile) {
|
||||
tsCompile = require('./typescript').init({
|
||||
basePath: workPath,
|
||||
logError: true,
|
||||
tsCompile = register({
|
||||
basePath: workPath, // The base is the same as root now.json dir
|
||||
project: path, // Resolve tsconfig.json from entrypoint dir
|
||||
files: true, // Include all files such as global `.d.ts`
|
||||
});
|
||||
}
|
||||
try {
|
||||
var { code, map } = tsCompile(source, path);
|
||||
} catch (e) {
|
||||
if (config.debug) {
|
||||
console.error(e);
|
||||
console.log(
|
||||
'TypeScript compilation failed, falling back to basic transformModule'
|
||||
);
|
||||
}
|
||||
// If TypeScript compile fails, attempt a direct non-typecheck compile
|
||||
var { code, map } = tsCompile(source, path, true);
|
||||
}
|
||||
const { code, map } = tsCompile(source, path);
|
||||
tsCompiled.add(relPath);
|
||||
preparedFiles[
|
||||
relPath.slice(0, -3 - Number(path.endsWith('x'))) + '.js.map'
|
||||
@@ -239,7 +229,12 @@ async function compile(
|
||||
}
|
||||
}
|
||||
// Rename .ts -> .js (except for entry)
|
||||
if (path !== entrypoint && tsCompiled.has(path)) {
|
||||
// There is a bug on Windows where entrypoint uses forward slashes
|
||||
// and workPath uses backslashes so we use resolve before comparing.
|
||||
if (
|
||||
resolve(workPath, path) !== resolve(workPath, entrypoint) &&
|
||||
tsCompiled.has(path)
|
||||
) {
|
||||
preparedFiles[
|
||||
path.slice(0, -3 - Number(path.endsWith('x'))) + '.js'
|
||||
] = entry;
|
||||
|
||||
@@ -112,11 +112,11 @@ function normalizeSlashes(value: string): string {
|
||||
/**
|
||||
* Return type for registering `ts-node`.
|
||||
*/
|
||||
export type Compile = (
|
||||
export type Register = (
|
||||
code: string,
|
||||
fileName: string,
|
||||
skipTypeCheck?: boolean
|
||||
) => { code: string; map: string };
|
||||
) => SourceOutput;
|
||||
|
||||
/**
|
||||
* Cached fs operation wrapper.
|
||||
@@ -136,7 +136,7 @@ function cachedLookup<T>(fn: (arg: string) => T): (arg: string) => T {
|
||||
/**
|
||||
* Register TypeScript compiler.
|
||||
*/
|
||||
export function init(opts: Options = {}): Compile {
|
||||
export function register(opts: Options = {}): Register {
|
||||
const options = Object.assign({}, DEFAULTS, opts);
|
||||
|
||||
const ignoreDiagnostics = [
|
||||
@@ -148,7 +148,7 @@ export function init(opts: Options = {}): Compile {
|
||||
|
||||
// Require the TypeScript compiler and configuration.
|
||||
const cwd = options.basePath || process.cwd();
|
||||
const nowNodeBase = resolve(__dirname, '../../../');
|
||||
const nowNodeBase = resolve(__dirname, '..', '..', '..');
|
||||
try {
|
||||
var compiler = require.resolve(options.compiler || 'typescript', {
|
||||
paths: [cwd, nowNodeBase],
|
||||
@@ -182,14 +182,18 @@ export function init(opts: Options = {}): Compile {
|
||||
return new Error(diagnosticText);
|
||||
}
|
||||
|
||||
function reportTSError(configDiagnosticList: _ts.Diagnostic[]) {
|
||||
const error = createTSError(configDiagnosticList);
|
||||
if (options.logError) {
|
||||
// Print error in red color and continue execution.
|
||||
console.error('\x1b[31m%s\x1b[0m', error);
|
||||
} else {
|
||||
// Throw error and exit the script.
|
||||
throw error;
|
||||
function reportTSError(
|
||||
diagnostics: _ts.Diagnostic[],
|
||||
shouldExit: boolean | undefined
|
||||
) {
|
||||
if (!diagnostics || diagnostics.length === 0) {
|
||||
return;
|
||||
}
|
||||
const error = createTSError(diagnostics);
|
||||
// Print error in red color and continue execution.
|
||||
console.error('\x1b[31m%s\x1b[0m', error);
|
||||
if (shouldExit) {
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,7 +208,7 @@ export function init(opts: Options = {}): Compile {
|
||||
/**
|
||||
* Create the basic required function using transpile mode.
|
||||
*/
|
||||
let getOutput = function(code: string, fileName: string): [string, string] {
|
||||
let getOutput = function(code: string, fileName: string): SourceOutput {
|
||||
const result = ts.transpileModule(code, {
|
||||
fileName,
|
||||
transformers,
|
||||
@@ -216,16 +220,13 @@ export function init(opts: Options = {}): Compile {
|
||||
? filterDiagnostics(result.diagnostics, ignoreDiagnostics)
|
||||
: [];
|
||||
|
||||
if (diagnosticList.length) reportTSError(diagnosticList);
|
||||
reportTSError(diagnosticList, config.options.noEmitOnError);
|
||||
|
||||
return [result.outputText, result.sourceMapText as string];
|
||||
return { code: result.outputText, map: result.sourceMapText as string };
|
||||
};
|
||||
|
||||
// Use full language services when the fast option is disabled.
|
||||
let getOutputTypeCheck: (
|
||||
code: string,
|
||||
fileName: string
|
||||
) => [string, string];
|
||||
let getOutputTypeCheck: (code: string, fileName: string) => SourceOutput;
|
||||
{
|
||||
const memoryCache = new MemoryCache(config.fileNames);
|
||||
const cachedReadFile = cachedLookup(debugFn('readFile', readFile));
|
||||
@@ -302,7 +303,7 @@ export function init(opts: Options = {}): Compile {
|
||||
ignoreDiagnostics
|
||||
);
|
||||
|
||||
if (diagnosticList.length) reportTSError(diagnosticList);
|
||||
reportTSError(diagnosticList, config.options.noEmitOnError);
|
||||
|
||||
if (output.emitSkipped) {
|
||||
throw new TypeError(`${relative(cwd, fileName)}: Emit skipped`);
|
||||
@@ -319,7 +320,10 @@ export function init(opts: Options = {}): Compile {
|
||||
);
|
||||
}
|
||||
|
||||
return [output.outputFiles[1].text, output.outputFiles[0].text];
|
||||
return {
|
||||
code: output.outputFiles[1].text,
|
||||
map: output.outputFiles[0].text,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -340,7 +344,7 @@ export function init(opts: Options = {}): Compile {
|
||||
|
||||
// Read project configuration when available.
|
||||
configFileName = options.project
|
||||
? normalizeSlashes(resolve(cwd, options.project))
|
||||
? ts.findConfigFile(normalizeSlashes(options.project), fileExists)
|
||||
: ts.findConfigFile(normalizeSlashes(cwd), fileExists);
|
||||
|
||||
if (configFileName) return normalizeSlashes(configFileName);
|
||||
@@ -369,7 +373,7 @@ export function init(opts: Options = {}): Compile {
|
||||
ignoreDiagnostics
|
||||
);
|
||||
// Render the configuration errors.
|
||||
if (configDiagnosticList.length) reportTSError(configDiagnosticList);
|
||||
reportTSError(configDiagnosticList, true);
|
||||
return errorResult;
|
||||
}
|
||||
|
||||
@@ -407,17 +411,21 @@ export function init(opts: Options = {}): Compile {
|
||||
ignoreDiagnostics
|
||||
);
|
||||
// Render the configuration errors.
|
||||
if (configDiagnosticList.length) reportTSError(configDiagnosticList);
|
||||
reportTSError(configDiagnosticList, configResult.options.noEmitOnError);
|
||||
}
|
||||
|
||||
return configResult;
|
||||
}
|
||||
|
||||
// Create a simple TypeScript compiler proxy.
|
||||
function compile(code: string, fileName: string, skipTypeCheck?: boolean) {
|
||||
function compile(
|
||||
code: string,
|
||||
fileName: string,
|
||||
skipTypeCheck?: boolean
|
||||
): SourceOutput {
|
||||
const configFileName = detectConfig(fileName);
|
||||
const build = getBuild(configFileName);
|
||||
const [value, sourceMap] = (skipTypeCheck
|
||||
const { code: value, map: sourceMap } = (skipTypeCheck
|
||||
? build.getOutput
|
||||
: build.getOutputTypeCheck)(code, fileName);
|
||||
const output = {
|
||||
@@ -435,8 +443,8 @@ export function init(opts: Options = {}): Compile {
|
||||
}
|
||||
|
||||
interface Build {
|
||||
getOutput(code: string, fileName: string): [string, string];
|
||||
getOutputTypeCheck(code: string, fileName: string): [string, string];
|
||||
getOutput(code: string, fileName: string): SourceOutput;
|
||||
getOutputTypeCheck(code: string, fileName: string): SourceOutput;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -471,6 +479,11 @@ function fixConfig(ts: TSCommon, config: _ts.ParsedCommandLine) {
|
||||
return config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal source output.
|
||||
*/
|
||||
type SourceOutput = { code: string; map: string };
|
||||
|
||||
/**
|
||||
* Filter diagnostics.
|
||||
*/
|
||||
|
||||
5
packages/now-node/test/fixtures/18-nested-tsconfig/dep.ts
vendored
Normal file
5
packages/now-node/test/fixtures/18-nested-tsconfig/dep.ts
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
// This will compile differently when target is es5 vs es6
|
||||
|
||||
export function hello(name: string) {
|
||||
`Hello ${name}`;
|
||||
}
|
||||
10
packages/now-node/test/fixtures/18-nested-tsconfig/functions/es5.ts
vendored
Normal file
10
packages/now-node/test/fixtures/18-nested-tsconfig/functions/es5.ts
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
import { IncomingMessage, ServerResponse } from 'http';
|
||||
import { hello } from '../dep';
|
||||
|
||||
export default function(req: IncomingMessage, res: ServerResponse) {
|
||||
if (req) {
|
||||
res.end(hello.toString());
|
||||
} else {
|
||||
res.end('no req found');
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@
|
||||
"strictPropertyInitialization": true /* Enable strict checking of property initialization in classes. */,
|
||||
"noImplicitThis": true /* Raise error on 'this' expressions with an implied 'any' type. */,
|
||||
"alwaysStrict": true /* Parse in strict mode and emit "use strict" for each source file. */,
|
||||
|
||||
"noEmitOnError": true,
|
||||
"esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
|
||||
},
|
||||
"exclude": ["./screenshot-api/**"]
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { NowRequest, NowResponse } from '@now/node';
|
||||
import { hello } from './dep';
|
||||
|
||||
export default function(req: NowRequest, res: NowResponse) {
|
||||
if (req) {
|
||||
res.end('root:RANDOMNESS_PLACEHOLDER');
|
||||
res.end(hello.toString());
|
||||
} else {
|
||||
res.end('no req found');
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
{
|
||||
"version": 2,
|
||||
"builds": [
|
||||
{ "src": "functions/referer-redirect.ts", "use": "@now/node" },
|
||||
{ "src": "functions/double-redirect.ts", "use": "@now/node" },
|
||||
{ "src": "functions/trailing-redirect.ts", "use": "@now/node" },
|
||||
{ "src": "functions/*.ts", "use": "@now/node" },
|
||||
{ "src": "index.ts", "use": "@now/node" }
|
||||
],
|
||||
"routes": [
|
||||
@@ -26,7 +24,11 @@
|
||||
"probes": [
|
||||
{
|
||||
"path": "/",
|
||||
"mustContain": "root:RANDOMNESS_PLACEHOLDER"
|
||||
"mustContain": "`"
|
||||
},
|
||||
{
|
||||
"path": "/functions/es5.ts",
|
||||
"mustContain": "+"
|
||||
},
|
||||
{
|
||||
"path": "/pricing/",
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
"version": "1.0.0",
|
||||
"main": "index.js",
|
||||
"devDependencies": {
|
||||
"@now/node": "*",
|
||||
"typescript": "3.5.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"target": "esnext",
|
||||
"module": "esnext",
|
||||
"lib": ["dom", "es2017"],
|
||||
"noEmit": true,
|
||||
"noEmitOnError": true,
|
||||
"moduleResolution": "node",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"strict": true,
|
||||
|
||||
6
packages/now-node/test/fixtures/45-noEmitOnError-true/index.ts
vendored
Normal file
6
packages/now-node/test/fixtures/45-noEmitOnError-true/index.ts
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
import { IncomingMessage, ServerResponse } from 'http';
|
||||
export default function handler(req: IncomingMessage, res: ServerResponse) {
|
||||
if (req && !req.thisDoesNotExist) {
|
||||
res.end('no-emit-on-error-true:RANDOMNESS_PLACEHOLDER');
|
||||
}
|
||||
}
|
||||
10
packages/now-node/test/fixtures/45-noEmitOnError-true/now.json
vendored
Normal file
10
packages/now-node/test/fixtures/45-noEmitOnError-true/now.json
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"version": 2,
|
||||
"builds": [{ "src": "index.ts", "use": "@now/node" }],
|
||||
"probes": [
|
||||
{
|
||||
"path": "/",
|
||||
"mustContain": "no-emit-on-error-true:RANDOMNESS_PLACEHOLDER"
|
||||
}
|
||||
]
|
||||
}
|
||||
6
packages/now-node/test/fixtures/45-noEmitOnError-true/package.json
vendored
Normal file
6
packages/now-node/test/fixtures/45-noEmitOnError-true/package.json
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
}
|
||||
10
packages/now-node/test/fixtures/45-noEmitOnError-true/tsconfig.json
vendored
Normal file
10
packages/now-node/test/fixtures/45-noEmitOnError-true/tsconfig.json
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"sourceMap": true,
|
||||
"target": "esnext",
|
||||
"noUnusedLocals": true,
|
||||
"noEmitOnError": true
|
||||
}
|
||||
}
|
||||
6
packages/now-node/test/fixtures/46-noEmitOnError-false/index.ts
vendored
Normal file
6
packages/now-node/test/fixtures/46-noEmitOnError-false/index.ts
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
import { IncomingMessage, ServerResponse } from 'http';
|
||||
export default function handler(req: IncomingMessage, res: ServerResponse) {
|
||||
if (req && !req.thisDoesNotExist) {
|
||||
res.end('no-emit-on-error-false:RANDOMNESS_PLACEHOLDER');
|
||||
}
|
||||
}
|
||||
10
packages/now-node/test/fixtures/46-noEmitOnError-false/now.json
vendored
Normal file
10
packages/now-node/test/fixtures/46-noEmitOnError-false/now.json
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"version": 2,
|
||||
"builds": [{ "src": "index.ts", "use": "@now/node" }],
|
||||
"probes": [
|
||||
{
|
||||
"path": "/",
|
||||
"mustContain": "no-emit-on-error-false:RANDOMNESS_PLACEHOLDER"
|
||||
}
|
||||
]
|
||||
}
|
||||
6
packages/now-node/test/fixtures/46-noEmitOnError-false/package.json
vendored
Normal file
6
packages/now-node/test/fixtures/46-noEmitOnError-false/package.json
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
}
|
||||
10
packages/now-node/test/fixtures/46-noEmitOnError-false/tsconfig.json
vendored
Normal file
10
packages/now-node/test/fixtures/46-noEmitOnError-false/tsconfig.json
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"sourceMap": true,
|
||||
"target": "esnext",
|
||||
"noUnusedLocals": true,
|
||||
"noEmitOnError": false
|
||||
}
|
||||
}
|
||||
@@ -19,8 +19,25 @@ beforeAll(async () => {
|
||||
|
||||
const fixturesPath = path.resolve(__dirname, 'fixtures');
|
||||
|
||||
const testsThatFailToBuild = new Set(['45-noEmitOnError-true']);
|
||||
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
for (const fixture of fs.readdirSync(fixturesPath)) {
|
||||
if (testsThatFailToBuild.has(fixture)) {
|
||||
// eslint-disable-next-line no-loop-func
|
||||
it(`should not build ${fixture}`, async () => {
|
||||
try {
|
||||
await testDeployment(
|
||||
{ builderUrl, buildUtilsUrl },
|
||||
path.join(fixturesPath, fixture),
|
||||
);
|
||||
} catch (err) {
|
||||
expect(err.message).toMatch(/is ERROR/);
|
||||
}
|
||||
});
|
||||
continue; //eslint-disable-line
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-loop-func
|
||||
it(`should build ${fixture}`, async () => {
|
||||
await expect(
|
||||
|
||||
@@ -101,7 +101,7 @@ elif 'app' in __now_variables:
|
||||
}
|
||||
|
||||
for key, value in environ.items():
|
||||
if isinstance(value, string_types) and key != 'QUERY_STRING':
|
||||
if isinstance(value, string_types):
|
||||
environ[key] = wsgi_encoding_dance(value)
|
||||
|
||||
for key, value in headers.items():
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@now/python",
|
||||
"version": "0.2.14",
|
||||
"version": "0.2.16",
|
||||
"main": "./dist/index.js",
|
||||
"license": "MIT",
|
||||
"homepage": "https://zeit.co/docs/v2/deployments/official-builders/python-now-python",
|
||||
|
||||
@@ -46,34 +46,10 @@ async function pipInstall(pipPath: string, workDir: string, ...args: string[]) {
|
||||
}
|
||||
}
|
||||
|
||||
async function pipInstallUser(pipPath: string, ...args: string[]) {
|
||||
console.log(
|
||||
`running "pip install --disable-pip-version-check --user ${args.join(
|
||||
' '
|
||||
)}"...`
|
||||
);
|
||||
try {
|
||||
await execa(
|
||||
pipPath,
|
||||
['install', '--disable-pip-version-check', '--user', ...args],
|
||||
{
|
||||
stdio: 'inherit',
|
||||
}
|
||||
);
|
||||
} catch (err) {
|
||||
console.log(
|
||||
`failed to run "pip install --disable-pip-version-check --user ${args.join(
|
||||
' '
|
||||
)}"`
|
||||
);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async function pipenvInstall(pyUserBase: string, srcDir: string) {
|
||||
async function pipenvConvert(cmd: string, srcDir: string) {
|
||||
console.log('running pipfile2req');
|
||||
try {
|
||||
const out = await execa.stdout(join(pyUserBase, 'bin', 'pipfile2req'), [], {
|
||||
const out = await execa.stdout(cmd, [], {
|
||||
cwd: srcDir,
|
||||
});
|
||||
fs.writeFileSync(join(srcDir, 'requirements.txt'), out);
|
||||
@@ -108,8 +84,6 @@ export const build = async ({
|
||||
workPath = destNow;
|
||||
}
|
||||
|
||||
const pyUserBase = await getWriteableDirectory();
|
||||
process.env.PYTHONUSERBASE = pyUserBase;
|
||||
const pipPath = 'pip3';
|
||||
|
||||
try {
|
||||
@@ -144,9 +118,23 @@ export const build = async ({
|
||||
if (pipfileLockDir) {
|
||||
console.log('found "Pipfile.lock"');
|
||||
|
||||
// Install pipenv.
|
||||
await pipInstallUser(pipPath, 'pipfile-requirements', '--no-warn-script-location');
|
||||
await pipenvInstall(pyUserBase, pipfileLockDir);
|
||||
// Convert Pipenv.Lock to requirements.txt.
|
||||
// We use a different`workPath` here because we want `pipfile-requirements` and it's dependencies
|
||||
// to not be part of the lambda environment. By using pip's `--target` directive we can isolate
|
||||
// it into a separate folder.
|
||||
const tempDir = await getWriteableDirectory();
|
||||
await pipInstall(
|
||||
pipPath,
|
||||
tempDir,
|
||||
'pipfile-requirements',
|
||||
'--no-warn-script-location'
|
||||
);
|
||||
|
||||
// Python needs to know where to look up all the packages we just installed.
|
||||
// We tell it to use the same location as used with `--target`
|
||||
process.env.PYTHONPATH = tempDir;
|
||||
const convertCmd = join(tempDir, 'bin', 'pipfile2req');
|
||||
await pipenvConvert(convertCmd, pipfileLockDir);
|
||||
}
|
||||
|
||||
fsFiles = await glob('**', workPath);
|
||||
|
||||
8
packages/now-python/test/fixtures/13-wsgi-url-params-encoding/custom.py
vendored
Normal file
8
packages/now-python/test/fixtures/13-wsgi-url-params-encoding/custom.py
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
from flask import Flask, Response, request, __version__
|
||||
app = Flask(__name__)
|
||||
|
||||
@app.route('/', defaults={'path': ''})
|
||||
@app.route('/<path:path>')
|
||||
def catch_all(path):
|
||||
qs = request.args.to_dict()
|
||||
return Response("path: %s query: %s" %(path, qs), mimetype='text/html')
|
||||
8
packages/now-python/test/fixtures/13-wsgi-url-params-encoding/index.py
vendored
Normal file
8
packages/now-python/test/fixtures/13-wsgi-url-params-encoding/index.py
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
from flask import Flask, Response, request, __version__
|
||||
app = Flask(__name__)
|
||||
|
||||
@app.route('/', defaults={'path': ''})
|
||||
@app.route('/<path:path>')
|
||||
def catch_all(path):
|
||||
qs = request.args.to_dict()
|
||||
return Response("path: %s query: %s" %(path, qs), mimetype='text/html')
|
||||
15
packages/now-python/test/fixtures/13-wsgi-url-params-encoding/now.json
vendored
Normal file
15
packages/now-python/test/fixtures/13-wsgi-url-params-encoding/now.json
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"version": 2,
|
||||
"builds": [{ "src": "*.py", "use": "@now/python" }],
|
||||
"routes": [{ "src": "/%E6%82%A8%E5%A5%BD", "dest": "custom.py" }],
|
||||
"probes": [
|
||||
{
|
||||
"path": "/?%E6%82%A8%E5%A5%BD=/",
|
||||
"mustContain": "path: query: {'您好': '/'}"
|
||||
},
|
||||
{
|
||||
"path": "/%E6%82%A8%E5%A5%BD?hello=/",
|
||||
"mustContain": "path: 您好 query: {'hello': '/'}"
|
||||
}
|
||||
]
|
||||
}
|
||||
1
packages/now-python/test/fixtures/13-wsgi-url-params-encoding/requirements.txt
vendored
Normal file
1
packages/now-python/test/fixtures/13-wsgi-url-params-encoding/requirements.txt
vendored
Normal file
@@ -0,0 +1 @@
|
||||
Flask==1.0.2
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@now/routing-utils",
|
||||
"version": "1.2.1",
|
||||
"version": "1.2.2",
|
||||
"description": "ZEIT Now route validation utilities",
|
||||
"main": "./dist/index.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
|
||||
@@ -70,14 +70,6 @@ export function normalizeRoutes(
|
||||
handling.push(route.handle);
|
||||
}
|
||||
} else if (route.src) {
|
||||
// typeof normal route
|
||||
if (route.continue && route.dest) {
|
||||
errors.push({
|
||||
message: `Cannot use both continue and dest`,
|
||||
src: route.src,
|
||||
});
|
||||
}
|
||||
|
||||
// Route src should always start with a '^'
|
||||
if (!route.src.startsWith('^')) {
|
||||
route.src = `^${route.src}`;
|
||||
|
||||
@@ -115,12 +115,6 @@ describe('normalizeRoutes', () => {
|
||||
handle: 'filesystem',
|
||||
});
|
||||
|
||||
routes.push({ src: '^/about$', dest: '/about', continue: true });
|
||||
errors.push({
|
||||
message: 'Cannot use both continue and dest',
|
||||
src: '^/about$',
|
||||
});
|
||||
|
||||
routes.push({ src: '^/(broken]$' });
|
||||
errors.push({
|
||||
message: 'Invalid regular expression: "^/(broken]$"',
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@now/static-build",
|
||||
"version": "0.9.5",
|
||||
"version": "0.9.8",
|
||||
"license": "MIT",
|
||||
"main": "./dist/index",
|
||||
"homepage": "https://zeit.co/docs/v2/deployments/official-builders/static-build-now-static-build",
|
||||
|
||||
@@ -65,26 +65,21 @@ export default [
|
||||
dependency: '@vue/cli-service',
|
||||
getOutputDirName: async () => 'dist',
|
||||
defaultRoutes: [
|
||||
{
|
||||
src: '^/[^/]*\\.(js|txt|ico|json)',
|
||||
headers: { 'cache-control': 'max-age=300' },
|
||||
continue: true,
|
||||
},
|
||||
{
|
||||
src: '^/(img|js|css|fonts|media)/.*',
|
||||
headers: { 'cache-control': 'max-age=31536000, immutable' },
|
||||
continue: true,
|
||||
},
|
||||
{
|
||||
handle: 'filesystem',
|
||||
},
|
||||
{
|
||||
src: '^/js/(.*)',
|
||||
headers: { 'cache-control': 'max-age=31536000, immutable' },
|
||||
dest: '/js/$1',
|
||||
},
|
||||
{
|
||||
src: '^/css/(.*)',
|
||||
headers: { 'cache-control': 'max-age=31536000, immutable' },
|
||||
dest: '/css/$1',
|
||||
},
|
||||
{
|
||||
src: '^/img/(.*)',
|
||||
headers: { 'cache-control': 'max-age=31536000, immutable' },
|
||||
dest: '/img/$1',
|
||||
},
|
||||
{
|
||||
src: '/(.*)',
|
||||
src: '^.*',
|
||||
dest: '/index.html',
|
||||
},
|
||||
],
|
||||
@@ -158,33 +153,20 @@ export default [
|
||||
{
|
||||
src: '/static/(.*)',
|
||||
headers: { 'cache-control': 's-maxage=31536000, immutable' },
|
||||
dest: '/static/$1',
|
||||
},
|
||||
{
|
||||
src: '/favicon.ico',
|
||||
dest: '/favicon.ico',
|
||||
},
|
||||
{
|
||||
src: '/asset-manifest.json',
|
||||
dest: '/asset-manifest.json',
|
||||
},
|
||||
{
|
||||
src: '/manifest.json',
|
||||
dest: '/manifest.json',
|
||||
},
|
||||
{
|
||||
src: '/precache-manifest.(.*)',
|
||||
dest: '/precache-manifest.$1',
|
||||
continue: true,
|
||||
},
|
||||
{
|
||||
src: '/service-worker.js',
|
||||
headers: { 'cache-control': 's-maxage=0' },
|
||||
dest: '/service-worker.js',
|
||||
continue: true,
|
||||
},
|
||||
{
|
||||
src: '/sockjs-node/(.*)',
|
||||
dest: '/sockjs-node/$1',
|
||||
},
|
||||
{
|
||||
handle: 'filesystem',
|
||||
},
|
||||
{
|
||||
src: '/(.*)',
|
||||
headers: { 'cache-control': 's-maxage=0' },
|
||||
@@ -232,4 +214,23 @@ export default [
|
||||
dependency: 'sapper',
|
||||
getOutputDirName: async () => '__sapper__/export',
|
||||
},
|
||||
{
|
||||
name: 'Saber',
|
||||
dependency: 'saber',
|
||||
getOutputDirName: async () => 'public',
|
||||
defaultRoutes: [
|
||||
{
|
||||
src: '/_saber/.*',
|
||||
headers: { 'cache-control': 'max-age=31536000, immutable' },
|
||||
},
|
||||
{
|
||||
handle: 'filesystem',
|
||||
},
|
||||
{
|
||||
src: '.*',
|
||||
status: 404,
|
||||
dest: '404.html',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
@@ -333,8 +333,14 @@ export async function build({
|
||||
const spawnOpts = getSpawnOptions(meta, nodeVersion);
|
||||
await runShellScript(path.join(workPath, entrypoint), [], spawnOpts);
|
||||
validateDistDir(distPath, meta.isDev, config);
|
||||
|
||||
const output = await glob('**', distPath, mountpoint);
|
||||
|
||||
return glob('**', distPath, mountpoint);
|
||||
return {
|
||||
output,
|
||||
routes: [],
|
||||
watch: []
|
||||
};
|
||||
}
|
||||
|
||||
let message = `Build "src" is "${entrypoint}" but expected "package.json"`;
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
{
|
||||
"version": 2,
|
||||
"builds": [
|
||||
{ "src": "package.json", "use": "@now/static-build", "config": { "zeroConfig": true } }
|
||||
{
|
||||
"src": "package.json",
|
||||
"use": "@now/static-build",
|
||||
"config": { "zeroConfig": true }
|
||||
}
|
||||
],
|
||||
"probes": [
|
||||
{ "path": "/", "mustContain": "React App" }
|
||||
{ "path": "/", "mustContain": "React App" },
|
||||
{ "path": "/testing-output-dir.txt", "mustContain": "This is some content" }
|
||||
]
|
||||
}
|
||||
|
||||
1
packages/now-static-build/test/fixtures/12-create-react-app/public/testing-output-dir.txt
vendored
Normal file
1
packages/now-static-build/test/fixtures/12-create-react-app/public/testing-output-dir.txt
vendored
Normal file
@@ -0,0 +1 @@
|
||||
This is some content
|
||||
@@ -1,10 +1,50 @@
|
||||
{
|
||||
"version": 2,
|
||||
"builds": [
|
||||
{ "src": "package.json", "use": "@now/static-build", "config": { "zeroConfig": true } }
|
||||
{
|
||||
"src": "package.json",
|
||||
"use": "@now/static-build",
|
||||
"config": {
|
||||
"zeroConfig": true
|
||||
}
|
||||
}
|
||||
],
|
||||
"probes": [
|
||||
{ "path": "/", "mustContain": "13-vue" },
|
||||
{ "path": "/923h3223329ddas", "mustContain": "13-vue" }
|
||||
{
|
||||
"path": "/",
|
||||
"mustContain": "13-vue"
|
||||
},
|
||||
{
|
||||
"path": "/js/app.js",
|
||||
"headers": {
|
||||
"cache-control": "max-age=31536000, immutable"
|
||||
},
|
||||
"mustContain": "function"
|
||||
},
|
||||
{
|
||||
"path": "/css/app.css",
|
||||
"headers": {
|
||||
"cache-control": "max-age=31536000, immutable"
|
||||
},
|
||||
"mustContain": "font-family"
|
||||
},
|
||||
{
|
||||
"path": "/robots.txt",
|
||||
"headers": {
|
||||
"cache-control": "max-age=300"
|
||||
},
|
||||
"mustContain": "Disallow"
|
||||
},
|
||||
{
|
||||
"path": "/manifest.json",
|
||||
"headers": {
|
||||
"cache-control": "max-age=300"
|
||||
},
|
||||
"mustContain": "13-vue-manifest"
|
||||
},
|
||||
{
|
||||
"path": "/923h3223329ddas",
|
||||
"mustContain": "13-vue"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
20
packages/now-static-build/test/fixtures/13-vue/public/manifest.json
vendored
Normal file
20
packages/now-static-build/test/fixtures/13-vue/public/manifest.json
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "13-vue-manifest",
|
||||
"short_name": "13-vue-manifest",
|
||||
"icons": [
|
||||
{
|
||||
"src": "./img/icons/android-chrome-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "./img/icons/android-chrome-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"start_url": "./index.html",
|
||||
"display": "standalone",
|
||||
"background_color": "#000000",
|
||||
"theme_color": "#4DBA87"
|
||||
}
|
||||
2
packages/now-static-build/test/fixtures/13-vue/public/robots.txt
vendored
Normal file
2
packages/now-static-build/test/fixtures/13-vue/public/robots.txt
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
User-agent: *
|
||||
Disallow:
|
||||
5
packages/now-static-build/test/fixtures/13-vue/vue.config.js
vendored
Normal file
5
packages/now-static-build/test/fixtures/13-vue/vue.config.js
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
module.exports = {
|
||||
// This is necessary for our test probes
|
||||
// so that the generated file names are deterministic.
|
||||
filenameHashing: false,
|
||||
};
|
||||
4
packages/now-static-build/test/fixtures/25-saber/.gitignore
vendored
Normal file
4
packages/now-static-build/test/fixtures/25-saber/.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
node_modules
|
||||
*.log
|
||||
.saber
|
||||
public
|
||||
11
packages/now-static-build/test/fixtures/25-saber/README.md
vendored
Normal file
11
packages/now-static-build/test/fixtures/25-saber/README.md
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
# my-saber-blog
|
||||
|
||||
## Scripts
|
||||
|
||||
### `npm run dev`
|
||||
|
||||
Run dev server at `http://localhost:3000`
|
||||
|
||||
### `npm run build`
|
||||
|
||||
Build your website to `public` folder which you can deploy to ZEIT Now, GitHub Pages, Netlify or wherever you want.
|
||||
25
packages/now-static-build/test/fixtures/25-saber/now.json
vendored
Normal file
25
packages/now-static-build/test/fixtures/25-saber/now.json
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"version": 2,
|
||||
"builds": [
|
||||
{
|
||||
"src": "package.json",
|
||||
"use": "@now/static-build",
|
||||
"config": { "zeroConfig": true }
|
||||
}
|
||||
],
|
||||
"probes": [
|
||||
{
|
||||
"path": "/",
|
||||
"mustContain": "Your Awesome Title"
|
||||
},
|
||||
{
|
||||
"path": "/_saber/js/client.js",
|
||||
"headers": { "cache-control": "max-age=31536000, immutable" },
|
||||
"mustContain": "function"
|
||||
},
|
||||
{
|
||||
"path": "/not-exist",
|
||||
"mustContain": "Back Home"
|
||||
}
|
||||
]
|
||||
}
|
||||
13
packages/now-static-build/test/fixtures/25-saber/package.json
vendored
Normal file
13
packages/now-static-build/test/fixtures/25-saber/package.json
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "saber",
|
||||
"build": "saber build"
|
||||
},
|
||||
"devDependencies": {
|
||||
"saber": "latest",
|
||||
"saber-theme-minima": "latest",
|
||||
"saber-plugin-feed": "latest",
|
||||
"saber-plugin-query-posts": "latest"
|
||||
}
|
||||
}
|
||||
9
packages/now-static-build/test/fixtures/25-saber/pages/_posts/my-example-post.md
vendored
Normal file
9
packages/now-static-build/test/fixtures/25-saber/pages/_posts/my-example-post.md
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
---
|
||||
title: My Example Post
|
||||
date: 2016-05-20
|
||||
layout: post
|
||||
---
|
||||
|
||||
Eos eu docendi tractatos sapientem, brute option menandri in vix, quando vivendo accommodare te ius. Nec melius fastidii constituam id, viderer theophrastus ad sit, hinc semper periculis cum id. Noluisse postulant assentior est in, no choro sadipscing repudiandae vix. Vis in euismod delenit dignissim. Ex quod nostrum sit, suas decore animal id ius, nobis solet detracto quo te.
|
||||
|
||||
No laudem altera adolescens has, volumus lucilius eum no. Eam ei nulla audiam efficiantur. Suas affert per no, ei tale nibh sea. Sea ne magna harum, in denique scriptorem sea, cetero alienum tibique ei eos. Labores persequeris referrentur eos ei.
|
||||
11
packages/now-static-build/test/fixtures/25-saber/pages/_posts/super-long-article.md
vendored
Normal file
11
packages/now-static-build/test/fixtures/25-saber/pages/_posts/super-long-article.md
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
---
|
||||
title: Some articles are just so long they deserve a really long title to see if things will break well
|
||||
layout: post
|
||||
date: 2016-05-18
|
||||
---
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce bibendum neque eget nunc mattis eu sollicitudin enim tincidunt. Vestibulum lacus tortor, ultricies id dignissim ac, bibendum in velit. Proin convallis mi ac felis pharetra aliquam. Curabitur dignissim accumsan rutrum. In arcu magna, aliquet vel pretium et, molestie et arcu. Mauris lobortis nulla et felis ullamcorper bibendum. Phasellus et hendrerit mauris. Proin eget nibh a massa vestibulum pretium. Suspendisse eu nisl a ante aliquet bibendum quis a nunc. Praesent varius interdum vehicula. Aenean risus libero, placerat at vestibulum eget, ultricies eu enim. Praesent nulla tortor, malesuada adipiscing adipiscing sollicitudin, adipiscing eget est.
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce bibendum neque eget nunc mattis eu sollicitudin enim tincidunt. Vestibulum lacus tortor, ultricies id dignissim ac, bibendum in velit. Proin convallis mi ac felis pharetra aliquam. Curabitur dignissim accumsan rutrum. In arcu magna, aliquet vel pretium et, molestie et arcu. Mauris lobortis nulla et felis ullamcorper bibendum. Phasellus et hendrerit mauris. Proin eget nibh a massa vestibulum pretium. Suspendisse eu nisl a ante aliquet bibendum quis a nunc. Praesent varius interdum vehicula. Aenean risus libero, placerat at vestibulum eget, ultricies eu enim. Praesent nulla tortor, malesuada adipiscing adipiscing sollicitudin, adipiscing eget est.
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce bibendum neque eget nunc mattis eu sollicitudin enim tincidunt. Vestibulum lacus tortor, ultricies id dignissim ac, bibendum in velit. Proin convallis mi ac felis pharetra aliquam. Curabitur dignissim accumsan rutrum. In arcu magna, aliquet vel pretium et, molestie et arcu. Mauris lobortis nulla et felis ullamcorper bibendum. Phasellus et hendrerit mauris. Proin eget nibh a massa vestibulum pretium. Suspendisse eu nisl a ante aliquet bibendum quis a nunc. Praesent varius interdum vehicula. Aenean risus libero, placerat at vestibulum eget, ultricies eu enim. Praesent nulla tortor, malesuada adipiscing adipiscing sollicitudin, adipiscing eget est.
|
||||
7
packages/now-static-build/test/fixtures/25-saber/pages/_posts/super-short-article.md
vendored
Normal file
7
packages/now-static-build/test/fixtures/25-saber/pages/_posts/super-short-article.md
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
title: 'Some articles are just so short that we have to make the footer stick'
|
||||
date: 2016-05-19
|
||||
layout: post
|
||||
---
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
|
||||
8
packages/now-static-build/test/fixtures/25-saber/pages/about.md
vendored
Normal file
8
packages/now-static-build/test/fixtures/25-saber/pages/about.md
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
---
|
||||
title: About
|
||||
layout: page
|
||||
---
|
||||
|
||||
This is the Saber port of the base Jekyll theme. Check out the [GitHub project](https://github.com/egoist/saber-theme-minima) for detailed usages.
|
||||
|
||||
You can find out more info about customizing your theme, as well as basic Saber usage documentation at https://saber.land
|
||||
6
packages/now-static-build/test/fixtures/25-saber/pages/index.md
vendored
Normal file
6
packages/now-static-build/test/fixtures/25-saber/pages/index.md
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
# Fallback to `default` layout if `index` is not found
|
||||
layout: index
|
||||
# Inject post list as `page.posts` (by saber-plugin-query-posts)
|
||||
injectAllPosts: true
|
||||
---
|
||||
24
packages/now-static-build/test/fixtures/25-saber/saber-config.yml
vendored
Normal file
24
packages/now-static-build/test/fixtures/25-saber/saber-config.yml
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
theme: minima
|
||||
|
||||
siteConfig:
|
||||
url: https://example.com
|
||||
author: Author of This Site
|
||||
email: author@your-domain.com
|
||||
description: Write an awesome description for your new site here. You can edit this line in saber-config.yml. It will appear in your document head meta (for Google search results) site description.
|
||||
|
||||
themeConfig:
|
||||
nav:
|
||||
- text: Home
|
||||
link: /
|
||||
- text: About
|
||||
link: /about.html
|
||||
social:
|
||||
twitter: saber_land
|
||||
github: egoist
|
||||
rss: true
|
||||
|
||||
plugins:
|
||||
- resolve: saber-plugin-query-posts
|
||||
- resolve: saber-plugin-feed
|
||||
options:
|
||||
atomFeed: true
|
||||
3
packages/now-static-build/test/fixtures/25-saber/saber-node.js
vendored
Normal file
3
packages/now-static-build/test/fixtures/25-saber/saber-node.js
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
exports.getWebpackConfig = config => {
|
||||
config.output.filename = 'js/[name].js';
|
||||
};
|
||||
@@ -90,6 +90,16 @@ async function testDeployment (
|
||||
const { text, resp } = await fetchDeploymentUrl(probeUrl, fetchOpts);
|
||||
console.log('finished testing', JSON.stringify(probe));
|
||||
|
||||
if (probe.status) {
|
||||
if (probe.status !== resp.status) {
|
||||
throw new Error(
|
||||
`Fetched page ${probeUrl} does not return the status ${
|
||||
probe.status
|
||||
} Instead it has ${resp.status}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (probe.mustContain) {
|
||||
if (!text.includes(probe.mustContain)) {
|
||||
await fs.writeFile(path.join(__dirname, 'failed-page.txt'), text);
|
||||
@@ -117,7 +127,7 @@ async function testDeployment (
|
||||
);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
} else if (!probe.status) {
|
||||
assert(false, 'probe must have a test condition');
|
||||
}
|
||||
}
|
||||
@@ -140,14 +150,10 @@ async function nowDeployIndexTgz (file) {
|
||||
}
|
||||
|
||||
async function fetchDeploymentUrl (url, opts) {
|
||||
for (let i = 0; i < 500; i += 1) {
|
||||
for (let i = 0; i < 50; i += 1) {
|
||||
const resp = await fetch(url, opts);
|
||||
const text = await resp.text();
|
||||
if (
|
||||
text
|
||||
&& !text.includes('Join Free')
|
||||
&& !text.includes('The page could not be found')
|
||||
) {
|
||||
if (text && !text.includes('Join Free')) {
|
||||
return { resp, text };
|
||||
}
|
||||
|
||||
|
||||
@@ -1480,10 +1480,10 @@
|
||||
resolved "https://registry.yarnpkg.com/@zeit/ncc/-/ncc-0.20.4.tgz#00f0a25a88cac3712af4ba66561d9e281c6f05c9"
|
||||
integrity sha512-fmq+F/QxPec+k/zvT7HiVpk7oiGFseS6brfT/AYqmCUp6QFRK7vZf2Ref46MImsg/g2W3g5X6SRvGRmOAvEfdA==
|
||||
|
||||
"@zeit/node-file-trace@0.2.6":
|
||||
version "0.2.6"
|
||||
resolved "https://registry.yarnpkg.com/@zeit/node-file-trace/-/node-file-trace-0.2.6.tgz#0884bf7a7176f6aa865a40c8c8b95513d59ee463"
|
||||
integrity sha512-b6OPed+EtVPMNdSdumBPIBFq0h6CgvVj7sa4Lmbq/KJu9KnOJ19Vu4YrJvSWRjgzP4SJqlQ4ya/HUXRP/LWVog==
|
||||
"@zeit/node-file-trace@0.2.13":
|
||||
version "0.2.13"
|
||||
resolved "https://registry.yarnpkg.com/@zeit/node-file-trace/-/node-file-trace-0.2.13.tgz#44b21a2c6bedc381f696ea03046c27cdd793cc9b"
|
||||
integrity sha512-DxpZ1G1w88NnFwNcfUJlhkGsFCcx5kXksFEmhlBiI+k53km5vhRo6uO+ExI09YIcr29gOKglm1gusNiFEJaN8A==
|
||||
dependencies:
|
||||
acorn "^6.1.1"
|
||||
acorn-stage3 "^2.0.0"
|
||||
|
||||
Reference in New Issue
Block a user