From 8619d4ede0c00e94d73499f774a8c357a19af997 Mon Sep 17 00:00:00 2001 From: Calle Kabo Date: Sat, 10 Apr 2021 11:36:38 +1200 Subject: [PATCH 1/6] fix: #110 package.patterns --- README.md | 2 +- package.json | 2 +- src/index.ts | 38 +++++++++++++++++++++++++++++--------- src/pack.ts | 9 +++++++-- 4 files changed, 38 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index a3c8d223..230cd6d1 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ See [example folder](example) for a minimal example. ### Including extra files -All files from `package/include` will be included in the final build file. See [Exclude/Include](https://serverless.com/framework/docs/providers/aws/guide/packaging#exclude--include) +All files from `package/patterns` will be included in the final build file. See [Patterns](https://serverless.com/framework/docs/providers/aws/guide/packaging#patterns) ### External Dependencies diff --git a/package.json b/package.json index bd9eb330..7c524b23 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "@types/jest": "^26.0.14", "@types/node": "^12.12.38", "@types/ramda": "^0.27.6", - "@types/serverless": "^1.78.18", + "@types/serverless": "^1.78.25", "@typescript-eslint/eslint-plugin": "^4.2.0", "@typescript-eslint/parser": "^4.2.0", "eslint": "^7.9.0", diff --git a/src/index.ts b/src/index.ts index cc61cd1d..4cfc708b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -172,13 +172,12 @@ export class EsbuildPlugin implements Plugin { for (const fnName in this.functions) { const fn = this.serverless.service.getFunction(fnName); fn.package = fn.package || { - exclude: [], - include: [], + patterns: [], }; // Add plugin to excluded packages or an empty array if exclude is undefined - fn.package.exclude = [ - ...new Set([...(fn.package.exclude || []), 'node_modules/serverless-esbuild']), + fn.package.patterns = [ + ...new Set([ ...(fn.package.patterns || []), '!node_modules/serverless-esbuild' ]), ]; } } @@ -216,13 +215,13 @@ export class EsbuildPlugin implements Plugin { }); } - /** Link or copy extras such as node_modules or package.include definitions */ + /** Link or copy extras such as node_modules or package.patterns 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); + // include any "extras" from the "patterns" section + if (service.package.patterns && service.package.patterns.length > 0) { + const files = await globby(service.package.patterns); for (const filename of files) { const destFileName = path.resolve(path.join(this.buildDirPath, filename)); @@ -233,7 +232,28 @@ export class EsbuildPlugin implements Plugin { } if (!fs.existsSync(destFileName)) { - fs.copySync(path.resolve(filename), path.resolve(path.join(this.buildDirPath, filename))); + fs.copySync(path.resolve(filename), destFileName); + } + } + } + + // include any "extras" from the individual function "patterns" section + for (const fnName in this.functions) { + const fn = this.serverless.service.getFunction(fnName); + if (!fn.package?.patterns?.length) { + continue; + } + const files = await globby(fn.package.patterns); + for (const filename of files) { + const destFileName = path.resolve(path.join(this.buildDirPath, `__only_${fn.name}`, filename)); + const dirname = path.dirname(destFileName); + + if (!fs.existsSync(dirname)) { + fs.mkdirpSync(dirname); + } + + if (!fs.existsSync(destFileName)) { + fs.copySync(path.resolve(filename), destFileName); } } } diff --git a/src/pack.ts b/src/pack.ts index 6ba764c4..4dca3ddf 100644 --- a/src/pack.ts +++ b/src/pack.ts @@ -107,10 +107,13 @@ export async function pack(this: EsbuildPlugin) { const artifactPath = path.join(this.workDirPath, SERVERLESS_FOLDER, zipName); // filter files - const filesPathList = files.filter(({ rootPath, localPath }) => { + const filesPathList = files.filter(({ localPath }) => { // exclude non individual files based on file path (and things that look derived, e.g. foo.js => foo.js.map) if (excludedFiles.find(p => localPath.startsWith(p))) return false; + // exclude files that belong to individual functions + if (localPath.startsWith('__only_') && !localPath.startsWith(`__only_${name}/`)) return false; + // exclude non whitelisted dependencies if (localPath.startsWith('node_modules')) { // if no externals is set or if the provider is google, we do not need any files from node_modules @@ -123,7 +126,9 @@ export async function pack(this: EsbuildPlugin) { } return true; - }); + }) + // remove prefix from individual function extra files + .map(({localPath, ...rest}) => ({ localPath: localPath.replace(`__only_${name}/`, ''), ...rest})); const startZip = Date.now(); await zip(artifactPath, filesPathList); From 9403b93106a2e0228caaf8f936408756bd1d5667 Mon Sep 17 00:00:00 2001 From: Calle Kabo Date: Sat, 10 Apr 2021 20:16:37 +1200 Subject: [PATCH 2/6] fix: re-add support for include/export --- src/index.ts | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/index.ts b/src/index.ts index 4cfc708b..6670300a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,7 +2,7 @@ import { build, BuildResult, BuildOptions } from 'esbuild'; import * as fs from 'fs-extra'; import * as globby from 'globby'; import * as path from 'path'; -import { mergeRight } from 'ramda'; +import { concat, mergeRight } from 'ramda'; import * as Serverless from 'serverless'; import * as Plugin from 'serverless/classes/Plugin'; import * as chokidar from 'chokidar'; @@ -173,11 +173,12 @@ export class EsbuildPlugin implements Plugin { const fn = this.serverless.service.getFunction(fnName); fn.package = fn.package || { patterns: [], + exclude: [], }; // Add plugin to excluded packages or an empty array if exclude is undefined fn.package.patterns = [ - ...new Set([ ...(fn.package.patterns || []), '!node_modules/serverless-esbuild' ]), + ...new Set([ ...(fn.package.exclude || []).map(concat('!')), ...(fn.package.patterns || []), '!node_modules/serverless-esbuild' ]), ]; } } @@ -220,8 +221,11 @@ export class EsbuildPlugin implements Plugin { const { service } = this.serverless; // include any "extras" from the "patterns" section - if (service.package.patterns && service.package.patterns.length > 0) { - const files = await globby(service.package.patterns); + const globalPatterns = [ + ...new Set([ ...(service.package.include || []), ...(service.package.patterns || []) ]), + ]; + if (globalPatterns.length > 0) { + const files = await globby(globalPatterns); for (const filename of files) { const destFileName = path.resolve(path.join(this.buildDirPath, filename)); @@ -240,10 +244,13 @@ export class EsbuildPlugin implements Plugin { // include any "extras" from the individual function "patterns" section for (const fnName in this.functions) { const fn = this.serverless.service.getFunction(fnName); - if (!fn.package?.patterns?.length) { + const fnPatterns = [ + ...new Set([ ...(fn.package.include || []), ...(fn.package.patterns || []) ]), + ]; + if (fnPatterns.length === 0) { continue; } - const files = await globby(fn.package.patterns); + const files = await globby(fnPatterns); for (const filename of files) { const destFileName = path.resolve(path.join(this.buildDirPath, `__only_${fn.name}`, filename)); const dirname = path.dirname(destFileName); From 855db0cccb9651cf78e86e8281b5338c81d30aa4 Mon Sep 17 00:00:00 2001 From: Calle Kabo Date: Sun, 11 Apr 2021 15:12:03 +1200 Subject: [PATCH 3/6] fix: include individual extra files when not using individual packaging --- src/pack.ts | 13 ++++++++++--- src/types.ts | 6 ++++++ src/utils.ts | 3 ++- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/pack.ts b/src/pack.ts index 4dca3ddf..8f6648ac 100644 --- a/src/pack.ts +++ b/src/pack.ts @@ -1,11 +1,12 @@ import * as fs from 'fs-extra'; import * as glob from 'glob'; import * as path from 'path'; -import { intersection, isEmpty, path as get, without } from 'ramda'; +import { intersection, isEmpty, lensProp, map, over, path as get, pipe, reject, replace, test, without } from 'ramda'; import * as semver from 'semver'; import { EsbuildPlugin, SERVERLESS_FOLDER } from '.'; import { doSharePath, flatDep, getDepsFromBundle } from './helper'; import * as Packagers from './packagers'; +import { IFiles } from './types'; import { humanSize, zip } from './utils'; function setFunctionArtifactPath(this: EsbuildPlugin, func, artifactPath) { @@ -38,7 +39,7 @@ export async function pack(this: EsbuildPlugin) { ); // get a list of all path in build - const files: { localPath: string; rootPath: string }[] = glob + const files: IFiles = glob .sync('**', { cwd: this.buildDirPath, dot: true, @@ -57,8 +58,14 @@ export async function pack(this: EsbuildPlugin) { const zipName = `${this.serverless.service.service}.zip`; const artifactPath = path.join(this.workDirPath, SERVERLESS_FOLDER, zipName); + // remove prefixes from individual extra files + const filesPathList = pipe( + reject(test(/^__only_[^/]+$/)) as (x: IFiles) => IFiles, + map(over(lensProp('localPath'), replace(/^__only_[^/]+\//, ''))) + )(files); + const startZip = Date.now(); - await zip(artifactPath, files); + await zip(artifactPath, filesPathList); const { size } = fs.statSync(artifactPath); this.serverless.cli.log( diff --git a/src/types.ts b/src/types.ts index f550abad..042159c5 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,2 +1,8 @@ // eslint-disable-next-line @typescript-eslint/no-explicit-any export type JSONObject = any; + +export interface IFile { + readonly localPath: string + readonly rootPath: string +} +export type IFiles = readonly IFile[]; diff --git a/src/utils.ts b/src/utils.ts index 4f7de55b..96f8c8fb 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -3,6 +3,7 @@ import * as childProcess from 'child_process'; import * as fs from 'fs-extra'; import * as path from 'path'; import { join } from 'ramda'; +import { IFiles } from './types'; export class SpawnError extends Error { constructor(message: string, public stdout: string, public stderr: string) { @@ -91,7 +92,7 @@ export const humanSize = (size: number) => { return `${sanitized} ${['B', 'KB', 'MB', 'GB', 'TB'][i]}`; }; -export const zip = (zipPath: string, filesPathList: { rootPath: string; localPath: string }[]) => { +export const zip = (zipPath: string, filesPathList: IFiles) => { fs.mkdirpSync(path.dirname(zipPath)); const zip = archiver.create('zip'); From 6303ad82f90c9131d59059b324f6364bae6abed7 Mon Sep 17 00:00:00 2001 From: Calle Kabo Date: Sun, 11 Apr 2021 16:10:45 +1200 Subject: [PATCH 4/6] fix: remove duplicated code --- src/index.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/index.ts b/src/index.ts index 6670300a..55b1155e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -173,7 +173,6 @@ export class EsbuildPlugin implements Plugin { const fn = this.serverless.service.getFunction(fnName); fn.package = fn.package || { patterns: [], - exclude: [], }; // Add plugin to excluded packages or an empty array if exclude is undefined @@ -244,13 +243,10 @@ export class EsbuildPlugin implements Plugin { // include any "extras" from the individual function "patterns" section for (const fnName in this.functions) { const fn = this.serverless.service.getFunction(fnName); - const fnPatterns = [ - ...new Set([ ...(fn.package.include || []), ...(fn.package.patterns || []) ]), - ]; - if (fnPatterns.length === 0) { + if (fn.package.patterns.length === 0) { continue; } - const files = await globby(fnPatterns); + const files = await globby(fn.package.patterns); for (const filename of files) { const destFileName = path.resolve(path.join(this.buildDirPath, `__only_${fn.name}`, filename)); const dirname = path.dirname(destFileName); From ece100c1d2bdd98ba12f1b312bb84c44c798bc36 Mon Sep 17 00:00:00 2001 From: Calle Kabo Date: Mon, 12 Apr 2021 08:56:44 +1200 Subject: [PATCH 5/6] fix: consistent way of setting patterns --- src/index.ts | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/src/index.ts b/src/index.ts index 55b1155e..d734bd19 100644 --- a/src/index.ts +++ b/src/index.ts @@ -169,16 +169,30 @@ export class EsbuildPlugin implements Plugin { fs.mkdirpSync(this.buildDirPath); fs.mkdirpSync(path.join(this.workDirPath, SERVERLESS_FOLDER)); // exclude serverless-esbuild + this.serverless.service.package = { + ...(this.serverless.service.package || {}), + patterns: [ + ...new Set([ + ...(this.serverless.service.package?.include || []), + ...(this.serverless.service.package?.exclude || []).map(concat('!')), + ...(this.serverless.service.package?.patterns || []), + '!node_modules/serverless-esbuild', + ]), + ] + }; + for (const fnName in this.functions) { const fn = this.serverless.service.getFunction(fnName); - fn.package = fn.package || { - patterns: [], + fn.package = { + ...(fn.package || {}), + patterns: [ + ...new Set([ + ...(fn.package?.include || []), + ...(fn.package?.exclude || []).map(concat('!')), + ...(fn.package?.patterns || []), + ]), + ] }; - - // Add plugin to excluded packages or an empty array if exclude is undefined - fn.package.patterns = [ - ...new Set([ ...(fn.package.exclude || []).map(concat('!')), ...(fn.package.patterns || []), '!node_modules/serverless-esbuild' ]), - ]; } } @@ -220,11 +234,8 @@ export class EsbuildPlugin implements Plugin { const { service } = this.serverless; // include any "extras" from the "patterns" section - const globalPatterns = [ - ...new Set([ ...(service.package.include || []), ...(service.package.patterns || []) ]), - ]; - if (globalPatterns.length > 0) { - const files = await globby(globalPatterns); + if (service.package.patterns.length > 0) { + const files = await globby(service.package.patterns); for (const filename of files) { const destFileName = path.resolve(path.join(this.buildDirPath, filename)); From 7cbbf1f98dab1fa200022580420e9b8417df75c4 Mon Sep 17 00:00:00 2001 From: Calle Kabo Date: Tue, 13 Apr 2021 08:12:53 +1200 Subject: [PATCH 6/6] fix: mention include/exclude --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 230cd6d1..a4d1dd16 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,9 @@ See [example folder](example) for a minimal example. ### Including extra files -All files from `package/patterns` will be included in the final build file. See [Patterns](https://serverless.com/framework/docs/providers/aws/guide/packaging#patterns) +All files from `package/patterns` will be included in the final build file. See [Patterns](https://serverless.com/framework/docs/providers/aws/guide/packaging#patterns). + +Include/exclude is deprecated, but still supported. ### External Dependencies