如何使用 webpack 转译 typescript 以与 AWS Sam-cli 兼容

How to transpile typescript using webpack to be compatible with AWS Sam-cli

我正在尝试使用 webpack 在 AWS sam local 上获取 typescript 运行ning 进行转译,但由于所有额外的 webpack 输出,sam local 无法找到我导出的处理程序函数。

如果我只是 运行 tsc 并将我的代码转译为 lambda 函数 运行 没问题,那么我的问题是可以使用 webpack 转译 typescript 而无需添加所有额外的 webpack 模块内容吗?或者,如果没有,您是否有任何其他建议让我的构建与 AWS sam-cli

兼容

我当前代码遇到的错误是 TypeError: handler is not a function

这是我的 webpack 输出

exports["handler"] =
/******/ (function(modules) { // webpackBootstrap
/******/    // The module cache
/******/    var installedModules = {};
/******/
/******/    // The require function
/******/    function __webpack_require__(moduleId) {
/******/
/******/        // Check if module is in cache
/******/        if(installedModules[moduleId]) {
/******/            return                     
installedModules[moduleId].exports;
/******/        }
/******/        // Create a new module (and put it into the         
cache)
/******/        var module = installedModules[moduleId] = {
/******/            i: moduleId,
/******/            l: false,
/******/            exports: {}
/******/        };
/******/
/******/        // Execute the module function
/******/        modules[moduleId].call(module.exports, module, 
module.exports, __webpack_require__);
/******/
/******/        // Flag the module as loaded
/******/        module.l = true;
/******/
/******/        // Return the exports of the module
/******/        return module.exports;
/******/    }
/******/
/******/
/******/    // expose the modules object (__webpack_modules__)
/******/    __webpack_require__.m = modules;
/******/
/******/    // expose the module cache
/******/    __webpack_require__.c = installedModules;
/******/
/******/    // define getter function for harmony exports
/******/    __webpack_require__.d = function(exports, name, getter)     
{
/******/        if(!__webpack_require__.o(exports, name)) {
/******/            Object.defineProperty(exports, name, { 
enumerable: true, get: getter });
/******/        }
/******/    };
/******/
/******/    // define __esModule on exports
/******/    __webpack_require__.r = function(exports) {
/******/        if(typeof Symbol !== 'undefined' && 
Symbol.toStringTag) {
/******/            Object.defineProperty(exports, 
Symbol.toStringTag, { value: 'Module' });
/******/        }
/******/        Object.defineProperty(exports, '__esModule', { 
value: true });
/******/    };
/******/
/******/    // create a fake namespace object
/******/    // mode & 1: value is a module id, require it
/******/    // mode & 2: merge all properties of value into the ns
/******/    // mode & 4: return value when already ns object
/******/    // mode & 8|1: behave like require
/******/    __webpack_require__.t = function(value, mode) {
/******/        if(mode & 1) value = __webpack_require__(value);
/******/        if(mode & 8) return value;
/******/        if((mode & 4) && typeof value === 'object' && 
value && value.__esModule) return value;
/******/        var ns = Object.create(null);
/******/        __webpack_require__.r(ns);
/******/        Object.defineProperty(ns, 'default', { 
enumerable: true, value: value });
/******/        if(mode & 2 && typeof value != 'string') for(var 
key in value) __webpack_require__.d(ns, key, function(key) { return 
value[key]; }.bind(null, key));
/******/        return ns;
/******/    };
/******/
/******/    // getDefaultExport function for compatibility with non- 
harmony modules
/******/    __webpack_require__.n = function(module) {
/******/        var getter = module && module.__esModule ?
/******/            function getDefault() { return 
module['default']; } :
/******/            function getModuleExports() { return 
module; };
/******/        __webpack_require__.d(getter, 'a', getter);
/******/        return getter;
/******/    };
/******/
/******/    // Object.prototype.hasOwnProperty.call
/******/    __webpack_require__.o = function(object, property) { 
return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/    // __webpack_public_path__
/******/    __webpack_require__.p = "";
/******/
/******/
/******/    // Load entry module and return exports
/******/    return __webpack_require__(__webpack_require__.s = 
"./src/lambda/users/register/index.ts");
/******/ })

 /**************************************************************/
