Skip to content

Commit

Permalink
API GW -> S3 proxy support & new routes configuration (#60)
Browse files Browse the repository at this point in the history
* feat: add support for new page routes and api gw static routes proxied to S3
  • Loading branch information
danielcondemarin authored May 11, 2019
1 parent cee3829 commit 6523b5e
Show file tree
Hide file tree
Showing 30 changed files with 1,104 additions and 716 deletions.
151 changes: 23 additions & 128 deletions __tests__/index.test.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,7 @@
const ServerlessPluginBuilder = require("../utils/test/ServerlessPluginBuilder");
const displayStackOutput = require("../lib/displayStackOutput");
const build = require("../lib/build");
const NextPage = require("../classes/NextPage");
const PluginBuildDir = require("../classes/PluginBuildDir");

jest.mock("js-yaml");
jest.mock("../lib/build");
jest.mock("../lib/parseNextConfiguration");
jest.mock("../lib/displayStackOutput");
jest.mock("../utils/logger");

describe("ServerlessNextJsPlugin", () => {
let pluginBuilder;
Expand All @@ -25,132 +18,20 @@ describe("ServerlessNextJsPlugin", () => {
});

it.each`
hook | method
${"before:offline:start"} | ${"buildNextPages"}
${"before:package:initialize"} | ${"buildNextPages"}
${"before:deploy:function:initialize"} | ${"buildNextPages"}
${"before:package:createDeploymentArtifacts"} | ${"addAssetsBucketForDeployment"}
${"after:aws:deploy:deploy:uploadArtifacts"} | ${"uploadStaticAssets"}
${"after:aws:info:displayStackOutputs"} | ${"printStackOutput"}
${"after:package:createDeploymentArtifacts"} | ${"removePluginBuildDir"}
hook | method
${"before:offline:start"} | ${"build"}
${"before:package:initialize"} | ${"build"}
${"before:deploy:function:initialize"} | ${"build"}
${"after:aws:deploy:deploy:uploadArtifacts"} | ${"uploadStaticAssets"}
${"after:aws:info:displayStackOutputs"} | ${"printStackOutput"}
${"after:package:createDeploymentArtifacts"} | ${"removePluginBuildDir"}
${"before:aws:package:finalize:mergeCustomProviderResources"} | ${"addCustomStackResources"}
`("should hook to $hook with method $method", ({ hook, method }) => {
expect(plugin[method]).toBeDefined();
expect(plugin.hooks[hook]).toEqual(plugin[method]);
});
});

describe("#buildNextPages", () => {
describe("packaging plugin build directory", () => {
const nextConfigDir = "/path/to/next-app";

beforeEach(() => {
build.mockResolvedValueOnce([]);
});

it("should include plugin build directory for packaging", () => {
expect.assertions(1);

const plugin = pluginBuilder
.withNextCustomConfig({ nextConfigDir })
.build();

return plugin.buildNextPages().then(() => {
expect(plugin.serverless.service.package.include).toContain(
`${nextConfigDir}/${PluginBuildDir.BUILD_DIR_NAME}/**`
);
});
});

it("should include plugin build directory for packaging when package include isn't defined", () => {
expect.assertions(1);

const plugin = pluginBuilder
.withNextCustomConfig({ nextConfigDir })
.build();

plugin.serverless.service.package.include = undefined;

return plugin.buildNextPages().then(() => {
expect(plugin.serverless.service.package.include).toContain(
`${nextConfigDir}/${PluginBuildDir.BUILD_DIR_NAME}/**`
);
});
});
});

it("should call build with pluginBuildDir and user provided pageConfig", () => {
expect.assertions(1);

build.mockResolvedValueOnce([]);
const nextConfigDir = "/path/to/next";

const pageConfig = {
home: {
memory: "512"
}
};

const plugin = new ServerlessPluginBuilder()
.withNextCustomConfig({
nextConfigDir: nextConfigDir,
pageConfig
})
.build();

return plugin.buildNextPages().then(() => {
expect(build).toBeCalledWith(
new PluginBuildDir(nextConfigDir),
pageConfig,
undefined
);
});
});

it("should set the next functions in serverless", () => {
expect.assertions(1);

const homePagePath = "/path/to/next/build/serverless/pages/home.js";
const aboutPagePath = "/path/to/next/build/serverless/pages/about.js";

build.mockResolvedValueOnce([
new NextPage(homePagePath),
new NextPage(aboutPagePath)
]);

const plugin = new ServerlessPluginBuilder().build();

return plugin.buildNextPages().then(() => {
expect(Object.keys(plugin.serverless.service.functions)).toEqual([
"homePage",
"aboutPage"
]);
});
});

it("should call service.setFunctionNames", () => {
expect.assertions(1);

const homePagePath = "/path/to/next/build/serverless/pages/home.js";
const aboutPagePath = "/path/to/next/build/serverless/pages/about.js";

build.mockResolvedValueOnce([
new NextPage(homePagePath),
new NextPage(aboutPagePath)
]);

const setFunctionNamesMock = jest.fn();

const plugin = new ServerlessPluginBuilder()
.withService({
setFunctionNames: setFunctionNamesMock
})
.build();

return plugin.buildNextPages().then(() => {
expect(setFunctionNamesMock).toBeCalled();
});
});
});

describe("#printStackOutput", () => {
it("should call displayStackOutput with awsInfo", () => {
const awsInfo = {
Expand Down Expand Up @@ -183,4 +64,18 @@ describe("ServerlessNextJsPlugin", () => {
});
});
});

describe("#getPluginConfigValue", () => {
it("uses default values when config key not provided", () => {
const plugin = pluginBuilder
.withPluginConfig({
routes: undefined,
uploadBuildAssets: undefined
})
.build();

expect(plugin.getPluginConfigValue("routes")).toEqual([]);
expect(plugin.getPluginConfigValue("uploadBuildAssets")).toEqual(true);
});
});
});
39 changes: 38 additions & 1 deletion classes/NextPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ const toPosix = require("../utils/pathToPosix");
const PluginBuildDir = require("./PluginBuildDir");

