Skip to content
This repository was archived by the owner on May 10, 2021. It is now read-only.

Commit c468b53

Browse files
committed
track NoN files when configured dirs are used and clean before running NoN
1 parent ae79eb0 commit c468b53

File tree

4 files changed

+249
-6
lines changed

4 files changed

+249
-6
lines changed

index.js

+7-1
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,15 @@ const {
1414
* publishDir: string to path
1515
* }
1616
*/
17+
1718
const nextOnNetlify = (options = {}) => {
1819
const functionsPath = options.functionsDir || NETLIFY_FUNCTIONS_PATH;
1920
const publishPath = options.publishDir || NETLIFY_PUBLISH_PATH;
2021

21-
prepareFolders({ functionsPath, publishPath });
22+
const trackNextOnNetlifyFiles = prepareFolders({
23+
functionsPath,
24+
publishPath,
25+
});
2226

2327
copyPublicFiles(publishPath);
2428

@@ -27,6 +31,8 @@ const nextOnNetlify = (options = {}) => {
2731
setupPages({ functionsPath, publishPath });
2832

2933
setupRedirects(publishPath);
34+
35+
trackNextOnNetlifyFiles();
3036
};
3137

3238
module.exports = nextOnNetlify;

lib/steps/prepareFolders.js

+67-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,19 @@
1-
const { emptyDirSync } = require("fs-extra");
1+
const { join } = require("path");
2+
const {
3+
emptyDirSync,
4+
existsSync,
5+
readdirSync,
6+
readFileSync,
7+
writeFileSync,
8+
removeSync,
9+
} = require("fs-extra");
10+
const findCacheDir = require("find-cache-dir");
211
const { logTitle, log } = require("../helpers/logger");
312
const { NETLIFY_PUBLISH_PATH, NETLIFY_FUNCTIONS_PATH } = require("../config");
413

5-
// Empty existing publish and functions folders
14+
const TRACKING_FILE_SEPARATOR = "---";
15+
16+
// Clean existing publish and functions folders
617
const prepareFolders = ({ functionsPath, publishPath }) => {
718
logTitle("🚀 Next on Netlify 🚀");
819

@@ -19,8 +30,60 @@ const prepareFolders = ({ functionsPath, publishPath }) => {
1930
log(" ", "Make sure these are set in your netlify.toml file.");
2031
}
2132

22-
if (publishPath === NETLIFY_PUBLISH_PATH) emptyDirSync(publishPath);
23-
if (functionsPath === NETLIFY_FUNCTIONS_PATH) emptyDirSync(functionsPath);
33+
const cacheDir = findCacheDir({ name: "next-on-netlify", create: true });
34+
const trackingFilePath = join(cacheDir, ".nonfiletracking");
35+
const trackingFile = existsSync(trackingFilePath)
36+
? readFileSync(trackingFilePath, "utf8")
37+
: "---";
38+
39+
const [trackedFunctions, trackedPublish] = trackingFile.split("---");
40+
const functionsBeforeRun = existsSync(functionsPath)
41+
? readdirSync(functionsPath)
42+
: [];
43+
const publishBeforeRun = existsSync(publishPath)
44+
? readdirSync(publishPath)
45+
: [];
46+
47+
const isConfiguredPublishDir = publishPath !== NETLIFY_PUBLISH_PATH;
48+
const isConfiguredFunctionsDir = functionsPath !== NETLIFY_FUNCTIONS_PATH;
49+
50+
if (isConfiguredPublishDir) {
51+
trackedPublish.split("\n").forEach((file) => {
52+
const filePath = join(publishPath, file);
53+
if (existsSync(filePath)) {
54+
removeSync(filePath);
55+
}
56+
});
57+
} else {
58+
emptyDirSync(publishPath);
59+
}
60+
if (isConfiguredFunctionsDir) {
61+
trackedFunctions.split("\n").forEach((file) => {
62+
const filePath = join(functionsPath, file);
63+
if (existsSync(filePath)) {
64+
removeSync(filePath);
65+
}
66+
});
67+
} else {
68+
emptyDirSync(functionsPath);
69+
}
70+
71+
// this callback will run at the end of nextOnNetlify()
72+
return () => {
73+
const functionsAfterRun = isConfiguredFunctionsDir
74+
? readdirSync(functionsPath)
75+
: functionsBeforeRun;
76+
const publishAfterRun = isConfiguredPublishDir
77+
? readdirSync(publishPath)
78+
: publishBeforeRun;
79+
const getDiff = (before, after) =>
80+
after.filter((filePath) => !before.includes(filePath));
81+
const functionsDiff = getDiff(functionsBeforeRun, functionsAfterRun);
82+
const publishDiff = getDiff(publishBeforeRun, publishAfterRun);
83+
84+
const totalFilesDiff = [...functionsDiff, "---", ...publishDiff];
85+
writeFileSync(trackingFilePath, totalFilesDiff.join("\n"));
86+
};
2487
};
2588

2689
module.exports = prepareFolders;

tests/configurableDirs.test.js

+141
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
// Test next-on-netlify when config is set from a function in next.config.js
2+
// See: https://github.com/netlify/next-on-netlify/issues/25
3+
4+
const { parse, join } = require("path");
5+
const { existsSync, readdirSync, readFileSync } = require("fs-extra");
6+
const buildNextApp = require("./helpers/buildNextApp");
7+
8+
// The name of this test file (without extension)
9+
const FILENAME = parse(__filename).name;
10+
11+
// The directory which will be used for testing.
12+
// We simulate a NextJS app within that directory, with pages, and a
13+
// package.json file.
14+
const PROJECT_PATH = join(__dirname, "builds", FILENAME);
15+
const FUNCTIONS_DIR = "my-functions";
16+
const PUBLISH_DIR = "my-publish";
17+
18+
// Capture the output to verify successful build
19+
let buildOutput;
20+
21+
beforeAll(
22+
async () => {
23+
runOutput = await buildNextApp()
24+
.forTest(__filename)
25+
.withPages("pages")
26+
.withNextConfig("next.config.js")
27+
.withPackageJson("package.json")
28+
.runWithRequire({ functionsDir: FUNCTIONS_DIR, publishDir: PUBLISH_DIR });
29+
},
30+
// time out after 180 seconds
31+
180 * 1000
32+
);
33+
34+
describe("next-on-netlify", () => {
35+
const functionsDir = join(PROJECT_PATH, FUNCTIONS_DIR);
36+
37+
test("builds successfully", () => {
38+
expect(runOutput).toMatch("Built successfully!");
39+
});
40+
41+
test("creates a Netlify Function for each SSR page", () => {
42+
expect(existsSync(join(functionsDir, "next_index", "next_index.js"))).toBe(
43+
true
44+
);
45+
expect(
46+
existsSync(join(functionsDir, "next_shows_id", "next_shows_id.js"))
47+
).toBe(true);
48+
expect(
49+
existsSync(
50+
join(functionsDir, "next_shows_params", "next_shows_params.js")
51+
)
52+
).toBe(true);
53+
expect(
54+
existsSync(
55+
join(
56+
functionsDir,
57+
"next_getServerSideProps_static",
58+
"next_getServerSideProps_static.js"
59+
)
60+
)
61+
).toBe(true);
62+
expect(
63+
existsSync(
64+
join(
65+
functionsDir,
66+
"next_getServerSideProps_id",
67+
"next_getServerSideProps_id.js"
68+
)
69+
)
70+
).toBe(true);
71+
});
72+
73+
test("copies static pages to output directory", () => {
74+
const OUTPUT_PATH = join(PROJECT_PATH, PUBLISH_DIR);
75+
76+
expect(existsSync(join(OUTPUT_PATH, "static.html"))).toBe(true);
77+
expect(existsSync(join(OUTPUT_PATH, "static/[id].html"))).toBe(true);
78+
});
79+
80+
test("copies static assets to out_publish/_next/ directory", () => {
81+
const dirs = readdirSync(
82+
join(PROJECT_PATH, PUBLISH_DIR, "_next", "static")
83+
);
84+
85+
expect(dirs.length).toBe(2);
86+
expect(dirs).toContain("chunks");
87+
});
88+
});
89+
90+
describe("clean up of NoN files", () => {
91+
test("creates a .nonfiletracking to audit NoN-specific files between builds", () => {
92+
const cacheDir = join(PROJECT_PATH, "/node_modules/.cache/next-on-netlify");
93+
const dirs = readdirSync(cacheDir);
94+
expect(dirs[0]).toEqual(".nonfiletracking");
95+
});
96+
97+
test(".nonfiletracking contains NoN-specific files", () => {
98+
const cacheDir = join(PROJECT_PATH, "/node_modules/.cache/next-on-netlify");
99+
const fileList = readFileSync(join(cacheDir, ".nonfiletracking"), "utf8");
100+
// had to test equality this way because of windows :)
101+
const isSameList = (arr1, arr2) =>
102+
arr1.reduce((isSame, func) => {
103+
if (arr2.includes(func)) {
104+
isSame = true;
105+
} else {
106+
isSame = false;
107+
}
108+
return isSame;
109+
}, true);
110+
const nextFunctions = [
111+
"next_api_shows_id",
112+
"next_api_shows_params",
113+
"next_api_static",
114+
"next_getServerSideProps_all_slug",
115+
"next_getServerSideProps_id",
116+
"next_getServerSideProps_static",
117+
"next_getStaticProps_id",
118+
"next_getStaticProps_static",
119+
"next_getStaticProps_withFallback_id",
120+
"next_getStaticProps_withFallback_slug",
121+
"next_getStaticProps_withRevalidate_id",
122+
"next_getStaticProps_withRevalidate_withFallback_id",
123+
"next_getStaticProps_withrevalidate",
124+
"next_index",
125+
"next_shows_id",
126+
"next_shows_params",
127+
];
128+
const fileListFunctions = fileList.split("---")[0].trim().split("\n");
129+
expect(isSameList(nextFunctions, fileListFunctions)).toBe(true);
130+
const publishFiles = [
131+
"404.html",
132+
"_next",
133+
"_redirects",
134+
"getStaticProps",
135+
"static",
136+
"static.html",
137+
];
138+
const fileListPublish = fileList.split("---")[1].trim().split("\n");
139+
expect(isSameList(publishFiles, fileListPublish)).toBe(true);
140+
});
141+
});

tests/helpers/buildNextApp.js

+34-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ class NextAppBuilder {
6363

6464
// Build the application with next build
6565
async build() {
66-
// Generate a cach hash ID from the current contents of the staging folder.
66+
// Generate a cache hash ID from the current contents of the staging folder.
6767
const { hash: cacheHash } = await hashElement(this.__stagingPath, {
6868
encoding: "hex",
6969
});
@@ -88,6 +88,39 @@ class NextAppBuilder {
8888
return stdout;
8989
}
9090

91+
async runWithRequire(options) {
92+
// Generate a cach hash ID from the current contents of the staging folder.
93+
const { hash: cacheHash } = await hashElement(this.__stagingPath, {
94+
encoding: "hex",
95+
});
96+
this.__cacheHash = cacheHash;
97+
98+
// If we have no cached build for this NextJS app, let's run next build and
99+
// cache the result
100+
if (!existsSync(this.__cachePath)) {
101+
// Build the nextJS app
102+
await npmRun("next-build", this.__stagingPath);
103+
104+
// Cache the build
105+
copySync(this.__stagingPath, this.__cachePath);
106+
}
107+
108+
// Copy the built NextJS app from the cache to the app folder, where we will
109+
// run next-on-netlify
110+
copySync(this.__cachePath, this.__appPath);
111+
112+
process.chdir(this.__appPath);
113+
const nextOnNetlify = require("../..");
114+
nextOnNetlify({
115+
functionsDir: join(this.__appPath, options.functionsDir),
116+
publishDir: join(this.__appPath, options.publishDir),
117+
});
118+
return "Built successfully!";
119+
}
120+
121+
// TO-DO: when I try to split out the shared logic between build & runWithRequire into its own
122+
// function on NextBuilder, everything breaks; not sure why
123+
91124
/*****************************************************************************
92125
* Private functions
93126
****************************************************************************/

0 commit comments

Comments
 (0)