Layer0 3.x run fails when has flag

RUN_LOCAL=true layer0 run works until I make changes, then get the error:

TypeError: Cannot read property 'static' of undefined
    at jT.addAssets (/Users/ashleyjewett/projects/web/.layer0/lambda/routes.js:17:19977)
    at jT.addNextRoutesToGroup (/Users/ashleyjewett/projects/web/.layer0/lambda/routes.js:17:15869)
    at jT.updateRoutes (/Users/ashleyjewett/projects/web/.layer0/lambda/routes.js:17:15728)
    at FSWatcher.<anonymous> (/Users/ashleyjewett/projects/web/.layer0/lambda/routes.js:17:14714)
    at FSWatcher.emit (events.js:315:20)
    at FSEvent.FSWatcher._handle.onchange (internal/fs/watchers.js:186:12)

Note: This only seems to happen when performed with the run local flag.

One thing to check is your node version. Layer0 requires Node 14.

I’m using node v14 LTS

Hey @ajewe. You mentioned some changes that you are making - could you post here what works and doesn’t work? Also, we ignore RUN_LOCAL so the change in the behavior is likely not on our side.

Ah okay, good to know…so locally running our app with just layer0 run, everything works normally and I’m able to make changes to our repo and see updates.

Now going through the logs after running locally with RUN_LOCAL=true layer0 run, I do see this warning at the top:

Ensure that there is only one instance of "graphql" in the node_modules
directory. If different versions of "graphql" are the dependencies of other
relied on modules, use "resolutions" to ensure only one version is installed.

https://yarnpkg.com/en/docs/selective-version-resolutions

Duplicate "graphql" modules cannot be used at the same time since different
versions may have different capabilities and behavior. The data from one
version used in the function from another could produce confusing and
spurious results.
    at Zk (/Users/ashleyjewett/projects/web/.layer0/lambda/routes.js:34:27888)
    at Dn (/Users/ashleyjewett/projects/web/.layer0/lambda/routes.js:45:3428)
    at Xh (/Users/ashleyjewett/projects/web/.layer0/lambda/routes.js:45:3224)
    at rO (/Users/ashleyjewett/projects/web/.layer0/lambda/routes.js:45:6105)
    at nO (/Users/ashleyjewett/projects/web/.layer0/lambda/routes.js:45:6138)
    at new jn (/Users/ashleyjewett/projects/web/.layer0/lambda/routes.js:45:5794)
    at jn (/Users/ashleyjewett/projects/web/.layer0/lambda/routes.js:45:5812)
    at /Users/ashleyjewett/projects/web/.layer0/lambda/routes.js:62:8905
    at /Users/ashleyjewett/projects/web/.layer0/lambda/routes.js:1:709
    at /Users/ashleyjewett/projects/web/.layer0/lambda/routes.js:62:14180
    at /Users/ashleyjewett/projects/web/.layer0/lambda/routes.js:1:709
    at /Users/ashleyjewett/projects/web/.layer0/lambda/routes.js:64:56854
    at /Users/ashleyjewett/projects/web/.layer0/lambda/routes.js:1:709
    at /Users/ashleyjewett/projects/web/.layer0/lambda/routes.js:68:17654
    at /Users/ashleyjewett/projects/web/.layer0/lambda/routes.js:1:709
    at /Users/ashleyjewett/projects/web/.layer0/lambda/routes.js:184:34165

But it’s still running, until there are any source code changes, then it breaks with that err included in my initial post. So the sequence is:

  1. run RUN_LOCAL=true layer0 run command, it does an initial build which works fine
  2. I make source code changes, (any changes)
  3. it detects changes and rebuilds, and it crashes

I assume RUN_LOCAL is an environment variable that’s specific to your app? It’s not something that Layer0 uses. What does RUN_LOCAL do?

We’re using it to ensure the config uses our local .env.local file

//layer0.config.js

if (process.env.RUN_LOCAL === 'true') {
    const path = require('path');
    const env = require('dotenv');
    env.config({ path: path.resolve(process.cwd(), '.env.local') });
}

RUN_LOCAL=true layer0 run works as expected on this POC:

