diff --git a/.gitignore b/.gitignore index 59a95f3..ec22e12 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,4 @@ node_modules .idea dist/ .serverless/ - +.esbuild-visualizer diff --git a/cdk/lib/lambda-stack.ts b/cdk/lib/lambda-stack.ts index 3a5c211..8ceff70 100644 --- a/cdk/lib/lambda-stack.ts +++ b/cdk/lib/lambda-stack.ts @@ -18,7 +18,10 @@ export class LambdaStack extends cdk.Stack { ) ), runtime: lambda.Runtime.NODEJS_18_X, - functionName: 'users-cdk-boilerplate' + functionName: 'users-cdk-boilerplate', + environment: { + NODE_OPTIONS: '--enable-source-maps', + } }); const productsLambda = new lambda.Function(this, 'products-lambda', { @@ -32,7 +35,10 @@ export class LambdaStack extends cdk.Stack { ) ), runtime: lambda.Runtime.NODEJS_18_X, - functionName: 'products-cdk-boilerplate' + functionName: 'products-cdk-boilerplate', + environment: { + NODE_OPTIONS: '--enable-source-maps', + } }); } } diff --git a/cdk/package.json b/cdk/package.json index 5a5f8f7..d9a4d21 100644 --- a/cdk/package.json +++ b/cdk/package.json @@ -9,6 +9,7 @@ "watch": "tsc -w", "test": "jest", "cdk": "cdk", + "diff": "cdk diff", "deploy": "cdk deploy" }, "devDependencies": { diff --git a/esbuild.ts b/esbuild.ts index 1afc4d3..aec3882 100644 --- a/esbuild.ts +++ b/esbuild.ts @@ -1,6 +1,8 @@ import * as fs from 'fs'; import * as path from 'path'; -import {build} from 'esbuild'; +import {build, Plugin} from 'esbuild'; +import {visualizer, TemplateType} from "esbuild-visualizer"; +import * as open from "open"; const functionsDir = 'src'; const outDir = 'dist'; @@ -9,16 +11,90 @@ const entryPoints = fs .filter(entry => entry !== 'common') .map(entry => `${functionsDir}/${entry}/handler.ts`); -build({ - entryPoints, - bundle: true, - outdir: path.join(__dirname, outDir), - outbase: functionsDir, - platform: 'node', - sourcemap: 'external', - write: true, - tsconfig: './tsconfig.json', - minify: true, - keepNames: false, + +export type EsbuildFunctionBundlerOptions = { + /** + * Defaults to cdk.out/esbuild-visualizer + */ + outputDir?: string, + + /** + * Defaults to "treemap" + */ + template?: TemplateType, + + /** + * Open the HTML file after bundling + */ + open?: boolean +} + +function esBuildPluginShrinkSourceMap(): Plugin +{ + //https://github.com/evanw/esbuild/issues/1685#issuecomment-944916409 + return { + name: 'excludeVendorFromSourceMap', + setup(build) { + build.onLoad({ filter: /node_modules/ }, args => { + if (args.path.endsWith('.js') && !args.path.endsWith('.json')) + return { + contents: fs.readFileSync(args.path, 'utf8') + + '\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIiJdLCJtYXBwaW5ncyI6IkEifQ==', + loader: 'default', + } + else + return + }) + }, + } +} + +(async () => { + for (const entryPoint of entryPoints) + { + const resp = await build({ + entryPoints: [entryPoint], + bundle: true, + outdir: path.join(__dirname, outDir), + outbase: functionsDir, + platform: 'node', + sourcemap: 'external', + write: true, + tsconfig: './tsconfig.json', + minify: true, + keepNames: false, + plugins: [ + esBuildPluginShrinkSourceMap(), + ], + metafile: true, + }); + + const bundlerDefaults: EsbuildFunctionBundlerOptions = { + outputDir: ".esbuild-visualizer", + template: "treemap" + }; + + /* Analyze Bundle */ + // fs.writeFileSync('meta.json', JSON.stringify(result.metafile)); + // let text = await esbuild.analyzeMetafile(result.metafile, {verbose: true, color: true}); + // console.log(text); + const htmlContent = await visualizer(resp.metafile, { + title: entryPoint, + template: bundlerDefaults.template!, + }); + + + const outputFile = path.join(__dirname, bundlerDefaults.outputDir!, entryPoint + ".html") + const outputDir = path.dirname(outputFile) + if(!fs.existsSync(outputDir)) + fs.mkdirSync(outputDir, {recursive: true}); + + fs.writeFileSync(outputFile, htmlContent, {}); + + await open(outputFile); + } +})().catch(e => { + console.error(e); // eslint-disable-next-line no-process-exit -}).catch(() => process.exit(1)); + process.exit(1); +}); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 7a2e921..2ae05c8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,12 +10,14 @@ "license": "ISC", "dependencies": { "aws-lambda": "^1.0.7", - "lambda-log": "^3.1.0" + "lambda-log": "^3.1.0", + "open": "^8.4.2" }, "devDependencies": { "@types/aws-lambda": "^8.10.125", "@types/lambda-log": "^3.0.2", "esbuild": "^0.19.5", + "esbuild-visualizer": "^0.4.1", "serverless": "^3.36.0", "serverless-better-credentials": "^2.0.0", "ts-node": "^10.9.1", @@ -2818,6 +2820,37 @@ "node": ">= 10" } }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/clone": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", @@ -3252,7 +3285,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", - "dev": true, "engines": { "node": ">=8" } @@ -3445,6 +3477,31 @@ "@esbuild/win32-x64": "0.19.5" } }, + "node_modules/esbuild-visualizer": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/esbuild-visualizer/-/esbuild-visualizer-0.4.1.tgz", + "integrity": "sha512-5XI3unzqPr3xqfzR/mzK3LhoAJs3FQhiIXBsKJ3Oh6CjyjuXz6HVmhJMoisrcpeTZip65fR54Dk53MZncA0AUQ==", + "dev": true, + "dependencies": { + "open": "^8.4.0", + "yargs": "^17.6.2" + }, + "bin": { + "esbuild-visualizer": "dist/bin/cli.js" + }, + "engines": { + "node": ">=14.20" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, "node_modules/escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -3884,6 +3941,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, "node_modules/get-intrinsic": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", @@ -4261,7 +4327,6 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "dev": true, "bin": { "is-docker": "cli.js" }, @@ -4394,7 +4459,6 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dev": true, "dependencies": { "is-docker": "^2.0.0" }, @@ -5193,7 +5257,6 @@ "version": "8.4.2", "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", - "dev": true, "dependencies": { "define-lazy-prop": "^2.0.0", "is-docker": "^2.1.1", @@ -5570,6 +5633,15 @@ "node": ">=8.10.0" } }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", @@ -6673,6 +6745,15 @@ "node": ">=0.4" } }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", @@ -6708,6 +6789,33 @@ "sprintf-js": "~1.0.2" } }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, "node_modules/yauzl": { "version": "2.10.0", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", diff --git a/package.json b/package.json index b0ff247..e3b2efb 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,7 @@ "prebuild": "rm -rf dist", "build": "tsc --outDir dist && rm -rf dist && ts-node esbuild.ts", "postbuild": "ts-node postbuild.ts", + "cdk-diff": "npm run build && pushd cdk && npm i && npm run diff && popd", "cdk-deploy": "npm run build && pushd cdk && npm i && npm run deploy && popd", "serverless-deploy": "npm run build && serverless deploy" }, @@ -17,6 +18,7 @@ "@types/aws-lambda": "^8.10.125", "@types/lambda-log": "^3.0.2", "esbuild": "^0.19.5", + "esbuild-visualizer": "^0.4.1", "serverless": "^3.36.0", "serverless-better-credentials": "^2.0.0", "ts-node": "^10.9.1", @@ -24,6 +26,7 @@ }, "dependencies": { "aws-lambda": "^1.0.7", - "lambda-log": "^3.1.0" + "lambda-log": "^3.1.0", + "open": "^8.4.2" } } diff --git a/postbuild.ts b/postbuild.ts index 401fc77..838c7b2 100644 --- a/postbuild.ts +++ b/postbuild.ts @@ -10,7 +10,7 @@ fs.readdirSync(path.join(__dirname, functionsDir)) 'ls -lah', `pushd dist/${entry}`, `echo "zipping ${entry} lambda"`, - `zip -R ${entry}.zip *.js`, + `zip -R ${entry}.zip *.js *.map`, 'popd', ]; execSync(commands.join(' && '), {