Skip to content

Commit

Permalink
Support static directory upload to S3 (#54)
Browse files Browse the repository at this point in the history
* feat: add support for static directory upload to S3
* feat: add debug flag exposed via DEBUG=sls-next:*
  • Loading branch information
danielcondemarin authored Apr 27, 2019
1 parent 6739a5f commit 97c6405
Show file tree
Hide file tree
Showing 14 changed files with 799 additions and 361 deletions.
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,12 @@ custom:

With this approach you could have a CloudFront distribution in front of the bucket and use a custom domain in the assetPrefix.

| Plugin config key | Default Value | Description |
| ----------------- | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| assetsBucketName | \<empty\> | Creates an S3 bucket with the name provided. The bucket will be used for uploading next static assets |
| staticDir | \<empty\> | Directory with static assets to be uploaded to S3, typically a directory named `static`, but it can be any other name. Requires a bucket provided via the `assetPrefix` described above or the `assetsBucketName` plugin config. |
| uploadBuildAssets | true | In the unlikely event that you only want to upload the `staticDir`, set this to `false` |

## Deploying

`serverless deploy`
Expand Down
65 changes: 0 additions & 65 deletions __tests__/index.test.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
const path = require("path");
const ServerlessPluginBuilder = require("../utils/test/ServerlessPluginBuilder");
const parsedNextConfigurationFactory = require("../utils/test/parsedNextConfigurationFactory");
const uploadStaticAssetsToS3 = require("../lib/uploadStaticAssetsToS3");
const displayStackOutput = require("../lib/displayStackOutput");
const parseNextConfiguration = require("../lib/parseNextConfiguration");
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/uploadStaticAssetsToS3");
jest.mock("../lib/displayStackOutput");
jest.mock("../utils/logger");

Expand Down Expand Up @@ -159,66 +154,6 @@ describe("ServerlessNextJsPlugin", () => {
});
});

describe("#uploadStaticAssets", () => {
it("should NOT call uploadStaticAssetsToS3 when there isn't a bucket available", () => {
parseNextConfiguration.mockReturnValueOnce(
parsedNextConfigurationFactory({}, null)
);

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

return plugin.uploadStaticAssets().then(() => {
expect(uploadStaticAssetsToS3).not.toBeCalled();
});
});

it("should call uploadStaticAssetsToS3 with bucketName and next static dir", () => {
const distDir = "build";
parseNextConfiguration.mockReturnValueOnce(
parsedNextConfigurationFactory({
distDir
})
);

uploadStaticAssetsToS3.mockResolvedValueOnce("Assets Uploaded");

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

return plugin.uploadStaticAssets().then(() => {
expect(uploadStaticAssetsToS3).toBeCalledWith({
staticAssetsPath: path.join("/path/to/next", distDir, "static"),
bucketName: "my-bucket",
providerRequest: expect.any(Function)
});
});
});

it("should call uploadStaticAssetsToS3 with bucketName from plugin config", () => {
const distDir = "build";
parseNextConfiguration.mockReturnValueOnce(
parsedNextConfigurationFactory({
distDir
})
);

uploadStaticAssetsToS3.mockResolvedValueOnce("Assets Uploaded");

const plugin = new ServerlessPluginBuilder()
.withNextCustomConfig({
assetsBucketName: "custom-bucket"
})
.build();

return plugin.uploadStaticAssets().then(() => {
expect(uploadStaticAssetsToS3).toBeCalledWith({
staticAssetsPath: path.join("/path/to/next", distDir, "static"),
bucketName: "custom-bucket",
providerRequest: expect.any(Function)
});
});
});
});

describe("#printStackOutput", () => {
it("should call displayStackOutput with awsInfo", () => {
const awsInfo = {
Expand Down
28 changes: 2 additions & 26 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
"use strict";

const path = require("path");
const uploadStaticAssetsToS3 = require("./lib/uploadStaticAssetsToS3");
const displayStackOutput = require("./lib/displayStackOutput");
const parseNextConfiguration = require("./lib/parseNextConfiguration");
const build = require("./lib/build");
const PluginBuildDir = require("./classes/PluginBuildDir");
const addAssetsBucketForDeployment = require("./lib/addAssetsBucketForDeployment");
const uploadStaticAssets = require("./lib/uploadStaticAssets");

class ServerlessNextJsPlugin {
constructor(serverless, options) {
Expand All @@ -19,7 +19,7 @@ class ServerlessNextJsPlugin {
this.pluginBuildDir = new PluginBuildDir(this.nextConfigDir);

this.addAssetsBucketForDeployment = addAssetsBucketForDeployment.bind(this);
this.uploadStaticAssets = this.uploadStaticAssets.bind(this);
this.uploadStaticAssets = uploadStaticAssets.bind(this);
this.printStackOutput = this.printStackOutput.bind(this);
this.buildNextPages = this.buildNextPages.bind(this);
this.removePluginBuildDir = this.removePluginBuildDir.bind(this);
Expand Down Expand Up @@ -74,30 +74,6 @@ class ServerlessNextJsPlugin {
this.serverless.service.setFunctionNames();
}

uploadStaticAssets() {
let { nextConfiguration, staticAssetsBucket } = this.configuration;

const bucketNameFromConfig = this.getPluginConfigValue("assetsBucketName");

if (bucketNameFromConfig) {
staticAssetsBucket = bucketNameFromConfig;
}

if (!staticAssetsBucket) {
return Promise.resolve();
}

return uploadStaticAssetsToS3({
staticAssetsPath: path.join(
this.nextConfigDir,
nextConfiguration.distDir,
"static"
),
providerRequest: this.providerRequest,
bucketName: staticAssetsBucket
});
}

printStackOutput() {
const awsInfo = this.serverless.pluginManager.getPlugins().find(plugin => {
return plugin.constructor.name === "AwsInfo";
Expand Down
19 changes: 19 additions & 0 deletions lib/__tests__/addAssetsBucketForDeployment.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,25 @@ describe("addAssetsBucketForDeployment", () => {
jest.clearAllMocks();
});

it("should error if staticDir provided but no bucket", () => {
expect.assertions(1);

const pluginWithoutBucket = new ServerlessPluginBuilder()
.withNextCustomConfig({
nextConfigDir: "./",
staticDir: "./static"
})
.build();

parseNextConfiguration.mockReturnValueOnce(
parsedNextConfigurationFactory({ staticAssetsBucket: null }, null)
);

return addAssetsBucketForDeployment.call(pluginWithoutBucket).catch(err => {
expect(err.message).toContain("staticDir requires a bucket. See");
});
});

it("should not call addS3BucketToResources if a staticAssetsBucket is not available", () => {
expect.assertions(1);
parseNextConfiguration.mockReturnValueOnce(
Expand Down
211 changes: 0 additions & 211 deletions lib/__tests__/uploadStaticAssetsToS3.test.js

This file was deleted.

Loading

0 comments on commit 97c6405

Please sign in to comment.