[now-next] Disable running next export from export-intent (#3448)

As requested by @timneutkens after investigating we're disabling auto running `next export` for the user during a build since most users who want their app exported will define `next export` in their `build` script
This commit is contained in:
JJ Kasper
2019-12-17 21:01:33 -06:00
committed by kodiakhq[bot]
parent 906dea096e
commit 49b375ed6a
13 changed files with 82 additions and 40 deletions

View File

@@ -354,30 +354,12 @@ export const build = async ({
} }
} }
const exportIntent = await getExportIntent(entryPath);
const userExport = await getExportStatus(entryPath); const userExport = await getExportStatus(entryPath);
if (exportIntent || userExport) { if (userExport) {
const exportIntent = await getExportIntent(entryPath);
const { trailingSlash = false } = exportIntent || {}; const { trailingSlash = false } = exportIntent || {};
if (!userExport) {
await writePackageJson(entryPath, {
...pkg,
scripts: {
...pkg.scripts,
'now-automatic-next-export': `next export --outdir "${path.resolve(
entryPath,
'out'
)}"`,
},
});
await runPackageJsonScript(entryPath, 'now-automatic-next-export', {
...spawnOpts,
env,
});
}
const resultingExport = await getExportStatus(entryPath); const resultingExport = await getExportStatus(entryPath);
if (!resultingExport) { if (!resultingExport) {
throw new Error( throw new Error(

View File

@@ -12,7 +12,7 @@
}, },
{ {
"path": "/", "path": "/",
"mustContain": "nextExport\":true" "mustNotContain": "nextExport\":true"
} }
] ]
} }

View File