/******/ ({

/***/ "./src/lambda/users/register/index.ts":
/*!********************************************!*\
  !*** ./src/lambda/users/register/index.ts ***!
  \********************************************/
/*! exports provided: handler */
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export 
(binding) */ __webpack_require__.d(__webpack_exports__, \"handler\", 
function() { return handler; });\n\nvar __awaiter = (undefined && 
undefined.__awaiter) || function (thisArg, _arguments, P, generator) 
{\n    return new (P || (P = Promise))(function (resolve, reject) 
{\n        function fulfilled(value) { try { 
step(generator.next(value)); } catch (e) { reject(e); } }\n        
function rejected(value) { try { step(generator[\"throw\"](value)); 
} catch (e) { reject(e); } }\n        function step(result) { 
result.done ? resolve(result.value) : new P(function (resolve) { 
resolve(result.value); }).then(fulfilled, rejected); }\n        
step((generator = generator.apply(thisArg, _arguments || 
[])).next());\n    });\n};\nvar __generator = (undefined && 
undefined.__generator) || function (thisArg, body) {\n    var _ = { 
label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1];  
}, trys: [], ops: [] }, f, y, t, g;\n    return g = { next: verb(0), 
\"throw\": verb(1), \"return\": verb(2) }, typeof Symbol === 
\"function\" && (g[Symbol.iterator] = function() { return this; }), 
g;\n    function verb(n) { return function (v) { return step([n, 
v]); }; }\n    function step(op) {\n        if (f) throw new 
TypeError(\"Generator is already executing.\");\n        while (_) 
try {\n            if (f = 1, y && (t = y[op[0] & 2 ? \"return\" : 
op[0] ? \"throw\" : \"next\"]) && !(t = t.call(y, op[1])).done) 
return t;\n            if (y = 0, t) op = [0, t.value];\n            
switch (op[0]) {\n                case 0: case 1: t = op; break;\n                
case 4: _.label++; return { value: op[1], done: false };\n                
case 5: _.label++; y = op[1]; op = [0]; continue;\n                
case 7: op = _.ops.pop(); _.trys.pop(); continue;\n                
default:\n                    if (!(t = _.trys, t = t.length > 0 && 
t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; 
}\n                    if (op[0] === 3 && (!t || (op[1] > t[0] && 
op[1] < t[3]))) { _.label = op[1]; break; }\n                    if 
(op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\n                    
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; 
}\n                    if (t[2]) _.ops.pop();\n                    
_.trys.pop(); continue;\n            }\n            op = 
body.call(thisArg, _);\n        } catch (e) { op = [6, e]; y = 0; } 
finally { f = t = 0; }\n        if (op[0] & 5) throw op[1]; return { 
value: op[0] ? op[1] : void 0, done: true };\n    }\n};\nvar _this = 
undefined;\nvar handler = function (event) {\n    if (event === void 
 0) { event = {}; }\n    return __awaiter(_this, void 0, void 0, 
 function () {\n        var response;\n        return 
__generator(this, function (_a) {\n            console.log('Hello 
World!');\n            response = JSON.stringify(event, null, 2);\n            
return [2 /*return*/, 'success'];\n        });\n    });\n};\n\n\n//# 
sourceURL=webpack://handler/./src/lambda/users/register/index.ts?");

/***/ })

/******/ });

这是原src码

'use strict'
export const handler = async (event: any = {}): Promise<any> => {
    console.log('Hello World!');
    const response = JSON.stringify(event, null, 2);
    return response;
}

这是 运行s 的 tsc 编译代码(我确实收到了一个错误,但我知道为什么会这样,这不是要修复的问题)

 'use strict';
 var __awaiter = (this && this.__awaiter) || function (thisArg, 
_arguments, P, generator) {
    return new (P || (P = Promise))(function (resolve, reject) {
         function fulfilled(value) { try {           
step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"] . 
 (value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) 
: new P(function (resolve) { resolve(result.value); 
 }).then(fulfilled, rejected); }
         step((generator = generator.apply(thisArg, _arguments || 
 [])).next());
     });
};
var __generator = (this && this.__generator) || function (thisArg, 
 body) {
     var _ = { label: 0, sent: function() { if (t[0] & 1) throw 
 t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
    return g = { next: verb(0), "throw": verb(1), "return": verb(2) 
 }, typeof Symbol === "function" && (g[Symbol.iterator] = function() 
{ return this; }), g;
    function verb(n) { return function (v) { return step([n, v]); };  
}
     function step(op) {
         if (f) throw new TypeError("Generator is already 
executing.");
        while (_) try {
            if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? 
 y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t 
 = t.call(y, op[1])).done) return t;
             if (y = 0, t) op = [op[0] & 2, t.value];
            switch (op[0]) {
                case 0: case 1: t = op; break;
                case 4: _.label++; return { value: op[1], done: 
 false };
                case 5: _.label++; y = op[1]; op = [0]; continue;
                case 7: op = _.ops.pop(); _.trys.pop(); continue;
                 default:
                    if (!(t = _.trys, t = t.length > 0 && t[t.length 
 - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
                     if (op[0] === 3 && (!t || (op[1] > t[0] && 
 op[1] < t[3]))) { _.label = op[1]; break; }
                     if (op[0] === 6 && _.label < t[1]) { _.label = 
 t[1]; t = op; break; }
                     if (t && _.label < t[2]) { _.label = t[2]; 
 _.ops.push(op); break; }
                     if (t[2]) _.ops.pop();
                     _.trys.pop(); continue;
             }
             op = body.call(thisArg, _);
        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
         if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : 
 void 0, done: true };
     }
 };
var _this = this;
exports.__esModule = true;
 exports.handler = function (event) {
     if (event === void 0) { event = {}; }
    return __awaiter(_this, void 0, void 0, function () {
         var response;
         return __generator(this, function (_a) {
             console.log('Hello World!');
             response = JSON.stringify(event, null, 2);
             return [2 /*return*/, 'success'];
         });
        });
 };

我已经尝试了多个不同的 libraryTargets,但 none 成功了

新用户问得好!这是(我认为)解决方案。


默认情况下,如果您在源代码中导入一些库,Webpack 会将其包含在它生成的包中。这对于 Web 来说非常简洁,因为您可以构建一个使用许多包的完整应用程序,并将整个应用程序捆绑到一个 .js 文件中,并将其提供给访问您网站的人。 Webpack 可以做很多事情,但这就是为什么它是 web bundler.

然而,在构建云功能时,情况有所不同。为您的网络功能提供服务的服务器已经拥有您将要使用的库,这与一些随机访问网站的人相反。只要我记得,您就可以告诉 AWS 您将使用标准 package.json 哪些库。

那么,如何告诉 webpack 不包含服务器已经 "know about" 的库?简单的答案,在你的 webpack.config.js 中使用 external 参数。示例:

// in webpack.config.js
module.exports = {
  // ...
  externals: {
    react: 'react', // tells webpack not to include the react package inside its bundle
  }
}

也就是说,顺便说一句,为什么 tsc "works",因为它只 转译 代码,而不是 bundle 你的源代码需要的所有东西都在一个文件里。