diff --git a/README.md b/README.md index d2d606cd..0919a6a9 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,27 @@ All files from `package/include` will be included in the final build file. See [ ## Usage +### Google Cloud Functions + +When using with Google Cloud Functions via the [serverless-google-cloudfunctions](https://github.com/serverless/serverless-google-cloudfunctions) +plugin, you simply have to provide a `main` field in your `package.json`: + +```js +{ + // ... + "main": "handler.js", + // .. +} +``` + +And this plugin will automatically compile your typescript correctly. Note +that the field must refer to the compiled file name, namely, ending with a `.js` +extension. + +If a `main` field was not found, then this plugin will use `index.js`. Before +compilation begins, it will check to see that the file indicated exists with a +`.ts` extension before actually trying to compile it. + ### Automatic compilation The normal Serverless deploy procedure will automatically compile with Typescript: diff --git a/example/package.json b/example/package.json index 233f6498..e2b840dd 100644 --- a/example/package.json +++ b/example/package.json @@ -1,4 +1,5 @@ { + "main": "handler.js", "dependencies": { "lodash": "^4.17.4" }, diff --git a/src/index.ts b/src/index.ts index a25087ab..6c48d059 100644 --- a/src/index.ts +++ b/src/index.ts @@ -65,7 +65,7 @@ export class ServerlessPlugin { } get rootFileNames() { - return typescript.extractFileNames(this.functions) + return typescript.extractFileNames(this.originalServicePath, this.serverless.service.provider.name, this.functions) } prepare() { @@ -118,7 +118,6 @@ export class ServerlessPlugin { this.serverless.config.servicePath = path.join(this.originalServicePath, buildFolder) } - const tsFileNames = typescript.extractFileNames(this.functions) const tsconfig = typescript.getTypescriptConfig( this.originalServicePath, this.isWatching ? null : this.serverless.cli @@ -126,7 +125,7 @@ export class ServerlessPlugin { tsconfig.outDir = buildFolder - const emitedFiles = await typescript.run(tsFileNames, tsconfig) + const emitedFiles = await typescript.run(this.rootFileNames, tsconfig) await this.copyExtras() return emitedFiles } diff --git a/src/types.ts b/src/types.ts index 30b930ac..4ad23338 100644 --- a/src/types.ts +++ b/src/types.ts @@ -6,6 +6,9 @@ export interface ServerlessInstance { servicePath: string } service: { + provider: { + name: string + } functions: { [key: string]: ServerlessFunction } package: ServerlessPackage getAllFunctions: () => string[] diff --git a/src/typescript.ts b/src/typescript.ts index 6b92ba28..7ead910a 100644 --- a/src/typescript.ts +++ b/src/typescript.ts @@ -18,7 +18,35 @@ export function makeDefaultTypescriptConfig() { return defaultTypescriptConfig } -export function extractFileNames(functions: { [key: string]: ServerlessFunction }): string[] { +export function extractFileNames(cwd: string, provider: string, functions?: { [key: string]: ServerlessFunction }): 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 + // that we already read the tsconfig.json file, by inspecting the current + // working directory. If the packageFile does not contain a valid main, then + // it instead selects the index.js file. + if (provider === 'google') { + const packageFilePath = path.join(cwd, 'package.json') + if (fs.existsSync(packageFilePath)) { + + // Load in the package.json file. + const packageFile = JSON.parse(fs.readFileSync(packageFilePath).toString()) + + // Either grab the package.json:main field, or use the index.ts file. + // (This will be transpiled to index.js). + const main = packageFile.main ? packageFile.main.replace(/\.js$/, '.ts') : 'index.ts' + + // Check that the file indeed exists. + if (!fs.existsSync(path.join(cwd, main))) { + console.log(`Cannot locate entrypoint, ${main} not found`) + throw new Error('Typescript compilation failed') + } + + return [main] + } + } + return _.values(functions) .map(fn => fn.handler) .map(h => { diff --git a/tests/typescript.extractFileName.test.ts b/tests/typescript.extractFileName.test.ts index 986587c1..13ca2339 100644 --- a/tests/typescript.extractFileName.test.ts +++ b/tests/typescript.extractFileName.test.ts @@ -1,5 +1,6 @@ import {extractFileNames} from '../src/typescript' import {ServerlessFunction} from '../src/types' +import * as path from 'path' const functions: { [key: string]: ServerlessFunction } = { hello: { @@ -26,9 +27,9 @@ const functions: { [key: string]: ServerlessFunction } = { } describe('extractFileName', () => { - it('get function filenames from serverless service', () => { + it('get function filenames from serverless service for a non-google provider', () => { expect( - extractFileNames(functions), + extractFileNames(process.cwd(), 'aws', functions), ).toEqual( [ 'my-folder/hello.ts', @@ -37,5 +38,14 @@ describe('extractFileName', () => { ], ) }) -}) + it('get function filename from serverless service for a google provider', () => { + expect( + extractFileNames(path.join(process.cwd(), 'example'), 'google') + ).toEqual( + [ + 'handler.ts' + ] + ) + }) +})