Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding a serverless.js file breaks expected functionality for Next.js Serverless Component with next-i18next support #8503

Closed
kylekirkby opened this issue Nov 14, 2020 · 5 comments

Comments

@kylekirkby
Copy link

I'm trying to deploy the infrastructure required running a multi-environment next.js app with i18n support. There is an issue where the @sls-next/serverless-component fails to add the translation JSON files to the default-lambda src. Someone in another issue (serverless-nextjs/serverless-next.js#383 (comment)) suggested extending the sls-next/serverless-component with a serverless.js file. This seems logical and great until adding this file breaks everything else. Adding a serverless.js file to extend a component results in serverless requiring a service and provider property but then still fails to deploy as expected.

serverless.yml
myNextApp:
  component: "./"
  inputs:
    timeout: 30
  memory: 1024
serverless.js
// serverless.js
const NextJsComponent = require("serverless-next.js/serverless");
const fs = require("fs-extra");

class MyNextJsComponent extends NextJsComponent {
  async default(inputs = {}) {
    if (inputs.build !== false) {
      console.log("-> Building...");
      await this.build(inputs);
      console.log("Building was successful");
    }
    console.log("-> Copying locales directory...");
    this.copyLocales();
    console.log("Locale directory was copied successfully");
    console.log("-> Updating manifest...");
    this.updateNonDynamicManifest();
    console.log("Manifest update successful");
    console.log("-> Deploying...");
    return this.deploy(inputs);
  }

  copyLocales() {
    const localeSrc = "./static/locales";
    const localeDest = "./.serverless_nextjs/default-lambda/static/locales";
    fs.copySync(localeSrc, localeDest, { recursive: true });
  }

  updateNonDynamicManifest() {
    const manifestFileName =
      "./.serverless_nextjs/default-lambda/manifest.json";
    const manifestJson = require(manifestFileName);
    manifestJson.pages.ssr.nonDynamic["/index"] = "pages/index.js";
    fs.writeFileSync(manifestFileName, JSON.stringify(manifestJson));
  }
}

module.exports = MyNextJsComponent;
npx serverless output
  Serverless Error ---------------------------------------

  "service" property is missing in serverless.yml

  Get Support --------------------------------------------
     Docs:          docs.serverless.com
     Bugs:          github.com/serverless/serverless/issues
     Issues:        forum.serverless.com

  Your Environment Information ---------------------------
     Operating System:          linux
     Node Version:              12.18.1
     Framework Version:         2.11.1 (standalone)
     Plugin Version:            4.1.2
     SDK Version:               2.3.2
     Components Version:        3.3.0

Installed version

Framework Core: 2.11.1 (standalone)
Plugin: 4.1.2
SDK: 2.3.2
Components: 3.3.0
@dphang
Copy link

dphang commented Nov 14, 2020

The way next-18n works is that it expects locales to be in the local filesystem (Lambda in this case), however the serverless-next.js component doesn't know about the requirements of specific packages like next-18n. Two things (specific to serverless-next.js):

  1. Actually I added an input build.postBuildCommands which lets you run arbitrary commands after build but before deploy. So you can use it to add additional things into the .serverless_nextjs directory. For example, you can copy files into default-lambda, which is useful for next-18n or other similar packages that need files in the local filesystem (Lambda in this case). See here: Deploying with Serverless-next.js not working RFC Custom rewrites serverless-nextjs/serverless-next.js#767 (comment). You can try to copy the locales files using that method by adding any JS script, e.g your-script.js. Then you can execute it by adding postBuildCommands: ["node your-script.js"], and it will run in between build and deploy steps.

  2. For extending the component if you need even more flexibility, you should try to inspect the structure of the @sls-next/serverless-component npm package and might need to point it to something like /Users/danielphang/.serverless/components/registry/npm/@sls-next/serverless-component@1.18.0-alpha.18/node_modules/@sls-next/serverless-component/dist/component.js instead (or src/component.ts might work if you have TypeScript). So, I believe you'd have to add @sls-next/serverless-component to your package.json and then do:

import NextJsComponent from "@sls-next/serverless-component";

or

const NextJsComponent = require("@sls-next/serverless-component");

for the latest Serverless-next.js component version. TypeScript definitions are in @sls-next/serverless-component/dist/component.d.ts.

Also, for:

const NextJsComponent = require("serverless-next.js/serverless");

^ this one seems to be for an older version of serverless-next.js, maybe the old serverless-next.js component? So I wouldn't recommend to use it since it is unmaintained. (Sorry, don't quite remember, since it was before I joined this project).

Note that overriding methods this way might mean that you might not get latest updates if our component changes; you'd have to manually sync it yourself.

I think that error happens when Serverless can't resolve the component, then treats it like a regular Serverless framework app, not Serverless Components (it has to extend Component which is from Serverless).

@kylekirkby
Copy link
Author

Wow! Thank you @dphang for the in-depth reply!

Actually I added an input build.postBuildCommands which lets you run arbitrary commands after build but before deploy. So you can use it to add additional things into the .serverless_nextjs directory. For example, you can copy files into default-lambda, which is useful for next-18n or other similar packages that need files in the local filesystem (Lambda in this case). See here: serverless-nextjs/serverless-next.js#767 (comment). You can try to copy the locales files using that method by adding any JS script, e.g your-script.js. Then you can execute it by adding postBuildCommands: ["node your-script.js"], and it will run in between build and deploy steps.

This seems like a totally logical way to copy over the locales files. I don't know why I didn't think of/see this in the README.

import NextJsComponent from "@sls-next/serverless-component";

or

const NextJsComponent = require("@sls-next/serverless-component");

I've just tried adding the @sls-next/serverless-component to my package.json and importing/requiring using the suggestions you provided but still get:

  Serverless Error ---------------------------------------

  "service" property is missing in serverless.yml

  Get Support --------------------------------------------
     Docs:          docs.serverless.com
     Bugs:          github.com/serverless/serverless/issues
     Issues:        forum.serverless.com

  Your Environment Information ---------------------------
     Operating System:          linux
     Node Version:              12.18.1
     Framework Version:         2.11.1 (standalone)
     Plugin Version:            4.1.2
     SDK Version:               2.3.2
     Components Version:        3.3.0

I'm starting to think that serverless may have removed the functionality for extending a component and importing directly. From the documentation I cannot see any reference to using ./ to import an extended version of a component.

I'm going to try using the postBuildCommands suggestion now and see where I get! Thank you again!

@dphang
Copy link

dphang commented Nov 14, 2020

Sure, I am not sure if they removed ./ specifically but I thought Serverless should resolve a component if it finds a proper serverless.js file in that directory. At least that's what serverless-next.js does for its nextjs-component: https://github.com/serverless-nextjs/serverless-next.js/blob/84a3f40345c4e7a2e6dd72832ee148372bdcc813/packages/serverless-components/nextjs-component/serverless.js#L1-L3. While developing/maintaining serverless-next.js, I use a local component by pointing to a local nextjs-component directory.

@kylekirkby
Copy link
Author

I thought so too. Maybe, as you say, I'm pointing it at an invalid serverless.js file. 🤔

@medikoo
Copy link
Contributor

medikoo commented Nov 16, 2020

@kylekirkby thanks for report, but I believe this belongs to https://github.com/serverless-nextjs/serverless-next.js and not here. Can you open this issue over there?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants