1 | var util = require('util');
|
2 | var fs = require('fs');
|
3 | var path = require('path');
|
4 | var conf = require('./config');
|
5 | var webpack = require('webpack');
|
6 | var merge = require('webpack-merge');
|
7 | const findUp = require('find-up');
|
8 |
|
9 | const readdir = util.promisify(fs.readdir);
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 | const BABEL_ROOT_CONFIG_FILENAMES = [
|
16 | 'babel.config.js',
|
17 | 'babel.config.cjs',
|
18 | 'babel.config.mjs',
|
19 | 'babel.config.json',
|
20 | ];
|
21 |
|
22 | const BABEL_RELATIVE_CONFIG_FILENAMES = [
|
23 | '.babelrc',
|
24 | '.babelrc.js',
|
25 | '.babelrc.cjs',
|
26 | '.babelrc.mjs',
|
27 | '.babelrc.json',
|
28 | ];
|
29 |
|
30 | const BABEL_CONFIG_FILENAMES = [
|
31 | ...BABEL_ROOT_CONFIG_FILENAMES,
|
32 | ...BABEL_RELATIVE_CONFIG_FILENAMES,
|
33 | ];
|
34 |
|
35 | const testFilePattern = '\\.(test|spec)\\.?';
|
36 |
|
37 |
|
38 | function getBabelTarget(envConfig) {
|
39 | var key = 'AWS_LAMBDA_JS_RUNTIME';
|
40 | var runtimes = ['nodejs8.15.0', 'nodejs6.10.3'];
|
41 | var current = envConfig[key] || process.env[key] || 'nodejs8.15.0';
|
42 | var unknown = runtimes.indexOf(current) === -1;
|
43 | return unknown ? '8.15.0' : current.replace(/^nodejs/, '');
|
44 | }
|
45 |
|
46 | async function getRepositoryRoot(functionsDir, cwd) {
|
47 | const gitDirectory = await findUp('.git', {
|
48 | cwd: functionsDir,
|
49 | type: 'directory',
|
50 | });
|
51 | if (gitDirectory === undefined) {
|
52 | return cwd;
|
53 | }
|
54 |
|
55 | return path.dirname(gitDirectory);
|
56 | }
|
57 |
|
58 | async function existsBabelConfig(functionsDir, cwd) {
|
59 | const repositoryRoot = await getRepositoryRoot(functionsDir, cwd);
|
60 | const babelConfigFile = await findUp(
|
61 | (dir) => {
|
62 | const babelConfigFile = BABEL_CONFIG_FILENAMES.find(
|
63 | (babelConfigFilename) =>
|
64 | findUp.sync.exists(path.join(dir, babelConfigFilename)),
|
65 | );
|
66 | if (babelConfigFile) {
|
67 | return path.join(dir, babelConfigFile);
|
68 | }
|
69 |
|
70 | if (dir === repositoryRoot) {
|
71 | return findUp.stop;
|
72 | }
|
73 | return undefined;
|
74 | },
|
75 | {
|
76 | cwd: functionsDir,
|
77 | },
|
78 | );
|
79 | return Boolean(babelConfigFile);
|
80 | }
|
81 |
|
82 | async function webpackConfig(
|
83 | dir,
|
84 | { userWebpackConfig, useBabelrc, cwd = process.cwd() } = {},
|
85 | ) {
|
86 | var config = await conf.load();
|
87 | var envConfig = conf.loadContext(config).environment;
|
88 | var babelOpts = { cacheDirectory: true };
|
89 |
|
90 | var dirPath = path.resolve(path.join(cwd, dir));
|
91 | const isBabelConfigExists = await existsBabelConfig(dirPath, cwd);
|
92 | if (!isBabelConfigExists) {
|
93 | babelOpts.presets = [
|
94 | [
|
95 | require.resolve('@babel/preset-env'),
|
96 | { targets: { node: getBabelTarget(envConfig) } },
|
97 | ],
|
98 | ];
|
99 |
|
100 | babelOpts.plugins = [
|
101 | require.resolve('@babel/plugin-proposal-class-properties'),
|
102 | require.resolve('@babel/plugin-transform-object-assign'),
|
103 | require.resolve('@babel/plugin-proposal-object-rest-spread'),
|
104 | ];
|
105 | }
|
106 |
|
107 | var functionsDir = config.build.functions || config.build.Functions;
|
108 | var functionsPath = path.resolve(path.join(cwd, functionsDir));
|
109 |
|
110 | if (dirPath === functionsPath) {
|
111 | throw new Error(
|
112 | `
|
113 | netlify-lambda Error: Function source folder (specified in netlify-lambda serve/build command) and publish folder (specified in netlify.toml)
|
114 | should be different. They are both set to ${dirPath}.
|
115 |
|
116 | This is a common mistake for people switching from Netlify Dev to netlify-lambda. For an easy fix, change your functions key inside netlify.toml to something else, like "functions-build".
|
117 | You will then need to build your functions to that directory before they will work locally and the built functions will also need to be pushed to your repo.
|
118 | For more info, check https://github.com/netlify/netlify-lambda#usage
|
119 | `,
|
120 | );
|
121 | }
|
122 |
|
123 |
|
124 | var defineEnv = {};
|
125 | Object.keys(envConfig).forEach((key) => {
|
126 | defineEnv['process.env.' + key] = JSON.stringify(envConfig[key]);
|
127 | });
|
128 |
|
129 |
|
130 | var nodeEnv = process.env.NODE_ENV || 'production';
|
131 |
|
132 |
|
133 | var webpackMode = ['production', 'development'].includes(nodeEnv)
|
134 | ? nodeEnv
|
135 | : 'none';
|
136 |
|
137 | var webpackConfig = {
|
138 | mode: webpackMode,
|
139 | resolve: {
|
140 | extensions: ['.wasm', '.mjs', '.js', '.json', '.ts'],
|
141 | mainFields: ['module', 'main'],
|
142 | },
|
143 | module: {
|
144 | rules: [
|
145 | {
|
146 | test: /\.(m?js|ts)?$/,
|
147 | exclude: new RegExp(
|
148 | `(node_modules|bower_components|${testFilePattern})`,
|
149 | ),
|
150 | use: {
|
151 | loader: require.resolve('babel-loader'),
|
152 | options: { ...babelOpts, babelrc: useBabelrc },
|
153 | },
|
154 | },
|
155 | ],
|
156 | },
|
157 | context: dirPath,
|
158 | entry: {},
|
159 | target: 'node',
|
160 | plugins: [
|
161 | new webpack.IgnorePlugin(/vertx/),
|
162 | new webpack.DefinePlugin(defineEnv),
|
163 | ],
|
164 | output: {
|
165 | path: functionsPath,
|
166 | filename: '[name].js',
|
167 | libraryTarget: 'commonjs',
|
168 | },
|
169 | optimization: {
|
170 | nodeEnv,
|
171 | },
|
172 | bail: true,
|
173 | devtool: false,
|
174 | stats: {
|
175 | colors: true,
|
176 | },
|
177 | };
|
178 | const files = await readdir(dirPath);
|
179 | files.forEach(function (file) {
|
180 | if (file.match(/\.(m?js|ts)$/)) {
|
181 | var name = file.replace(/\.(m?js|ts)$/, '');
|
182 | if (!name.match(new RegExp(testFilePattern))) {
|
183 | webpackConfig.entry[name] = './' + file;
|
184 | }
|
185 | }
|
186 | });
|
187 | if (Object.keys(webpackConfig.entry) < 1) {
|
188 | console.warn(
|
189 | `
|
190 | ---Start netlify-lambda notification---
|
191 | WARNING: No valid single functions files (ending in .mjs, .js or .ts) were found.
|
192 | This could be because you have nested them in a folder.
|
193 | If this is expected (e.g. you have a zipped function built somewhere else), you may ignore this.
|
194 | ---End netlify-lambda notification---
|
195 | `,
|
196 | );
|
197 | }
|
198 | if (userWebpackConfig) {
|
199 | var webpackAdditional = require(path.join(cwd, userWebpackConfig));
|
200 |
|
201 | return merge.smart(webpackConfig, webpackAdditional);
|
202 | }
|
203 |
|
204 | return webpackConfig;
|
205 | }
|
206 |
|
207 | exports.run = async function (dir, additionalConfig) {
|
208 | const config = await webpackConfig(dir, additionalConfig);
|
209 | return new Promise(function (resolve, reject) {
|
210 | webpack(config, function (err, stats) {
|
211 | if (err) {
|
212 | return reject(err);
|
213 | }
|
214 | const errors = stats.compilation.errors || [];
|
215 | if (errors.length > 0) {
|
216 | return reject(stats.compilation.errors);
|
217 | }
|
218 | resolve(stats);
|
219 | });
|
220 | });
|
221 | };
|
222 |
|
223 | exports.watch = async function (dir, additionalConfig, cb) {
|
224 | const compiler = webpack(await webpackConfig(dir, additionalConfig));
|
225 | compiler.watch(await webpackConfig(dir, additionalConfig), cb);
|
226 | };
|