It looks like there’s actually a bug in @layer0/next. Is the repo on GitHub?

@howie.ross The POC contains both a package-lock.json and a yarn.lock. They are also out of sync from each other. It’s possible that the repo might exhibit the bug if its installation was reproducible.

The type definitions emitted for the library are very unusual. It appears that the original TypeScript was not annotated correctly (most class methods have no type annotation at all, some properties are typed as any, etc.) and the compiler was misconfigured in such a way that those issues were not reported.

NextRoutes.d.ts:

import PluginBase from '@layer0/core/plugins/PluginBase';
import ResponseWriter from '@layer0/core/router/ResponseWriter';
import RouteGroup from '@layer0/core/router/RouteGroup';
import Router from '@layer0/core/router/Router';
export default class NextRoutes extends PluginBase {
    private nextRouteGroupName;
    private nextRootDir;
    private pagesDir;
    private pagesDirRelative;
    private router?;
    private rewrites?;
    private redirects?;
    private routesManifest;
    private distDir;
    private defaultLocale?;
    type: string;
    /**
     * Provides next registered routes to router
     * @param {Function} renderFn Next page render function
     */
    constructor(nextRootDir?: string);
    /**
     * Attempt to get rewrites and redirects from routes-manifest.json in production.
     */
    private loadRewrites;
    /**
     * Returns the contents of pages-manifest.json
     */
    private getPagesManifest;
    /**
     * Returns the contents of prerender-manifest.json
     */
    private getPrerenderManifest;
    /**
     * Attempt to get rewrites and redirects from the next config in development.
     */
    private loadRewritesInDev;
    /**
     * Called when plugin is registered
     * @param router
     */
    onRegister(router: Router): void;
    /**
     * Update routes
     */
    private updateRoutes;
    /**
     * Adds next routes to route group
     * @param {RouteGroup} group
     */
    private addNextRoutesToGroup;
    /**
     * Find an existing route that would match a request with destination as the path - we will run its handler when
     * the request's path matches the rewrite source.
     * @param group
     * @param source
     * @param destination
     * @param index
     */
    private addRewrite;
    private addRewrites;
    /**
     * Adds rewrites and redirects from next.config.js
     * @param group
     */
    private addRedirects;
    /**
     * Adds routes for all pages and corresponding data in development
     * @param group
     */
    private addPagesInDev;
    /**
     * Adds routes for react components and API handlers
     * @param {*} group
     */
    private addPagesInProd;
    /**
     * Removes the locale part from the start of path
     * @param path E.g /en-US/p/[id]
     * @returns the path minus the locale, e.g /p/[id]
     */
    private removeLocale;
    /**
     * Automatically configure prerendering to pull all SSG pages into the edge cache.
     * This only needs to be done during a production build.
     */
    private addPrerendering;
    /**
     * Production route handler for all dynamic HTML and JSON requests (SSR and SSG).
     * @param page The next.js page to render
     */
    private createSSRHandler;
    /**
     * Creates a handler for SSG pages that can be optionally configured with fallback: trlayer0dfdue
     * @param page The next.js page path
     * @param options
     */
    private createSSGHandler;
    /**
     * Renders the the 404 page.
     *
     * Example:
     *
     * ```js
     *  import { nextRoutes } from '@layer0/next'
     *  import { Router } from '@layer0/core/router'
     *
     *  export default new Router()
     *    .get('/some/missing/page', (res) => {
     *      nextRoutes.render404(res)
     *    })
     *    .use(nextRoutes)
     * ```
     *
     * @param res
     */
    render404(res: ResponseWriter): Promise<void>;
    /**
     * Adds routes for static assets, including /public and /.next/static
     */
    private addAssets;
    /**
     * Adds routes for image-optimizer
     */
    addImageOptimizerRoutes(group: RouteGroup): void;
}

At the very least, compiling the project in strict mode would catch the class of error that @ajewe encountered.

EDIT: It appears that type annotations in the JSDoc comments are in conflict with the type annotations themselves (see the constructor, for example). This can causes issues for the compiler in some cases because it actually utilizes both kinds of type annotations.

This is logged as XDN-11818 to review our type annotations in doc comments.