UNPKG

serverless-plugin-typescript

Version:

[![serverless](http://public.serverless.com/badges/v3.svg)](http://www.serverless.com) [![npm version](https://badge.fury.io/js/serverless-plugin-typescript.svg)](https://badge.fury.io/js/serverless-plugin-typescript) [![Build Status](https://travis-ci.or

274 lines 12.6 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.TypeScriptPlugin = void 0; const path = require("path"); const fs = require("fs-extra"); const _ = require("lodash"); const globby = require("globby"); const typescript = require("./typescript"); const watchFiles_1 = require("./watchFiles"); const SERVERLESS_FOLDER = '.serverless'; const BUILD_FOLDER = '.build'; class TypeScriptPlugin { constructor(serverless, options) { this.serverless = serverless; this.options = options; this.commands = { invoke: { commands: { local: { options: { watch: { type: 'boolean', usage: 'Watch file changes and re-invoke automatically the function' } } } } } }; this.hooks = { 'before:run:run': () => __awaiter(this, void 0, void 0, function* () { yield this.compileTs(); yield this.copyExtras(); yield this.copyDependencies(); }), 'before:offline:start': () => __awaiter(this, void 0, void 0, function* () { yield this.compileTs(); yield this.copyExtras(); yield this.copyDependencies(); this.watchAll(); }), 'before:offline:start:init': () => __awaiter(this, void 0, void 0, function* () { yield this.compileTs(); yield this.copyExtras(); yield this.copyDependencies(); this.watchAll(); }), 'before:package:createDeploymentArtifacts': () => __awaiter(this, void 0, void 0, function* () { yield this.compileTs(); yield this.copyExtras(); yield this.copyDependencies(true); }), 'after:package:createDeploymentArtifacts': () => __awaiter(this, void 0, void 0, function* () { yield this.cleanup(); }), 'before:deploy:function:packageFunction': () => __awaiter(this, void 0, void 0, function* () { yield this.compileTs(); yield this.copyExtras(); yield this.copyDependencies(true); }), 'after:deploy:function:packageFunction': () => __awaiter(this, void 0, void 0, function* () { yield this.cleanup(); }), 'before:invoke:local:invoke': () => __awaiter(this, void 0, void 0, function* () { const emitedFiles = yield this.compileTs(); yield this.copyExtras(); yield 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': () => __awaiter(this, void 0, void 0, function* () { if (this.options.watch) { yield this.watchFunction(); } }) }; } get functions() { const { options } = this; const { service } = this.serverless; const functions = service.functions || {}; const nodeFunctions = {}; for (const [name, functionObject] of Object.entries(functions)) { const runtime = functions[name].runtime || service.provider.runtime; if (runtime.includes('nodejs')) { nodeFunctions[name] = functionObject; } } if (options.function && nodeFunctions[options.function]) { return { [options.function]: nodeFunctions[options.function] }; } return nodeFunctions; } get rootFileNames() { return _.union(typescript.extractFileNames(this.originalServicePath, this.serverless.service.provider.name, this.functions), typescript.getTypescriptCompileFiles(this.originalServicePath)); } prepare() { // exclude serverless-plugin-typescript for (const fnName in this.functions) { const fn = this.functions[fnName]; fn.package = fn.package || { exclude: [], include: [], patterns: [] }; // 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']); } } watchFunction() { return __awaiter(this, void 0, void 0, function* () { if (this.isWatching) { return; } this.serverless.cli.log(`Watch function ${this.options.function}...`); this.serverless.cli.log('Waiting for changes...'); this.isWatching = true; yield new Promise((resolve, reject) => { (0, watchFiles_1.watchFiles)(this.rootFileNames, this.originalServicePath, () => { this.serverless.pluginManager.spawn('invoke:local').catch(reject); }); }); }); } watchAll() { return __awaiter(this, void 0, void 0, function* () { if (this.isWatching) { return; } this.serverless.cli.log(`Watching typescript files...`); this.isWatching = true; (0, watchFiles_1.watchFiles)(this.rootFileNames, this.originalServicePath, this.compileTs.bind(this)); }); } compileTs() { return __awaiter(this, void 0, void 0, function* () { 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); } let tsConfigFileLocation; if (this.serverless.service.custom !== undefined && this.serverless.service.custom.serverlessPluginTypescript !== undefined) { tsConfigFileLocation = this.serverless.service.custom.serverlessPluginTypescript.tsConfigFileLocation; } const tsconfig = typescript.getTypescriptConfig(this.originalServicePath, tsConfigFileLocation, this.isWatching ? null : this.serverless.cli); tsconfig.outDir = BUILD_FOLDER; const emitedFiles = yield typescript.run(this.rootFileNames, tsconfig); this.serverless.cli.log('Typescript compiled.'); return emitedFiles; }); } /** Link or copy extras such as node_modules or package.patterns definitions */ copyExtras() { return __awaiter(this, void 0, void 0, function* () { const { service } = this.serverless; const patterns = [...(service.package.include || []), ...(service.package.patterns || [])]; // include any "extras" from the "include" section if (patterns.length > 0) { const files = yield globby(patterns); 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 */ copyDependencies(isPackaging = false) { return __awaiter(this, void 0, void 0, function* () { 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.removeSync(outModulesPath); } fs.copySync(path.resolve('node_modules'), path.resolve(path.join(BUILD_FOLDER, 'node_modules'))); } else { if (!fs.existsSync(outModulesPath)) { yield this.linkOrCopy(path.resolve('node_modules'), outModulesPath, 'junction'); } } // copy/link package.json if (!fs.existsSync(outPkgPath)) { yield this.linkOrCopy(path.resolve('package.json'), outPkgPath, 'file'); } }); } /** * Move built code to the serverless folder, taking into account individual * packaging preferences. */ moveArtifacts() { return __awaiter(this, void 0, void 0, function* () { const { service } = this.serverless; yield fs.copy(path.join(this.originalServicePath, BUILD_FOLDER, SERVERLESS_FOLDER), path.join(this.originalServicePath, SERVERLESS_FOLDER)); const layerNames = service.getAllLayers(); layerNames.forEach(name => { service.layers[name].package.artifact = path.join(this.originalServicePath, SERVERLESS_FOLDER, path.basename(service.layers[name].package.artifact)); }); 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)); }); } cleanup() { return __awaiter(this, void 0, void 0, function* () { yield 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. */ linkOrCopy(srcPath, dstPath, type) { return __awaiter(this, void 0, void 0, function* () { return fs.symlink(srcPath, dstPath, type) .catch(error => { if (error.code === 'EPERM' && error.errno === -4048) { return fs.copy(srcPath, dstPath); } throw error; }); }); } } exports.TypeScriptPlugin = TypeScriptPlugin; module.exports = TypeScriptPlugin; //# sourceMappingURL=index.js.map