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

Initialization extensions (move TS handling to extension package) #9311

Open
medikoo opened this issue Apr 16, 2021 · 2 comments
Open

Initialization extensions (move TS handling to extension package) #9311

medikoo opened this issue Apr 16, 2021 · 2 comments

Comments

@medikoo
Copy link
Contributor

medikoo commented Apr 16, 2021

Use case description

Originally discussed at serverless/typescript#28 (comment)

Framework already supports plugins. Still plugins can be configured only through service configuration, which means that there's no way to e.g. add support for different file type to serve as configuration type through plugin.

In light of that, such support needs to be baked into Framework internals (and this is what we did with TypeScript). Still that proves to be limited, error-prone, and incurs additional maintenance cost to the core.

Ideally if such extension can be configured externally and injected prior service file resolution.

Having that we could also move all TS related support to @serverless/typescript, and in its context solve all TS related challenges and make TS support even better.

Proposed solution (Strategy)

Recognize serverless.extensions property in package.json (resolved from current working directory only) which should be an array listing all extensions to be loaded when serverless command is invoked.

Each item in serverless.extensions should be a path to module, to be resolved with Node.js module resolution rules, e.g:

{
  "serverless": {
    "extensions": ["@serverless/typescript"]
  }
}

Will attempt to load main module of @serverless/typescript package from node_modules

Extension should export an object, which may expose following properties:

  • resolveServiceConfiguration - (possibly async) function which will be invoked before Framework internally attempts to resolve the service configuration. When invoked it should either return null, or object with configuration, serviceDir and configurationFilename properties.
  • variableFileSources - Object with configuration of support for additional file import variable extensions.

Example:

module.exports.resolveServiceConfiguration = async () => {
  // Resolve service configuration against process.cwd();
  return {
    configuration: {
      // Service configuration
    },
    serviceDir: // Absolute path to directory against which configuration paths should be resolved
    configurationFilename: "serverless.ts"
}

module.exports.variableFileSources = {
  // Add support for .ts file imports
  ts: async (filePath) => {
    // Resolve TS filePath content
    return JSONValuecontent;
  }
};

How to implement it? (Tactics)

1. Extensions resolution

  1. Introduce lib/cli/resolve-initialization-extensions.js module, which should:
    • Read package.json from current working directory
    • If it exists and hosts serverless.extensions property. It should validate it as an array (if it isn't it should throw meaningful error), and should load each extension, then it should confirm that all of them export plain object, with optional resolveServiceConfiguration plain function, and optional variableFileSources plain object, on which all properties are plain functions. Module should return array of resolved extensions.
  2. Right at serverless process intialization resolve extensions with lib/cli/resolve-initialization-extensions.js util.

2. Resolution of configuration data through extension

Right before we resolve configuration path internally, run resolveServiceConfiguration from all resolved extensions, stop on first that resolves a value. Validate existence of all properties configuration, serviceDir and configurationFilename.
if configuration data was resolved from extension, use it in the process, and do not resolve those values internally.

3. Registration of new file source extension

  1. Update variable resolver configuration, so file source configuration is updated with support for eventually configured custom extensions. We can do it by updating
    file: require('../lib/configuration/variables/sources/file'),
    to:
resolverConfiguration: {
  ...
  sources: {
    ...
    file: { ...require('../lib/configuration/variables/sources/file'), customFileResolvers: fileResolversFromExtensions }
  }
}
  1. Update file source resolver, to handle eventual this.customFileResolvers here:
    // Anything else support as plain text
@medikoo
Copy link
Contributor Author

medikoo commented Apr 16, 2021

@fredericbarthelet @pgrzesik let me know what you think about this proposal

@pgrzesik
Copy link
Contributor

Thanks @medikoo for a detailed proposal 🙌 It looks great in my opinion from a extension-agnostic point of view - as I'm not an expert on TS-related stuff, I cannot fully say that it will allow to support all intended use cases listed on original issue in typescript repository.

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

No branches or pull requests

2 participants