netlify-lambda
Version:
Build and serve lambda function with webpack compilation
147 lines (130 loc) • 4.28 kB
JavaScript
var fs = require('fs');
var path = require('path');
var conf = require('./config');
var webpack = require('webpack');
var merge = require('webpack-merge');
const testFilePattern = "\\.(test|spec)\\.?";
// custom babel target for each node version
function getBabelTarget(envConfig) {
var key = 'AWS_LAMBDA_JS_RUNTIME';
var runtimes = ['nodejs8.15.0', 'nodejs6.10.3'];
var current = envConfig[key] || process.env[key] || 'nodejs8.15.0';
var unknown = runtimes.indexOf(current) === -1;
return unknown ? '8.15.0' : current.replace(/^nodejs/, '');
}
function haveBabelrc(functionsDir) {
const cwd = process.cwd();
return (
fs.existsSync(path.join(cwd, '.babelrc')) ||
functionsDir.split('/').reduce((foundBabelrc, dir) => {
if (foundBabelrc) return foundBabelrc;
const indexOf = functionsDir.indexOf(dir);
const dirToSearch = functionsDir.substr(0, indexOf);
return fs.existsSync(path.join(cwd, dirToSearch, '.babelrc'));
}, false)
);
}
function webpackConfig(dir, additionalConfig) {
var config = conf.load();
var envConfig = conf.loadContext(config).environment;
var babelOpts = { cacheDirectory: true };
if (!haveBabelrc(dir)) {
babelOpts.presets = [
['@babel/preset-env', { targets: { node: getBabelTarget(envConfig) } }]
];
babelOpts.plugins = [
'@babel/plugin-proposal-class-properties',
'@babel/plugin-transform-object-assign',
'@babel/plugin-proposal-object-rest-spread'
];
}
var functionsDir = config.build.functions || config.build.Functions;
var functionsPath = path.join(process.cwd(), functionsDir);
var dirPath = path.join(process.cwd(), dir);
if (dirPath === functionsPath) {
throw new Error(
`
netlify-lambda Error: Function source folder (specified in netlify-lambda serve/build command)
and publish folder (specified in netlify.toml)
should be different.
For more info, check https://github.com/netlify/netlify-lambda#usage
`
);
}
// Include environment variables from config if available
var defineEnv = {};
Object.keys(envConfig).forEach(key => {
defineEnv['process.env.' + key] = JSON.stringify(envConfig[key]);
});
var webpackConfig = {
mode: 'production',
resolve: {
extensions: ['.wasm', '.mjs', '.js', '.json', '.ts']
},
module: {
rules: [
{
test: /\.(m?js|ts)?$/,
exclude: new RegExp(
`(node_modules|bower_components|${testFilePattern})`
),
use: {
loader: 'babel-loader',
options: babelOpts
}
}
]
},
context: dirPath,
entry: {},
target: 'node',
plugins: [
new webpack.IgnorePlugin(/vertx/),
new webpack.DefinePlugin(defineEnv)
],
output: {
path: functionsPath,
filename: '[name].js',
libraryTarget: 'commonjs'
},
devtool: false
};
fs.readdirSync(dirPath).forEach(function(file) {
if (file.match(/\.(m?js|ts)$/)) {
var name = file.replace(/\.(m?js|ts)$/, "");
if (!name.match(new RegExp(testFilePattern))) {
webpackConfig.entry[name] = "./" + file;
}
}
});
if (Object.keys(webpackConfig.entry) < 1) {
console.warn(
`
---Start netlify-lambda notification---
WARNING: No valid single functions files (ending in .mjs, .js or .ts) were found.
This could be because you have nested them in a folder.
If this is expected (e.g. you have a zipped function built somewhere else), you may ignore this.
---End netlify-lambda notification---
`
);
}
if (additionalConfig) {
var webpackAdditional = require(path.join(process.cwd(), additionalConfig));
return merge.smart(webpackConfig, webpackAdditional);
}
return webpackConfig;
}
exports.run = function(dir, additionalConfig) {
return new Promise(function(resolve, reject) {
webpack(webpackConfig(dir, additionalConfig), function(err, stats) {
if (err) {
return reject(err);
}
resolve(stats);
});
});
};
exports.watch = function(dir, additionalConfig, cb) {
var compiler = webpack(webpackConfig(dir, additionalConfig));
compiler.watch(webpackConfig(dir, additionalConfig), cb);
};