class NextPage {
constructor(pagePath, serverlessFunctionOverrides) {
constructor(pagePath, { serverlessFunctionOverrides, routes } = {}) {
this.pagePath = pagePath;
this.serverlessFunctionOverrides = serverlessFunctionOverrides;
this.routes = routes;
}

get pageOriginalPath() {
Expand All @@ -22,6 +23,22 @@ class NextPage {
return path.dirname(this.pagePath);
}

get pageId() {
const pathSegments = this.pagePath.split(path.sep);

// strip out the parent build directory from path
// sls-next-build/foo/bar.js -> /foo/bar.js
const relativePathSegments = pathSegments.slice(
pathSegments.indexOf(PluginBuildDir.BUILD_DIR_NAME) + 1,
pathSegments.length
);

// remove extension
// foo/bar.js -> /foo/bar
const parsed = path.parse(relativePathSegments.join(path.posix.sep));
return path.posix.join(parsed.dir, parsed.name);
}

get pageName() {
return path.basename(this.pagePath, ".js");
}
Expand Down Expand Up @@ -86,6 +103,15 @@ class NextPage {
merge(configuration, this.serverlessFunctionOverrides);
}

if (this.routes && this.routes.length > 0) {
configuration.events = [];

this.routes.forEach(r => {
const httpEvent = this.getHttpEventForRoute(r);
configuration.events.push(httpEvent);
});
}

const httpHeadEvents = this.getMatchingHttpHeadEvents(
configuration.events.filter(e => e.http.method === "get")
);
Expand All @@ -104,6 +130,17 @@ class NextPage {
return headEvent;
});
}

getHttpEventForRoute(route) {
const httpEvent = {
http: {
method: "get",
...route
}
};

return httpEvent;
}
}

module.exports = NextPage;
Loading

0 comments on commit 6523b5e

Please sign in to comment.