Connector packages help build and run your app within Layer0. When you run layer0 init, Layer0 CLI detects the framework used by your app and installs the corresponding connector package. For example, if you use Next.js, @layer0/next will be installed. If no connector package exists for the framework that you use, you can still deploy to Layer0 by implementing the connector interface directly in your app.

A Layer0 connector consists of four entry points:

  • init.js - Called when the user runs layer0 init, adding resources to the project necessary for deploying on Layer0. May also modify existing files with the project.
  • dev.js - Called when the user runs layer0 dev to run their app in development mode.
  • build.js - Called when the user runs layer0 build or layer0 deploy. Builds the application, copying resources into the .layer0 directory, which is ultimately zipped and uploaded to Layer0.
  • prod.js - Starts the application server in Layer0 cloud's serverless environment.

These files should be placed in the root directory of your connector package.

Called when the user runs layer0 init. This entry point adds resources to the project necessary for deploying on Layer0. It may also modify existing files within the project.

Optional, if not provided, layer0 init will add a default router and layer0.config.js to the user's project.

Example:

/* istanbul ignore file */
const { join } = require('path')
const { DeploymentBuilder } = require('@layer0/core/deploy')

/**
 * Called when the user runs layer0 init.
 */
export default async function init() {
  new DeploymentBuilder(process.cwd())
    // Copy files from the default-app directory within the connector package.
    // These typically include the routes.js file and layer0.config.js. Typescript alternatives are often provided.
    .addDefaultAppResources(join(__dirname, 'default-app'))

    // Adds layer0:* scripts to package.json
    .addDefaultLayer0Scripts()
}

The default-app directory typically contains the following files:

/(connector-root)
  /default-app
    /all              # resources to be added to both JavaScript and TypeScript projects
      layer0.config.js   # a default layer0.config.js file
    /js               # resources to be added to projects that do not use TypeScript
      routes.js       # a JavaScript implementation of the default routes file
    /ts               # resouces to be added to projects that use TypeScript
      routes.ts       # a TypeScript implementation of the default routes file

Additional files can be added beyond the ones listed above. They will be copied into the root directory of the user's application.

Called when the user runs layer0 dev. This entry point is responsible for starting the user's application in development mode. The @layer0/core library provides a createDevServer function to help with this.

Optional, if not provided, layer0 dev will simply start Layer0 in local development mode, but will not start a framework application server.

Example:

const { createDevServer } = require('@layer0/core/dev')

module.exports = function() {
  return createDevServer({
    // All console output from your app will be prefixed with this label
    label: 'Sapper',

    // The command to start your app in dev mode
    command: () => 'npx sapper dev',

    // Once your app's console output has matched all of the following patterns, the "Layer0 ready on ..." message will be displayed
    ready: [/listening on/i],

    // A function that is called with every line of output from your app. Return true to show that line to the user, false to hide it.
    // Many connectors use this to hide lines like "Next.js ready on http://localhost:3001", which might confuse the user as to
    // which URL to use when testing their app behind Layer0.
    filterOutput: line => !line.match(/some pattern/),
  })
}

Exports a function that is called when you run layer0 build. It is responsible for constructing the bundle that is deployed to the Layer0 cloud. This function typically uses @layer0/core/deploy/DeploymentBuilder to stage the exploded bundle in the .layer0 directory.

Optional, and not needed in most cases. The layer0 build command automatically creates a bundle that includes all static assets referenced in your routes file as well as the prod entry point mentioned above.

Example:

const { DeploymentBuilder } = require('@layer0/core/deploy')
const FrameworkBuildError = require('@layer0/core/errors/FrameworkBuildError')

export default async function build({ skipFramework }) {
  const builder = new DeploymentBuilder(appDir)
  builder.clearPreviousBuildOutput()

  if (!skipFramework) {
    // run the sapper build
    try {
      await builder.exec('npx sapper build')
    } catch (e) {
      // this lets the user know that the build error was within their application code, not their Layer0 router or configuration.
      throw new FrameworkBuildError('Sapper')
    }
  }

  builder
    // optionally add some file required by the app at runtime.  This is equivalent to setting the includeFiles config in layer0.config.js
    .addJSAsset('path/to/file/in/project')

  // build the Layer0 deployment bundle in the .layer0 directory
  await builder.build()
}

Layer0 runs your application in its serverless cloud by proxying requests to your framework's application server, which it expects to be running on a specific port. The prod.js entry point exports a function that is called when a new serverless function is provisioned. It is responsible for starting your app on the provided port so that it can receive requests from Layer0.

Optional. This entry point is only needed if your app uses server-side rendering or calls the renderWithApp method on ResponseWriter.

For example:

module.exports = async function prod(port) {
  process.env.PORT = port.toString()

  // Most frameworks export some kind of express server or other http listener. Your prod script
  // just needs to start it and bind it to the provided port.  In the case of Sapper, the way to do
  // this is to set the PORT environment variable and run the provided server script
  require('./__sapper__/build/server/server')
}

Note that the prod entry point cannot have any external dependencies. If your prod entry point imports any non-native node modules, you'll need to bundle it with something like webpack or rollup before publishing your package.

Here is an example webpack config:

// webpack.config.js
module.exports = {
  target: 'node',
  entry: {
    prod: './src/prod.js',
  },
  mode: 'production',
  resolve: {
    extensions: ['.js'],
  },
  output: {
    filename: '[name].js',
    path: './dist',
    libraryTarget: 'umd',
  },
}

To test your connector locally without publishing it to NPM:

  1. Use npm link, yarn link or yalc add to add the local connector package as a project dependency.
  2. Create an layer0.config.js file in the root directory of your project.
  3. Set the connector property to name of the connector package.

Now layer0 init, layer0 dev, layer0 build, and layer0 deploy commands will use the entry points in the connector, and your prod.js entrypoint will be used to serve requests in the Layer0 cloud.

If your project uses a framework that isn't supported by one of the official connector packages, you can still deploy to Layer0 by implementing your own connector directly within your project. To do so:

  1. Create a directory for your connector.
  2. Implement the entry points listed above.
  3. Create an layer0.config.js file in the root directory of your project.
  4. Set the connector property to the relative path to the directory containing the connector

Example project structure:

/my-project
  /layer0              # reference this directory in the connector property in layer0.config.js
    dev.js
    prod.js
    build.js
  layer0.config.js
  ... other source files and directories ...

Example layer0.config.js:

module.exports = {
  connector: './layer0', // use the local connector located in layer0 directory
}

Once the connector is in place, layer0 dev, layer0 build, and layer0 deploy commands will use the entry points in the connector, and your prod.js entrypoint will be used to serve requests in the Layer0 cloud.