forked from ecstasy2/serverless-babel-plugin
-
Notifications
You must be signed in to change notification settings - Fork 1
/
index.js
144 lines (119 loc) · 4.68 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
'use strict';
const unzip = require('unzip2');
const fs = require('fs');
const path = require('path');
const archiver = require('archiver');
const spawnSync = require('child_process').spawnSync;
const BbPromise = require('bluebird');
const glob = require('glob-all');
const rimraf = require('rimraf');
const _ = require('lodash');
const isWin = /^win/.test(process.platform);
const isLinux = /^linux/.test(process.platform);
const isMac = /^darwin/.test(process.platform);
class ServerlessPlugin {
constructor(serverless, options) {
this.serverless = serverless;
this.options = options;
this.hooks = {
'after:deploy:createDeploymentArtifacts': this.transform.bind(this),
'after:deploy:function:packageFunction': this.transform.bind(this),
};
}
transform() {
return new BbPromise((resolve, reject) => {
if (!this.serverless.service.custom ||
_.isUndefined(this.serverless.service.custom.babelPresets)) {
reject('For the serverless-babel-plugin you need to define `babelPresets` as custom configuration in your serverless.yaml');
}
if (!Array.isArray(this.serverless.service.custom.babelPresets)) {
reject('`babelPresets` in your serverless.yaml must be an Array');
}
if (_.isUndefined(this.serverless.service.custom.babelPlugins)) {
this.serverless.service.custom.babelPlugins = []
}
if (!Array.isArray(this.serverless.service.custom.babelPlugins)) {
reject('`babelPlugins` in your serverless.yaml must be an Array');
}
const servicePath = this.serverless.config.servicePath;
let bundleName = this.serverless.service.service;
// determine if we are deploying a single function or the entire service
if (this.options && this.options.f !== undefined) {
bundleName = `${bundleName}-${this.options.stage}-${this.options.f}`;
}
// unzip
const stream = fs.createReadStream(path.join(servicePath, `.serverless/${bundleName}.zip`))
.pipe(unzip.Extract({ path: path.join(servicePath, '.serverless/tmpBabelDirectory') }));
stream.on('error', (error) => {
reject(error);
});
// unzip2 actually emits close when completed. When unzipping a large file, using finish will cause this plugin to run prematurely
stream.on('close', () => {
// compile
const args = [
'--out-dir=tmpBabelDirectory',
'tmpBabelDirectory',
'--ignore=node_modules',
`--presets=${this.serverless.service.custom.babelPresets.join(',')}`,
`--plugins=${this.serverless.service.custom.babelPlugins.join(',')}`,
];
const options = {
cwd: path.join(servicePath, '.serverless'),
};
const execPath = path.join(__dirname, '..', '.bin/babel');
console.log('Babel Executable: ' + execPath);
if (isWin) execPath += '.cmd';
const result = spawnSync(execPath, args, options);
if (result.error) {
return reject(result.error);
}
const stdout = result && result.stdout && result.stdout.toString();
const sterr = result && result.stderr && result.stderr.toString();
if (stdout) {
this.serverless.cli.log(`Babel compilation:\n${stdout}`);
}
if (sterr) {
return reject(sterr);
}
// zip
this.serverless.cli.log('Packaging service with compiled files...');
const patterns = ['**'];
const tmpBabelDirectory = '.serverless/tmpBabelDirectory';
const zip = archiver.create('zip');
const artifactFilePath = `.serverless/${bundleName}.zip`;
this.serverless.utils.writeFileDir(artifactFilePath);
const output = fs.createWriteStream(artifactFilePath);
output.on('open', () => {
zip.pipe(output);
const files = glob.sync(patterns, {
cwd: tmpBabelDirectory,
dot: true,
silent: true,
follow: true,
});
files.forEach((filePath) => {
const fullPath = path.resolve(tmpBabelDirectory, filePath);
const stats = fs.statSync(fullPath);
if (!stats.isDirectory(fullPath)) {
zip.append(fs.readFileSync(fullPath), {
name: filePath,
mode: stats.mode,
});
}
});
zip.finalize();
});
zip.on('error', err => reject(err));
output.on('close', () => {
try {
rimraf.sync(tmpBabelDirectory, { disableGlob: true });
} catch (err) {
reject(err);
}
resolve(artifactFilePath);
});
});
});
}
}
module.exports = ServerlessPlugin;