@@ -1,4 +1,7 @@
{ {
"scripts": {
"build": "next build && next export"
},
"dependencies": { "dependencies": {
"next": "canary", "next": "canary",
"react": "^16.8.6", "react": "^16.8.6",

View File

@@ -0,0 +1,8 @@
const withOffline = require('next-offline');
module.exports = withOffline({
generateBuildId() {
return 'testing-build-id';
},
exportPathMap: d => d,
});

View File

@@ -0,0 +1,18 @@
{
"version": 2,
"builds": [{ "src": "package.json", "use": "@now/next" }],
"probes": [
{
"path": "/",
"mustContain": "Hi There"
},
{
"path": "/about",
"mustContain": "Hi on About"
},
{
"path": "/",
"mustNotContain": "nextExport\":true"
}
]
}

View File

@@ -0,0 +1,8 @@
{
"dependencies": {
"next": "canary",
"next-offline": "4.0.6",
"react": "^16.8.6",
"react-dom": "^16.8.6"
}
}

View File

@@ -0,0 +1,7 @@
function About() {
return <div>Hi on About</div>;
}
About.getInitialProps = () => ({});
export default About;

View File

@@ -0,0 +1,7 @@
function Home() {
return <div>Hi There</div>;
}
Home.getInitialProps = () => ({});
export default Home;

View File

@@ -7,8 +7,8 @@ const { spawn } = require('child_process');
const fetch = require('./fetch-retry.js'); const fetch = require('./fetch-retry.js');
const { nowDeploy } = require('./now-deploy.js'); const { nowDeploy } = require('./now-deploy.js');
async function packAndDeploy (builderPath) { async function packAndDeploy(builderPath) {
await spawnAsync('npm', [ '--loglevel', 'warn', 'pack' ], { await spawnAsync('npm', ['--loglevel', 'warn', 'pack'], {
stdio: 'inherit', stdio: 'inherit',
cwd: builderPath, cwd: builderPath,
}); });
@@ -23,7 +23,7 @@ async function packAndDeploy (builderPath) {
const RANDOMNESS_PLACEHOLDER_STRING = 'RANDOMNESS_PLACEHOLDER'; const RANDOMNESS_PLACEHOLDER_STRING = 'RANDOMNESS_PLACEHOLDER';
async function testDeployment ( async function testDeployment(
{ builderUrl, buildUtilsUrl }, { builderUrl, buildUtilsUrl },
fixturePath, fixturePath,
buildDelegate buildDelegate
@@ -85,7 +85,7 @@ async function testDeployment (
for (const probe of nowJson.probes || []) { for (const probe of nowJson.probes || []) {
console.log('testing', JSON.stringify(probe)); console.log('testing', JSON.stringify(probe));
if (probe.delay) { if (probe.delay) {
await new Promise((resolve) => setTimeout(resolve, probe.delay)); await new Promise(resolve => setTimeout(resolve, probe.delay));
continue; continue;
} }
const probeUrl = `https://${deploymentUrl}${probe.path}`; const probeUrl = `https://${deploymentUrl}${probe.path}`;
@@ -109,31 +109,40 @@ async function testDeployment (
} }
} }
if (probe.mustContain) { if (probe.mustContain || probe.mustNotContain) {
if (!text.includes(probe.mustContain)) { const shouldContain = !!probe.mustContain;
const containsIt = text.includes(probe.mustContain);
if (
(!containsIt && probe.mustContain) ||
(containsIt && probe.mustNotContain)
) {
fs.writeFileSync(path.join(__dirname, 'failed-page.txt'), text); fs.writeFileSync(path.join(__dirname, 'failed-page.txt'), text);
const headers = Array.from(resp.headers.entries()) const headers = Array.from(resp.headers.entries())
.map(([ k, v ]) => ` ${k}=${v}`) .map(([k, v]) => ` ${k}=${v}`)
.join('\n'); .join('\n');
throw new Error( throw new Error(
`Fetched page ${probeUrl} does not contain ${probe.mustContain}.` + `Fetched page ${probeUrl} does${
` Instead it contains ${text.slice(0, 60)}` + shouldContain ? ' not' : ''
} contain ${
shouldContain ? probe.mustContain : probe.mustNotContain
}.` +
(shouldContain ? ` Instead it contains ${text.slice(0, 60)}` : '') +
` Response headers:\n ${headers}` ` Response headers:\n ${headers}`
); );
} }
} else if (probe.responseHeaders) { } else if (probe.responseHeaders) {
// eslint-disable-next-line no-loop-func // eslint-disable-next-line no-loop-func
Object.keys(probe.responseHeaders).forEach((header) => { Object.keys(probe.responseHeaders).forEach(header => {
const actual = resp.headers.get(header); const actual = resp.headers.get(header);
const expected = probe.responseHeaders[header]; const expected = probe.responseHeaders[header];
const isEqual = Array.isArray(expected) const isEqual = Array.isArray(expected)
? expected.every((h) => actual.includes(h)) ? expected.every(h => actual.includes(h))
: expected.startsWith('/') && expected.endsWith('/') : expected.startsWith('/') && expected.endsWith('/')
? new RegExp(expected.slice(1, -1)).test(actual) ? new RegExp(expected.slice(1, -1)).test(actual)
: expected === actual; : expected === actual;
if (!isEqual) { if (!isEqual) {
const headers = Array.from(resp.headers.entries()) const headers = Array.from(resp.headers.entries())
.map(([ k, v ]) => ` ${k}=${v}`) .map(([k, v]) => ` ${k}=${v}`)
.join('\n'); .join('\n');
throw new Error( throw new Error(
@@ -154,7 +163,7 @@ async function testDeployment (
return { deploymentId, deploymentUrl }; return { deploymentId, deploymentUrl };
} }
async function nowDeployIndexTgz (file) { async function nowDeployIndexTgz(file) {
const bodies = { const bodies = {
'index.tgz': fs.readFileSync(file), 'index.tgz': fs.readFileSync(file),
'now.json': Buffer.from(JSON.stringify({ version: 2 })), 'now.json': Buffer.from(JSON.stringify({ version: 2 })),
@@ -163,7 +172,7 @@ async function nowDeployIndexTgz (file) {
return (await nowDeploy(bodies)).deploymentUrl; return (await nowDeploy(bodies)).deploymentUrl;
} }
async function fetchDeploymentUrl (url, opts) { async function fetchDeploymentUrl(url, opts) {
for (let i = 0; i < 50; i += 1) { for (let i = 0; i < 50; i += 1) {
const resp = await fetch(url, opts); const resp = await fetch(url, opts);
const text = await resp.text(); const text = await resp.text();
@@ -171,13 +180,13 @@ async function fetchDeploymentUrl (url, opts) {
return { resp, text }; return { resp, text };
} }
await new Promise((r) => setTimeout(r, 1000)); await new Promise(r => setTimeout(r, 1000));
} }
throw new Error(`Failed to wait for deployment READY. Url is ${url}`); throw new Error(`Failed to wait for deployment READY. Url is ${url}`);
} }
async function fetchTgzUrl (url) { async function fetchTgzUrl(url) {
for (let i = 0; i < 500; i += 1) { for (let i = 0; i < 500; i += 1) {
const resp = await fetch(url); const resp = await fetch(url);
if (resp.status === 200) { if (resp.status === 200) {
@@ -188,19 +197,19 @@ async function fetchTgzUrl (url) {
} }
} }
await new Promise((r) => setTimeout(r, 1000)); await new Promise(r => setTimeout(r, 1000));
} }
throw new Error(`Failed to wait for builder url READY. Url is ${url}`); throw new Error(`Failed to wait for builder url READY. Url is ${url}`);
} }
async function spawnAsync (...args) { async function spawnAsync(...args) {
return await new Promise((resolve, reject) => { return await new Promise((resolve, reject) => {
const child = spawn(...args); const child = spawn(...args);
let result; let result;
if (child.stdout) { if (child.stdout) {
result = ''; result = '';
child.stdout.on('data', (chunk) => { child.stdout.on('data', chunk => {
result += chunk.toString(); result += chunk.toString();
}); });
} }