Skip to content

Commit 4fe6328

Browse files
authored
Merge pull request #93 from floydspace/fix/fix-#90-refacto-directory
Fix/fix #90 refacto directory and bundling
2 parents bebc691 + 66d856d commit 4fe6328

8 files changed

+292
-204
lines changed

README.md

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
💨 serverless-esbuild
2-
==============
1+
# 💨 serverless-esbuild
32

43
Serverless plugin for zero-config JavaScript and TypeScript code bundling using promising fast & furious [`esbuild`](https://github.com/evanw/esbuild) bundler and minifier
54

@@ -9,16 +8,15 @@ Serverless plugin for zero-config JavaScript and TypeScript code bundling using
98
[![build status](https://img.shields.io/github/workflow/status/floydspace/serverless-esbuild/release)](https://github.com/floydspace/serverless-esbuild/actions)
109
[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)
1110

12-
1311
## Features
1412

15-
* Zero-config: Works out of the box without the need to install any other compiler or plugins
16-
* Supports ESNext syntax with transforming limitations (See *Note*)
17-
* Supports `sls package`, `sls deploy` and `sls deploy function`
18-
* Supports `sls invoke local`
19-
* Integrates nicely with [`serverless-offline`](https://github.com/dherault/serverless-offline)
13+
- Zero-config: Works out of the box without the need to install any other compiler or plugins
14+
- Supports ESNext syntax with transforming limitations (See _Note_)
15+
- Supports `sls package`, `sls deploy` and `sls deploy function`
16+
- Supports `sls invoke local`
17+
- Integrates nicely with [`serverless-offline`](https://github.com/dherault/serverless-offline)
2018

21-
*Note*: The default JavaScript syntax target is set to [`ES2017`](https://node.green/#ES2017), so the final bundle will be supported by all [AWS Lambda Node.js runtimes](https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html). If you still using an old lambda runtime and have to respect it you can play with esbuild `target` option, see [JavaScript syntax support](https://github.com/evanw/esbuild#javascript-syntax-support) for more details about syntax transform limitations.
19+
_Note_: The default JavaScript syntax target is set to [`ES2017`](https://node.green/#ES2017), so the final bundle will be supported by all [AWS Lambda Node.js runtimes](https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html). If you still using an old lambda runtime and have to respect it you can play with esbuild `target` option, see [JavaScript syntax support](https://github.com/evanw/esbuild#javascript-syntax-support) for more details about syntax transform limitations.
2220

2321
## Install
2422

@@ -55,7 +53,6 @@ See [example folder](example) for a minimal example.
5553

5654
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)
5755

58-
5956
## Usage
6057

6158
### Automatic compilation
@@ -73,13 +70,13 @@ simulate AWS Lambda and AWS API Gateway locally.
7370

7471
Add the plugins to your `serverless.yml` file and make sure that `serverless-esbuild`
7572
precedes `serverless-offline` as the order is important:
73+
7674
```yaml
77-
plugins:
78-
...
79-
- serverless-esbuild
80-
...
81-
- serverless-offline
82-
...
75+
plugins: ...
76+
- serverless-esbuild
77+
...
78+
- serverless-offline
79+
...
8380
```
8481

8582
Run `serverless offline` or `serverless offline start` to start the Lambda/API simulation.
@@ -109,11 +106,12 @@ Note: When overriding ignore pattern, remember to ignore `.build` directory to a
109106
110107
Configure your service the same as mentioned above, but additionally add the `serverless-dynamodb-local`
111108
plugin as follows:
109+
112110
```yaml
113-
plugins:
114-
- serverless-esbuild
115-
- serverless-dynamodb-local
116-
- serverless-offline
111+
plugins:
112+
- serverless-esbuild
113+
- serverless-dynamodb-local
114+
- serverless-offline
117115
```
118116

119117
Run `serverless offline start`.
@@ -136,4 +134,8 @@ Options are:
136134

137135
[Victor Korzunin](https://floydspace.github.io/)
138136

139-
Inspired by [serverless-plugin-typescript](https://github.com/prisma-labs/serverless-plugin-typescript)
137+
## Contributors
138+
139+
[Loup Topalian](https://github.com/olup)
140+
141+
Inspired by [serverless-plugin-typescript](https://github.com/prisma-labs/serverless-plugin-typescript) and [serverless-webpack](https://github.com/serverless-heaven/serverless-webpack)

src/index.ts

Lines changed: 33 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,13 @@ import * as chokidar from 'chokidar';
99

1010
import { extractFileNames } from './helper';
1111
import { packExternalModules } from './pack-externals';
12-
import { packIndividually } from './pack-individually';
12+
import { pack } from './pack';
13+
import { preOffline } from './pre-offline';
14+
import { preLocal } from './pre-local';
1315

1416
export const SERVERLESS_FOLDER = '.serverless';
1517
export const BUILD_FOLDER = '.build';
18+
export const WORK_FOLDER = '.esbuild';
1619

1720
interface OptionsExtended extends Serverless.Options {
1821
verbose?: boolean;
@@ -38,12 +41,13 @@ const DEFAULT_BUILD_OPTIONS: Partial<Configuration> = {
3841
packager: 'npm',
3942
watch: {
4043
pattern: './**/*.(js|ts)',
41-
ignore: [BUILD_FOLDER, 'dist', 'node_modules', SERVERLESS_FOLDER],
44+
ignore: [WORK_FOLDER, 'dist', 'node_modules', SERVERLESS_FOLDER],
4245
},
4346
};
4447

4548
export class EsbuildPlugin implements Plugin {
46-
private originalServicePath: string;
49+
workDirPath: string;
50+
buildDirPath: string;
4751

4852
serverless: Serverless;
4953
options: OptionsExtended;
@@ -55,13 +59,20 @@ export class EsbuildPlugin implements Plugin {
5559
func: any;
5660
}[];
5761
packExternalModules: () => Promise<void>;
58-
packIndividually: () => Promise<void>;
62+
pack: () => Promise<void>;
63+
preOffline: () => Promise<void>;
64+
preLocal: () => void;
5965

6066
constructor(serverless: Serverless, options: OptionsExtended) {
6167
this.serverless = serverless;
6268
this.options = options;
6369
this.packExternalModules = packExternalModules.bind(this);
64-
this.packIndividually = packIndividually.bind(this);
70+
this.pack = pack.bind(this);
71+
this.preOffline = preOffline.bind(this);
72+
this.preLocal = preLocal.bind(this);
73+
74+
this.workDirPath = path.join(this.serverless.config.servicePath, WORK_FOLDER);
75+
this.buildDirPath = path.join(this.workDirPath, BUILD_FOLDER);
6576

6677
const withDefaultOptions = mergeRight(DEFAULT_BUILD_OPTIONS);
6778
this.buildOptions = withDefaultOptions<Configuration>(
@@ -78,19 +89,21 @@ export class EsbuildPlugin implements Plugin {
7889
await this.bundle();
7990
await this.packExternalModules();
8091
await this.copyExtras();
92+
await this.preOffline();
8193
this.watch();
8294
},
8395
'before:offline:start:init': async () => {
8496
await this.bundle();
8597
await this.packExternalModules();
8698
await this.copyExtras();
99+
await this.preOffline();
87100
this.watch();
88101
},
89102
'before:package:createDeploymentArtifacts': async () => {
90103
await this.bundle();
91104
await this.packExternalModules();
92105
await this.copyExtras();
93-
await this.packIndividually();
106+
await this.pack();
94107
},
95108
'after:package:createDeploymentArtifacts': async () => {
96109
await this.cleanup();
@@ -99,7 +112,7 @@ export class EsbuildPlugin implements Plugin {
99112
await this.bundle();
100113
await this.packExternalModules();
101114
await this.copyExtras();
102-
await this.packIndividually();
115+
await this.pack();
103116
},
104117
'after:deploy:function:packageFunction': async () => {
105118
await this.cleanup();
@@ -108,6 +121,7 @@ export class EsbuildPlugin implements Plugin {
108121
await this.bundle();
109122
await this.packExternalModules();
110123
await this.copyExtras();
124+
await this.preLocal();
111125
},
112126
};
113127
}
@@ -129,7 +143,7 @@ export class EsbuildPlugin implements Plugin {
129143

130144
get rootFileNames() {
131145
return extractFileNames(
132-
this.originalServicePath,
146+
this.serverless.config.servicePath,
133147
this.serverless.service.provider.name,
134148
this.functions
135149
);
@@ -152,6 +166,8 @@ export class EsbuildPlugin implements Plugin {
152166
}
153167

154168
prepare() {
169+
fs.mkdirpSync(this.buildDirPath);
170+
fs.mkdirpSync(path.join(this.workDirPath, SERVERLESS_FOLDER));
155171
// exclude serverless-esbuild
156172
for (const fnName in this.functions) {
157173
const fn = this.serverless.service.getFunction(fnName);
@@ -171,20 +187,13 @@ export class EsbuildPlugin implements Plugin {
171187
this.prepare();
172188
this.serverless.cli.log('Compiling with esbuild...');
173189

174-
if (!this.originalServicePath) {
175-
// Save original service path and functions
176-
this.originalServicePath = this.serverless.config.servicePath;
177-
// Fake service path so that serverless will know what to zip
178-
this.serverless.config.servicePath = path.join(this.originalServicePath, BUILD_FOLDER);
179-
}
180-
181190
return Promise.all(
182191
this.rootFileNames.map(async ({ entry, func }) => {
183192
const config: Omit<BuildOptions, 'watch'> = {
184193
...this.buildOptions,
185194
external: [...this.buildOptions.external, ...this.buildOptions.exclude],
186195
entryPoints: [entry],
187-
outdir: path.join(this.originalServicePath, BUILD_FOLDER, path.dirname(entry)),
196+
outdir: path.join(this.buildDirPath, path.dirname(entry)),
188197
platform: 'node',
189198
incremental,
190199
};
@@ -216,15 +225,15 @@ export class EsbuildPlugin implements Plugin {
216225
const files = await globby(service.package.include);
217226

218227
for (const filename of files) {
219-
const destFileName = path.resolve(path.join(BUILD_FOLDER, filename));
228+
const destFileName = path.resolve(path.join(this.buildDirPath, filename));
220229
const dirname = path.dirname(destFileName);
221230

222231
if (!fs.existsSync(dirname)) {
223232
fs.mkdirpSync(dirname);
224233
}
225234

226235
if (!fs.existsSync(destFileName)) {
227-
fs.copySync(path.resolve(filename), path.resolve(path.join(BUILD_FOLDER, filename)));
236+
fs.copySync(path.resolve(filename), path.resolve(path.join(this.buildDirPath, filename)));
228237
}
229238
}
230239
}
@@ -238,14 +247,14 @@ export class EsbuildPlugin implements Plugin {
238247
const { service } = this.serverless;
239248

240249
await fs.copy(
241-
path.join(this.originalServicePath, BUILD_FOLDER, SERVERLESS_FOLDER),
242-
path.join(this.originalServicePath, SERVERLESS_FOLDER)
250+
path.join(this.workDirPath, SERVERLESS_FOLDER),
251+
path.join(this.serverless.config.servicePath, SERVERLESS_FOLDER)
243252
);
244253

245254
if (this.options.function) {
246255
const fn = service.getFunction(this.options.function);
247256
fn.package.artifact = path.join(
248-
this.originalServicePath,
257+
this.serverless.config.servicePath,
249258
SERVERLESS_FOLDER,
250259
path.basename(fn.package.artifact)
251260
);
@@ -256,7 +265,7 @@ export class EsbuildPlugin implements Plugin {
256265
const functionNames = service.getAllFunctions();
257266
functionNames.forEach(name => {
258267
service.getFunction(name).package.artifact = path.join(
259-
this.originalServicePath,
268+
this.serverless.config.servicePath,
260269
SERVERLESS_FOLDER,
261270
path.basename(service.getFunction(name).package.artifact)
262271
);
@@ -265,18 +274,16 @@ export class EsbuildPlugin implements Plugin {
265274
}
266275

267276
service.package.artifact = path.join(
268-
this.originalServicePath,
277+
this.serverless.config.servicePath,
269278
SERVERLESS_FOLDER,
270279
path.basename(service.package.artifact)
271280
);
272281
}
273282

274283
async cleanup(): Promise<void> {
275284
await this.moveArtifacts();
276-
// Restore service path
277-
this.serverless.config.servicePath = this.originalServicePath;
278285
// Remove temp build folder
279-
fs.removeSync(path.join(this.originalServicePath, BUILD_FOLDER));
286+
fs.removeSync(path.join(this.workDirPath));
280287
}
281288
}
282289

0 commit comments

Comments
 (0)