【问题标题】:async / await breaks my Webpack build for AWS Lambda; how can I migrate to Node 8.10?async / await 破坏了我为 AWS Lambda 构建的 Webpack;如何迁移到 Node 8.10?
【发布时间】:2018-04-20 10:20:19
【问题描述】:

注意:这是一个关于将 AWS Lambda Webpack 构建从 v6.10 迁移到 v8.10 的问答 - 不需要帮助,但当然总是鼓励更好的答案!


在阅读了 James Long 的优秀系列“Webpack 的后端应用”part 1, part2part3)。

直到最近,Amazon Web Services 提供的唯一 Node.js 版本是 6.10;您必须以“回调”样式编写 Lambda fn。但是在 2018 年 4 月 2 日AWS announced that 8.10 was now supported,建议的模式是异步/等待,这很棒!直到它立即破坏了我的 Webpack 构建。经过一些调试,我可以通过向 Lambda 处理程序添加一个异步 fn 来破坏我的构建(我什至不需要调用它):

async function firstAsync() {
  return true;
}

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

需要明确的是,在 AWS Lambda 控制台中执行此操作非常好,运行良好。 Webpack 甚至成功构建它,但在上传到 AWS Lambda 后,我收到以下错误消息:regeneratorRuntime is not defined。我的代码如下。我需要做什么?

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"
  }
}

【问题讨论】:

    标签: node.js amazon-web-services webpack aws-lambda


    【解决方案1】:

    Geek Stock 的answer above 仅在使用 Node v6.10 运行时时才需要。它允许您使用 async/await 语法,babel-runtime/regenerator 将您的异步函数转换为 ES6 生成器,这在 Node v4.3.2 和更新的运行时上受支持。

    但在 Node v8.10 中,情况有所不同。 async/await 已经被支持,所以你不需要 Babel 将你的 async 函数转换为生成器。你只要正确使用它,它就可以工作。

    至于您的具体情况,我假设您只是将 Javascript 代码更改为使用 async/await 代码,但您没有告诉 Babel 不要将您的 async/await 代码转换为生成器。这就是babel-runtime 抱怨缺少插件的原因。

    如果是这种情况,您只需将 Babel 配置为简单地以 Node v8.10 为目标。你可以在你的.babelrc中这样做...

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

    babel 将停止转换那些async 函数。而且由于它不进行转换,因此不再需要regenerator-runtime

    【讨论】:

    • OP 问题中的代码是 Babel 构建。您是否通过建议完全移除 Babel 来回答这个迁移问题?看来您的答案是重新配置 Babel,与 Babel 在他们的文章中的建议不同。我已经用你的方法做了一个 git rollback 并再次迁移,并且出现了同样的错误(regeneratorRuntime is not defined)。不清楚你在说什么。我会尝试完全移除 Babel,如果可能的话会更好。
    • 同样,当你为低于 8 的 Node 版本构建时,你只需要 regenerator-runtime。如果 async/await 是你唯一使用 Babel 的用例,那么你可以在定位 Node 时完全删除它v8。我的回答是如果你仍然需要它,就保留 Babel。如果你只使用async/await,那么如果你的目标是 Node v8.10,那么移除 Babel 会更好。
    • 提示:确保您还在开发机器和 CI 环境中使用 Node v8.10(如果有)。
    • 我同意。现在已经进行了 2 小时的代码重构会议(大声笑),经过一些更改后,我能够在没有 Babel 的情况下成功构建和部署到 Lambda 8.10。正如您所指出的,在 Lambda 6.10 及更早版本中,开发人员将需要我的回答。但如果开发人员可以完全摆脱 Babel,那么肯定会得到一个非常精简的构建。
    • 我们面临同样的问题。在节点 8.10 中使用 serverless-webpack 以及 lambda,我希望 Babel 不会转换我的 async/await。但它确实会转换它们,并且当我在升级到节点 8 时删除了 babel-runtime/regenerator 时,我遇到了这个错误:ReferenceError: regeneratorRuntime is not defined。 - Babel 配置目标 node 8.10(仅此而已) - devDependencies:@babel/core@babel/preset-envwebpackwebpack-node-externals - 依赖项:@babel/runtime
    【解决方案2】:

    就我而言,我将它与nodejs12.x 一起使用。我收到错误regeneratorRuntime 未定义

    我使用预设 es2015stage-0node12.x 代码。另外我使用的是旧版本的babel

    我做了什么,安装了:

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

    然后设置这个 babel 预设:

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

    谢谢,

    【讨论】:

      【解决方案3】:

      要开始在 Webpack 构建的代码中使用 async / await,您需要 Babel 的一些帮助,特别是 babel-runtimebabel-plugin-transform-runtime。幸运的是,关于here on the Babel website 的安装和使用有一篇非常好的文章。你需要 Babel 为你做以下事情:

      使用时自动需要 babel-runtime/regenerator 生成器/异步函数。

      我不会重复那里写的内容,然而,特别要注意的是您需要如何安装这些,因为虽然他们的文章确实适用于大多数人,但有些人需要进行调整以前不需要运行时的 AWS Lambda 开发人员dependencies

      第一部分很正常,你需要新的devDependencies:

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

      您还需要像他们描述的那样调整您的 .babelrc 文件:

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

      但这里是关键,这是上面代码的新内容:babel-runtime 是普通的dependencies,而不是devDependencies

      npm install --save babel-runtime
      

      这 2 次安装和 .babelrc 调整确实解决了上述异步/等待问题,但它为上面的构建引入了一个新问题:Cannot find module 'babel-runtime/regenerator'

      如果您完全关心保持 Webpack 构建的代码较小,那么您可能也像上面的代码一样使用 webpack-node-externals。例如,aws-sdk for JavaScript in Node 非常大,并且已经在 Lambda 环境中可用,因此再次捆绑它是多余的。上面的webpack-node-externals 配置将Webpack 配置为默认忽略node-modules 中的所有模块,而那里 是新问题的根源。新安装的babel-runtime 是一个模块,需要在构建中捆绑才能使 Lambda 正确运行。

      那么理解问题,答案就很简单了:不要使用默认配置。不要向webpack-node-externals 传递任何内容,而是像这样配置它:

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

      解决了最初的 async / await 问题,以及如果您在构建中没有以前的 dependencies 可能会遇到的(可能的)新问题。希望对您有所帮助 — Lambda awaiting 快乐!

      【讨论】:

      • 此过程适用于 Node v4.3 和 v6.10 运行时。
      • 我有点同意。从 6.10 迁移到 8.10 的第一步是首先评估您是否可以重构以完全消除 Babel,正如 dashmug 在他的回答中正确指出的那样。 这是一个更好的结果。 但是如果你因为其他原因不能避免 Babel,这个答案确实 也适用于 8.10,if 你遵循Babel 对.babelrc 的推荐显示在这里。测试证明了这一点,并且在 dashmug 的回答中使用 Babel 配置时失败了。尽管有该项目,但我们似乎确实在这里有 2 个有用的答案,具体取决于一个人的环境。谢谢你dashmug :)
      • 这仍然适用于 Node 8.10,因为您为早期版本编写的内容将继续适用于它。但是通过这种配置,您不会使用 Node 8 的 async/await 功能,因为 Babel 会将其转换为生成器。因此,正如 OP 问题所述,您并没有真正迁移到 Node 8。
      • 这个答案回答了“如何在节点 4 和 6 运行时使用 async/await?”的问题。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多