From aef5a0d6c49d0bfbfb93a43a29cf5b4cd28f41da Mon Sep 17 00:00:00 2001 From: Sean Dawson Date: Tue, 28 Jan 2020 14:38:20 +1000 Subject: [PATCH 1/4] fix: only process functions if runtime is node - This change fixes an issue where serverless-plugin-typescript would try to process functions that used different runtimes. - Typescript functions will only run on node runtimes so it makes sense to exclude functions on other runtimes from processing --- src/Serverless.d.ts | 2 + src/index.ts | 1 + src/typescript.ts | 8 +- tests/typescript.extractFileName.test.ts | 93 +++++++++++++++++++----- 4 files changed, 84 insertions(+), 20 deletions(-) diff --git a/src/Serverless.d.ts b/src/Serverless.d.ts index ec7d7049..1a47388d 100644 --- a/src/Serverless.d.ts +++ b/src/Serverless.d.ts @@ -11,6 +11,7 @@ declare namespace Serverless { service: { provider: { name: string + runtime?: string } functions: { [key: string]: Serverless.Function @@ -31,6 +32,7 @@ declare namespace Serverless { interface Function { handler: string package: Serverless.Package + runtime?: string } interface Package { diff --git a/src/index.ts b/src/index.ts index a249ce58..d55c469e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -92,6 +92,7 @@ export class TypeScriptPlugin { return typescript.extractFileNames( this.originalServicePath, this.serverless.service.provider.name, + this.serverless.service.provider.runtime, this.functions ) } diff --git a/src/typescript.ts b/src/typescript.ts index 22f7354a..a13089bc 100644 --- a/src/typescript.ts +++ b/src/typescript.ts @@ -18,7 +18,7 @@ export function makeDefaultTypescriptConfig() { return defaultTypescriptConfig } -export function extractFileNames(cwd: string, provider: string, functions?: { [key: string]: Serverless.Function }): string[] { +export function extractFileNames(cwd: string, provider: string, globalRuntime?: string, functions?: { [key: string]: Serverless.Function }): string[] { // The Google provider will use the entrypoint not from the definition of the // handler function, but instead from the package.json:main field, or via a // index.js file. This check reads the current package.json in the same way @@ -46,7 +46,13 @@ export function extractFileNames(cwd: string, provider: string, functions?: { [k } } + const runtimeIsNode = (runtime: string) => runtime.toLowerCase().startsWith('node') + const shouldProcessFunction = (fn: Serverless.Function) => + (fn.runtime !== undefined && runtimeIsNode(fn.runtime)) || + (fn.runtime === undefined && (globalRuntime === undefined || runtimeIsNode(globalRuntime))) + return _.values(functions) + .filter(shouldProcessFunction) .map(fn => fn.handler) .map(h => { const fnName = _.last(h.split('.')) diff --git a/tests/typescript.extractFileName.test.ts b/tests/typescript.extractFileName.test.ts index 82fac1d8..90046cfb 100644 --- a/tests/typescript.extractFileName.test.ts +++ b/tests/typescript.extractFileName.test.ts @@ -14,7 +14,8 @@ const functions: { [key: string]: Serverless.Function } = { package: { include: [], exclude: [] - } + }, + runtime: 'nodejs12.x' }, js: { handler: 'tests/assets/jsfile.create', @@ -23,28 +24,82 @@ const functions: { [key: string]: Serverless.Function } = { exclude: [] } }, + notActuallyTypescript: { + handler: 'tests/assets/jsfile.create', + package: { + include: [], + exclude: [] + }, + runtime: 'go1.x' + }, } describe('extractFileName', () => { - it('get function filenames from serverless service for a non-google provider', () => { - expect( - extractFileNames(process.cwd(), 'aws', functions), - ).toEqual( - [ - 'tests/assets/hello.ts', - 'tests/assets/world.ts', - 'tests/assets/jsfile.js', - ], - ) + describe('when the provider runtime is Node', () => { + it('can get function filenames from serverless service for a non-google provider', () => { + expect( + extractFileNames(process.cwd(), 'aws', 'nodejs10.x', functions), + ).toEqual( + [ + 'tests/assets/hello.ts', + 'tests/assets/world.ts', + 'tests/assets/jsfile.js', + ], + ) + }) + + it('can get function filename from serverless service for a google provider', () => { + expect( + extractFileNames(path.join(process.cwd(), 'example'), 'google', 'nodejs') + ).toEqual( + [ + 'handler.ts' + ] + ) + }) + }) + describe('when the provider runtime is not node', () => { + it('can get function filenames from serverless service for a non-google provider', () => { + expect( + extractFileNames(process.cwd(), 'aws', 'python2.7', functions), + ).toEqual( + [ + 'tests/assets/world.ts', + ], + ) + }) + + it('can get function filename from serverless service for a google provider', () => { + expect( + extractFileNames(path.join(process.cwd(), 'example'), 'google', 'python37') + ).toEqual( + [ + 'handler.ts' + ] + ) + }) }) + describe('when the provider runtime is undefined', () => { + it('can get function filenames from serverless service for a non-google provider', () => { + expect( + extractFileNames(process.cwd(), 'aws', undefined, functions), + ).toEqual( + [ + 'tests/assets/hello.ts', + 'tests/assets/world.ts', + 'tests/assets/jsfile.js', + ], + ) + }) - it('get function filename from serverless service for a google provider', () => { - expect( - extractFileNames(path.join(process.cwd(), 'example'), 'google') - ).toEqual( - [ - 'handler.ts' - ] - ) + it('can get function filename from serverless service for a google provider', () => { + expect( + extractFileNames(path.join(process.cwd(), 'example'), 'google', undefined) + ).toEqual( + [ + 'handler.ts' + ] + ) + }) }) }) From 6c15f357eed9e3090e384f2781dc21a53dfe3985 Mon Sep 17 00:00:00 2001 From: John Reeves Date: Mon, 3 Feb 2020 14:35:09 -0800 Subject: [PATCH 2/4] moved TypeScriptPlugin class into its own file. This fixes issues with the mixed types of exports so other code (tests) can import TypeScriptPlugin. --- src/index.ts | 277 +--------------------------------------- src/typeScriptPlugin.ts | 276 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 277 insertions(+), 276 deletions(-) create mode 100644 src/typeScriptPlugin.ts diff --git a/src/index.ts b/src/index.ts index a249ce58..48ae52de 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,278 +1,3 @@ -import * as path from 'path' -import * as fs from 'fs-extra' -import * as _ from 'lodash' -import * as globby from 'globby' - -import * as typescript from './typescript' -import { watchFiles } from './watchFiles' - -const SERVERLESS_FOLDER = '.serverless' -const BUILD_FOLDER = '.build' - -export class TypeScriptPlugin { - private originalServicePath: string - private isWatching: boolean - - serverless: Serverless.Instance - options: Serverless.Options - hooks: { [key: string]: Function } - - constructor(serverless: Serverless.Instance, options: Serverless.Options) { - this.serverless = serverless - this.options = options - - this.hooks = { - 'before:run:run': async () => { - await this.compileTs() - await this.copyExtras() - await this.copyDependencies() - }, - 'before:offline:start': async () => { - await this.compileTs() - await this.copyExtras() - await this.copyDependencies() - this.watchAll() - }, - 'before:offline:start:init': async () => { - await this.compileTs() - await this.copyExtras() - await this.copyDependencies() - this.watchAll() - }, - 'before:package:createDeploymentArtifacts': async () => { - await this.compileTs() - await this.copyExtras() - await this.copyDependencies(true) - }, - 'after:package:createDeploymentArtifacts': async () => { - await this.cleanup() - }, - 'before:deploy:function:packageFunction': async () => { - await this.compileTs() - await this.copyExtras() - await this.copyDependencies(true) - }, - 'after:deploy:function:packageFunction': async () => { - await this.cleanup() - }, - 'before:invoke:local:invoke': async () => { - const emitedFiles = await this.compileTs() - await this.copyExtras() - await this.copyDependencies() - if (this.isWatching) { - emitedFiles.forEach(filename => { - const module = require.resolve(path.resolve(this.originalServicePath, filename)) - delete require.cache[module] - }) - } - }, - 'after:invoke:local:invoke': () => { - if (this.options.watch) { - this.watchFunction() - this.serverless.cli.log('Waiting for changes...') - } - } - } - } - - get functions() { - const { options } = this - const { service } = this.serverless - - if (options.function) { - return { - [options.function]: service.functions[this.options.function] - } - } - - return service.functions - } - - get rootFileNames() { - return typescript.extractFileNames( - this.originalServicePath, - this.serverless.service.provider.name, - this.functions - ) - } - - prepare() { - // exclude serverless-plugin-typescript - for (const fnName in this.functions) { - const fn = this.functions[fnName] - fn.package = fn.package || { - exclude: [], - include: [], - } - - // Add plugin to excluded packages or an empty array if exclude is undefined - fn.package.exclude = _.uniq([...fn.package.exclude || [], 'node_modules/serverless-plugin-typescript']) - } - } - - async watchFunction(): Promise { - if (this.isWatching) { - return - } - - this.serverless.cli.log(`Watch function ${this.options.function}...`) - - this.isWatching = true - watchFiles(this.rootFileNames, this.originalServicePath, () => { - this.serverless.pluginManager.spawn('invoke:local') - }) - } - - async watchAll(): Promise { - if (this.isWatching) { - return - } - - this.serverless.cli.log(`Watching typescript files...`) - - this.isWatching = true - watchFiles(this.rootFileNames, this.originalServicePath, this.compileTs.bind(this)) - } - - async compileTs(): Promise { - this.prepare() - this.serverless.cli.log('Compiling with Typescript...') - - if (!this.originalServicePath) { - // Save original service path and functions - this.originalServicePath = this.serverless.config.servicePath - // Fake service path so that serverless will know what to zip - this.serverless.config.servicePath = path.join(this.originalServicePath, BUILD_FOLDER) - } - - const tsconfig = typescript.getTypescriptConfig( - this.originalServicePath, - this.isWatching ? null : this.serverless.cli - ) - - tsconfig.outDir = BUILD_FOLDER - - const emitedFiles = await typescript.run(this.rootFileNames, tsconfig) - this.serverless.cli.log('Typescript compiled.') - return emitedFiles - } - - /** Link or copy extras such as node_modules or package.include definitions */ - async copyExtras() { - const { service } = this.serverless - - // include any "extras" from the "include" section - if (service.package.include && service.package.include.length > 0) { - const files = await globby(service.package.include) - - for (const filename of files) { - const destFileName = path.resolve(path.join(BUILD_FOLDER, filename)) - const dirname = path.dirname(destFileName) - - if (!fs.existsSync(dirname)) { - fs.mkdirpSync(dirname) - } - - if (!fs.existsSync(destFileName)) { - fs.copySync(path.resolve(filename), path.resolve(path.join(BUILD_FOLDER, filename))) - } - } - } - } - - /** - * Copy the `node_modules` folder and `package.json` files to the output - * directory. - * @param isPackaging Provided if serverless is packaging the service for deployment - */ - async copyDependencies(isPackaging = false) { - const outPkgPath = path.resolve(path.join(BUILD_FOLDER, 'package.json')) - const outModulesPath = path.resolve(path.join(BUILD_FOLDER, 'node_modules')) - - // copy development dependencies during packaging - if (isPackaging) { - if (fs.existsSync(outModulesPath)) { - fs.unlinkSync(outModulesPath) - } - - fs.copySync( - path.resolve('node_modules'), - path.resolve(path.join(BUILD_FOLDER, 'node_modules')) - ) - } else { - if (!fs.existsSync(outModulesPath)) { - await this.linkOrCopy(path.resolve('node_modules'), outModulesPath, 'junction') - } - } - - // copy/link package.json - if (!fs.existsSync(outPkgPath)) { - await this.linkOrCopy(path.resolve('package.json'), outPkgPath, 'file') - } - } - - /** - * Move built code to the serverless folder, taking into account individual - * packaging preferences. - */ - async moveArtifacts(): Promise { - const { service } = this.serverless - - await fs.copy( - path.join(this.originalServicePath, BUILD_FOLDER, SERVERLESS_FOLDER), - path.join(this.originalServicePath, SERVERLESS_FOLDER) - ) - - if (this.options.function) { - const fn = service.functions[this.options.function] - fn.package.artifact = path.join( - this.originalServicePath, - SERVERLESS_FOLDER, - path.basename(fn.package.artifact) - ) - return - } - - if (service.package.individually) { - const functionNames = service.getAllFunctions() - functionNames.forEach(name => { - service.functions[name].package.artifact = path.join( - this.originalServicePath, - SERVERLESS_FOLDER, - path.basename(service.functions[name].package.artifact) - ) - }) - return - } - - service.package.artifact = path.join( - this.originalServicePath, - SERVERLESS_FOLDER, - path.basename(service.package.artifact) - ) - } - - async cleanup(): Promise { - await this.moveArtifacts() - // Restore service path - this.serverless.config.servicePath = this.originalServicePath - // Remove temp build folder - fs.removeSync(path.join(this.originalServicePath, BUILD_FOLDER)) - } - - /** - * Attempt to symlink a given path or directory and copy if it fails with an - * `EPERM` error. - */ - private async linkOrCopy(srcPath: string, dstPath: string, type?: fs.FsSymlinkType): Promise { - return fs.symlink(srcPath, dstPath, type) - .catch(error => { - if (error.code === 'EPERM' && error.errno === -4048) { - return fs.copy(srcPath, dstPath) - } - throw error - }) - } -} +import {TypeScriptPlugin} from './typeScriptPlugin' module.exports = TypeScriptPlugin diff --git a/src/typeScriptPlugin.ts b/src/typeScriptPlugin.ts new file mode 100644 index 00000000..371b80b7 --- /dev/null +++ b/src/typeScriptPlugin.ts @@ -0,0 +1,276 @@ +import * as path from 'path' +import * as fs from 'fs-extra' +import * as _ from 'lodash' +import * as globby from 'globby' + +import * as typescript from './typescript' +import { watchFiles } from './watchFiles' + +const SERVERLESS_FOLDER = '.serverless' +const BUILD_FOLDER = '.build' + +export class TypeScriptPlugin { + private originalServicePath: string + private isWatching: boolean + + serverless: Serverless.Instance + options: Serverless.Options + hooks: { [key: string]: Function } + + constructor(serverless: Serverless.Instance, options: Serverless.Options) { + this.serverless = serverless + this.options = options + + this.hooks = { + 'before:run:run': async () => { + await this.compileTs() + await this.copyExtras() + await this.copyDependencies() + }, + 'before:offline:start': async () => { + await this.compileTs() + await this.copyExtras() + await this.copyDependencies() + this.watchAll() + }, + 'before:offline:start:init': async () => { + await this.compileTs() + await this.copyExtras() + await this.copyDependencies() + this.watchAll() + }, + 'before:package:createDeploymentArtifacts': async () => { + await this.compileTs() + await this.copyExtras() + await this.copyDependencies(true) + }, + 'after:package:createDeploymentArtifacts': async () => { + await this.cleanup() + }, + 'before:deploy:function:packageFunction': async () => { + await this.compileTs() + await this.copyExtras() + await this.copyDependencies(true) + }, + 'after:deploy:function:packageFunction': async () => { + await this.cleanup() + }, + 'before:invoke:local:invoke': async () => { + const emitedFiles = await this.compileTs() + await this.copyExtras() + await this.copyDependencies() + if (this.isWatching) { + emitedFiles.forEach(filename => { + const module = require.resolve(path.resolve(this.originalServicePath, filename)) + delete require.cache[module] + }) + } + }, + 'after:invoke:local:invoke': () => { + if (this.options.watch) { + this.watchFunction() + this.serverless.cli.log('Waiting for changes...') + } + } + } + } + + get functions() { + const { options } = this + const { service } = this.serverless + + if (options.function) { + return { + [options.function]: service.functions[this.options.function] + } + } + + return service.functions + } + + get rootFileNames() { + return typescript.extractFileNames( + this.originalServicePath, + this.serverless.service.provider.name, + this.functions + ) + } + + prepare() { + // exclude serverless-plugin-typescript + for (const fnName in this.functions) { + const fn = this.functions[fnName] + fn.package = fn.package || { + exclude: [], + include: [], + } + + // Add plugin to excluded packages or an empty array if exclude is undefined + fn.package.exclude = _.uniq([...fn.package.exclude || [], 'node_modules/serverless-plugin-typescript']) + } + } + + async watchFunction(): Promise { + if (this.isWatching) { + return + } + + this.serverless.cli.log(`Watch function ${this.options.function}...`) + + this.isWatching = true + watchFiles(this.rootFileNames, this.originalServicePath, () => { + this.serverless.pluginManager.spawn('invoke:local') + }) + } + + async watchAll(): Promise { + if (this.isWatching) { + return + } + + this.serverless.cli.log(`Watching typescript files...`) + + this.isWatching = true + watchFiles(this.rootFileNames, this.originalServicePath, this.compileTs.bind(this)) + } + + async compileTs(): Promise { + this.prepare() + this.serverless.cli.log('Compiling with Typescript...') + + if (!this.originalServicePath) { + // Save original service path and functions + this.originalServicePath = this.serverless.config.servicePath + // Fake service path so that serverless will know what to zip + this.serverless.config.servicePath = path.join(this.originalServicePath, BUILD_FOLDER) + } + + const tsconfig = typescript.getTypescriptConfig( + this.originalServicePath, + this.isWatching ? null : this.serverless.cli + ) + + tsconfig.outDir = BUILD_FOLDER + + const emitedFiles = await typescript.run(this.rootFileNames, tsconfig) + this.serverless.cli.log('Typescript compiled.') + return emitedFiles + } + + /** Link or copy extras such as node_modules or package.include definitions */ + async copyExtras() { + const { service } = this.serverless + + // include any "extras" from the "include" section + if (service.package.include && service.package.include.length > 0) { + const files = await globby(service.package.include) + + for (const filename of files) { + const destFileName = path.resolve(path.join(BUILD_FOLDER, filename)) + const dirname = path.dirname(destFileName) + + if (!fs.existsSync(dirname)) { + fs.mkdirpSync(dirname) + } + + if (!fs.existsSync(destFileName)) { + fs.copySync(path.resolve(filename), path.resolve(path.join(BUILD_FOLDER, filename))) + } + } + } + } + + /** + * Copy the `node_modules` folder and `package.json` files to the output + * directory. + * @param isPackaging Provided if serverless is packaging the service for deployment + */ + async copyDependencies(isPackaging = false) { + const outPkgPath = path.resolve(path.join(BUILD_FOLDER, 'package.json')) + const outModulesPath = path.resolve(path.join(BUILD_FOLDER, 'node_modules')) + + // copy development dependencies during packaging + if (isPackaging) { + if (fs.existsSync(outModulesPath)) { + fs.unlinkSync(outModulesPath) + } + + fs.copySync( + path.resolve('node_modules'), + path.resolve(path.join(BUILD_FOLDER, 'node_modules')) + ) + } else { + if (!fs.existsSync(outModulesPath)) { + await this.linkOrCopy(path.resolve('node_modules'), outModulesPath, 'junction') + } + } + + // copy/link package.json + if (!fs.existsSync(outPkgPath)) { + await this.linkOrCopy(path.resolve('package.json'), outPkgPath, 'file') + } + } + + /** + * Move built code to the serverless folder, taking into account individual + * packaging preferences. + */ + async moveArtifacts(): Promise { + const { service } = this.serverless + + await fs.copy( + path.join(this.originalServicePath, BUILD_FOLDER, SERVERLESS_FOLDER), + path.join(this.originalServicePath, SERVERLESS_FOLDER) + ) + + if (this.options.function) { + const fn = service.functions[this.options.function] + fn.package.artifact = path.join( + this.originalServicePath, + SERVERLESS_FOLDER, + path.basename(fn.package.artifact) + ) + return + } + + if (service.package.individually) { + const functionNames = service.getAllFunctions() + functionNames.forEach(name => { + service.functions[name].package.artifact = path.join( + this.originalServicePath, + SERVERLESS_FOLDER, + path.basename(service.functions[name].package.artifact) + ) + }) + return + } + + service.package.artifact = path.join( + this.originalServicePath, + SERVERLESS_FOLDER, + path.basename(service.package.artifact) + ) + } + + async cleanup(): Promise { + await this.moveArtifacts() + // Restore service path + this.serverless.config.servicePath = this.originalServicePath + // Remove temp build folder + fs.removeSync(path.join(this.originalServicePath, BUILD_FOLDER)) + } + + /** + * Attempt to symlink a given path or directory and copy if it fails with an + * `EPERM` error. + */ + private async linkOrCopy(srcPath: string, dstPath: string, type?: fs.FsSymlinkType): Promise { + return fs.symlink(srcPath, dstPath, type) + .catch(error => { + if (error.code === 'EPERM' && error.errno === -4048) { + return fs.copy(srcPath, dstPath) + } + throw error + }) + } +} From 6cd5e459e2fda97eaf412693daa1ac5c647afb48 Mon Sep 17 00:00:00 2001 From: John Reeves Date: Mon, 3 Feb 2020 14:24:31 -0800 Subject: [PATCH 3/4] Skip functions that do not use node runtime. Allows mixed runtime projects. --- src/Serverless.d.ts | 2 + src/typeScriptPlugin.ts | 18 +++++++- tests/TypeScriptPlugin.test.ts | 58 ++++++++++++++++++++++++ tests/typescript.extractFileName.test.ts | 3 ++ 4 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 tests/TypeScriptPlugin.test.ts diff --git a/src/Serverless.d.ts b/src/Serverless.d.ts index ec7d7049..d2e83e1c 100644 --- a/src/Serverless.d.ts +++ b/src/Serverless.d.ts @@ -11,6 +11,7 @@ declare namespace Serverless { service: { provider: { name: string + runtime: string } functions: { [key: string]: Serverless.Function @@ -30,6 +31,7 @@ declare namespace Serverless { interface Function { handler: string + runtime: string package: Serverless.Package } diff --git a/src/typeScriptPlugin.ts b/src/typeScriptPlugin.ts index 371b80b7..ec347271 100644 --- a/src/typeScriptPlugin.ts +++ b/src/typeScriptPlugin.ts @@ -92,10 +92,24 @@ export class TypeScriptPlugin { return typescript.extractFileNames( this.originalServicePath, this.serverless.service.provider.name, - this.functions + this.nodeFunctions ) } + get nodeFunctions() { + const { service } = this.serverless + const functions = this.functions + + // filter out functions that have a non-node runtime because they can't even typescript + return Object.keys(this.functions) + .map(fn => ({fn, runtime: functions[fn].runtime || service.provider.runtime})) + .filter(fnObj => fnObj.runtime.match(/nodejs/)) + .reduce((prev, cur) => ({ + ...prev, + [cur.fn]: service.functions[cur.fn] + }), {} as {[key: string]: Serverless.Function}) + } + prepare() { // exclude serverless-plugin-typescript for (const fnName in this.functions) { @@ -234,7 +248,7 @@ export class TypeScriptPlugin { } if (service.package.individually) { - const functionNames = service.getAllFunctions() + const functionNames = Object.keys(this.nodeFunctions) functionNames.forEach(name => { service.functions[name].package.artifact = path.join( this.originalServicePath, diff --git a/tests/TypeScriptPlugin.test.ts b/tests/TypeScriptPlugin.test.ts new file mode 100644 index 00000000..7489c028 --- /dev/null +++ b/tests/TypeScriptPlugin.test.ts @@ -0,0 +1,58 @@ +import {TypeScriptPlugin} from '../src/typeScriptPlugin' + +describe('TypeScriptPlugin', () => { + it('rootFileNames includes only node runtimes', () => { + const slsInstance: Serverless.Instance = { + cli: { + log: jest.fn() + }, + config: { + servicePath: 'servicePath' + }, + service: { + provider: { + name: 'aws', + runtime: 'nodejs99' + }, + package: { + individually: true, + include: [], + exclude: [] + }, + functions: { + func1: { + handler: 'java-fn', + runtime: 'java8', + package: { + include: [], + exclude: [] + } + }, + func2: { + handler: 'node-fn', + runtime: 'nodejs99', + package: { + include: [], + exclude: [] + } + } + }, + + getAllFunctions: jest.fn() + }, + pluginManager: { + spawn: jest.fn() + } + } + + const plugin = new TypeScriptPlugin(slsInstance, {}) + + expect( + Object.keys(plugin.nodeFunctions) + ).toEqual( + [ + 'func2' + ], + ) + }) +}) diff --git a/tests/typescript.extractFileName.test.ts b/tests/typescript.extractFileName.test.ts index 82fac1d8..ad3446fc 100644 --- a/tests/typescript.extractFileName.test.ts +++ b/tests/typescript.extractFileName.test.ts @@ -4,6 +4,7 @@ import * as path from 'path' const functions: { [key: string]: Serverless.Function } = { hello: { handler: 'tests/assets/hello.handler', + runtime: 'nodejs10.1', package: { include: [], exclude: [] @@ -11,6 +12,7 @@ const functions: { [key: string]: Serverless.Function } = { }, world: { handler: 'tests/assets/world.handler', + runtime: 'nodejs10.1', package: { include: [], exclude: [] @@ -18,6 +20,7 @@ const functions: { [key: string]: Serverless.Function } = { }, js: { handler: 'tests/assets/jsfile.create', + runtime: 'nodejs10.1', package: { include: [], exclude: [] From 405b39f2398fb1bc4da7b98e4fb88eb53fdf80fd Mon Sep 17 00:00:00 2001 From: Sean Dawson Date: Sun, 9 Feb 2020 19:36:11 +1100 Subject: [PATCH 4/4] fix: use correct ES6 module syntax - Turns out `export default` is not the same as `modules.export = xyz` - The actual equivilant is `export = xyz` with `esModuleInterop` enabled - This is a better form than `modules.export = xyz` because we are able to use the type system - See: https://stackoverflow.com/questions/40294870/module-exports-vs-export-default-in-node-js-and-es6 and https://www.typescriptlang.org/docs/handbook/migrating-from-javascript.html#weeding-out-errors --- src/index.ts | 6 +++--- tsconfig.json | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/index.ts b/src/index.ts index 649d6cc4..baa655e5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,7 +1,7 @@ import * as path from 'path' import * as fs from 'fs-extra' import * as _ from 'lodash' -import * as globby from 'globby' +import globby from 'globby' import * as typescript from './typescript' import { watchFiles } from './watchFiles' @@ -9,7 +9,7 @@ import { watchFiles } from './watchFiles' const SERVERLESS_FOLDER = '.serverless' const BUILD_FOLDER = '.build' -export class TypeScriptPlugin { +class TypeScriptPlugin { private originalServicePath: string private isWatching: boolean @@ -278,4 +278,4 @@ export class TypeScriptPlugin { } } -export default TypeScriptPlugin \ No newline at end of file +export = TypeScriptPlugin \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 4eb97c5d..b4bb3452 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,7 +4,8 @@ "rootDir": ".", "target": "es6", "sourceMap": true, - "outDir": "dist" + "outDir": "dist", + "esModuleInterop": true }, "exclude": [ "node_modules"