async / await breaks my Webpack build for AWS Lambda; how can I migrate to Node 8.10?

£可爱£侵袭症+ 提交于 2020-08-23 07:52:29

问题


Note: this is a Q&A on migrating AWS Lambda Webpack builds from v6.10 to v8.10 — no help is needed, but even better answers are of course always encouraged!


For a while now I have been a disciple of using Webpack to build my back-end Lambdas after reading James Long's excellent series entitled "Backend Apps with Webpack" (part 1, part2, and part3).

Up until recently, the only version of Node.js that Amazon Web Services offered was 6.10; you had to write your Lambda fn in the "callback" style. But on April 2, 2018 AWS announced that 8.10 was now supported, and with it the suggested pattern is async / await which is great! Until it immediately broke my Webpack build. After a bit of debugging, I can break my build just by adding one async fn to the Lambda handler (I don't even need to call it):

async function firstAsync() {
  return true;
}

exports.handler = async (event) => {
    // TODO implement
    return 'Hello from Lambda!'
};

To be clear, doing this in the AWS Lambda console is perfectly fine, runs great. Webpack even builds it successfully, but upon uploading to AWS Lambda, I get the following error message: regeneratorRuntime is not defined. My code is below. What am I needing to do?

webpack.config.js

const nodeExternals = require('webpack-node-externals');
const path = require('path');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
const webpack = require('webpack');

const config = {
  entry: './src/index.js',

  output: {
    path: path.resolve(__dirname, 'dist'),
    library: 'index',
    libraryTarget: 'commonjs2',
    filename: 'index.js'
  },
  target: 'node', // building for a Node environment
  externals: [nodeExternals()], // in order to ignore all modules in node_modules folder 
  module: {
    rules: [{
      test: /\.(js|jsx)$/,
      use: {
        loader: 'babel-loader',
        options: {
          presets: ['env']
        }
      }
    }]
  },
  plugins: [
    new UglifyJsPlugin()
  ]
};

module.exports = config;

package.json

{
  "name": "lambda-webpack",
  "version": "1.0.0",
  "description": "An empty project scaffold to enable webpack builds in AWS Lambda",
  "main": "index.js",
  "scripts": {
    "build": "webpack",
    "upload": "upload.bat"
  },
  "author": "Geek Stocks®",
  "license": "MIT",
  "devDependencies": {
    "aws-sdk": "^2.179.0",
    "babel-core": "^6.26.0",
    "babel-loader": "^7.1.2",
    "babel-preset-env": "^1.6.1",
    "uglifyjs-webpack-plugin": "^1.1.6",
    "webpack": "^3.10.0",
    "webpack-node-externals": "^1.6.0"
  }
}

回答1:


Geek Stock's answer above is only necessary when using the Node v6.10 runtime. It allows you to use async/await syntax and babel-runtime/regenerator converts your async functions to ES6 generators which is supported on Node v4.3.2 and newer runtimes.

In Node v8.10 though, it is different. async/await is already supported so you don't need Babel to convert your async functions to generators. You just use it correctly and it works.

As for your specific situation, I assume you simply changed your Javascript code to use async/await code but you didn't tell Babel NOT to convert your async/await code to generators. That is why babel-runtime is complaining about a missing plugin.

If this is the case, you simply need to configure Babel to simply target Node v8.10. You can do it like this in your .babelrc...

{
  "presets": [
    [
      "env",
      {
        "targets": {
          "node": "8.10"
        }
      }
    ]
  ]
}

babel will then stop converting those async functions. And since it's not doing a conversion, it will not need the regenerator-runtime anymore.




回答2:


To begin using async / await in your Webpack-built code, you need a little help from Babel, specfically the babel-runtime and the babel-plugin-transform-runtime. Fortunately there is a really good writeup on the installation and use of both here on the Babel website. You need Babel to do the following for you:

Automatically requires babel-runtime/regenerator when you use generators/async functions.

I won't repeat what has been written there, however, of particular note is HOW you need to install these, because while their writeup certainly works for most, there is a needed tweak for some AWS Lambda devs who have not needed runtime dependencies before now.

The first part is pretty normal, you need new devDependencies:

npm install --save-dev babel-plugin-transform-runtime

And also you need to tweak your .babelrc file like they describe:

{
  "plugins": [
    ["transform-runtime", {
      "helpers": false,
      "polyfill": false,
      "regenerator": true,
      "moduleName": "babel-runtime"
    }]
  ]
}

But here is the kicker, and this is new to the code above: the babel-runtime is a regular dependencies, not a devDependencies:

npm install --save babel-runtime

These 2 installs and the .babelrc tweaks do SOLVE the async / await problem described above, but it introduces a new problem to the build above: Cannot find module 'babel-runtime/regenerator'.

If you are at all concerned with keeping your Webpack built code small, you are likely also using webpack-node-externals like the above code does. For example, the aws-sdk for JavaScript in Node is very large and is already available in the Lambda environment, so its superfluous to bundle it again. The webpack-node-externals configuration above configures Webpack to ignore ALL the modules in node-modules by default, and there is the root of the new problem. The newly installed babel-runtime is a module that needs to be bundled in the build in order for Lambda to run correctly.

Understanding the problem then, the answer becomes simple: don't use the default configuration. Instead of passing in nothing to webpack-node-externals, configure it like this:

externals: [nodeExternals({
  whitelist: [
    'babel-runtime/regenerator',
    'regenerator-runtime'
  ]
})], // ignore all modules in node_modules folder EXCEPT the whitelist

And that solves both the original async / await problem, and the (possible) new problem you may be encountering if you had no previous dependencies in your build. Hope that helps — happy Lambda awaiting!




回答3:


In my case I'm using it with nodejs12.x. I'm receiving the error regeneratorRuntime is not defined.

I was using preset es2015 and stage-0 with a node12.x code. Also I'm using an older version of babel.

What I did, installed:

"@babel/cli": "^7.10.1",
"@babel/core": "^7.10.2",
"@babel/preset-env": "^7.10.2"

And then set this babel preset:

"presets": [
    ["@babel/preset-env", {"targets": { "node": "current" }}]
]

Thanks,



来源:https://stackoverflow.com/questions/49939401/async-await-breaks-my-webpack-build-for-aws-lambda-how-can-i-migrate-to-node

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!