javascript - 与 webpack 捆绑的 Firebase 云功能?

标签 javascript node.js firebase webpack google-cloud-functions

我一直在尝试为我的云函数文件构建 webpack 构建。

我的项目结构:

ROOT

- FUNCTIONS
  - DIS
    - bundle.js // THIS SHOULD BE GENERATED BY WEBPACK
  - SRC
    - myCloudFunction.js  // SOURCE CODE FOR A CLOUD FUNCTION
    - entryPoint.js  // ENTRY POINT FOR WEBPACK
  - index.js    
  - package.json

- SRC
  - App.js

.babelrc
firebase.json
webpack.prod.js    // THIS BUILDS FOR CLIENT (WORKING FINE)
webpack.server.js  // THIS SHOULD BUILD FOR THE SERVER (NOT WORKING)

我的目标是:
  • 在现代 JS 中编写云函数文件和 index.js 并将它们与 webpack 一起编译和捆绑(使用我用来捆绑客户端代码的相同 webpack,但使用另一个配置文件)。

  • myCloudFunction.js (记录一些文本的简单函数)
    module.exports = (req,res) => {
      console.log('myCloudFunction is executing...');
      res.status(200).send('From myCloudFunction...');
    }
    

    entryPoint.js (基本上是导入函数的代码并导出为云函数)
    const functions = require('firebase-functions');
    const myCloudFunction = require('./src/myCloudFunction');
    
    module.exports.myCloudFunction = functions.https.onRequest(myCloudFunction);
    

    如果我使 index.js 与我的 entryPoint.js 完全相同,它就可以正常工作。但我想使用来自 entryPoint.js 的 webpack 捆绑文件,并将捆绑的结果设置为我的 index.js 文件。在这种情况下,基本上只会捆绑 2 个文件( entryPointmyCloudFunction )。

    我正在使用 webpack 捆绑:

    webpack.prod.server.js
    const webpack = require('webpack');
    const path = require('path');
    const Dotenv = require('dotenv-webpack');
    const { CleanWebpackPlugin } = require('clean-webpack-plugin');
    const nodeExternals = require('webpack-node-externals');
    
    module.exports = {
      mode: 'development',
      stats: 'verbose',
      devtool: 'inline-source-map',
    
      entry: {
        app: './functions/src/entryPoint.js'
      },
    
      output: {
        filename: 'bundle.js',
        path: path.resolve(__dirname, './functions/dist'),
        publicPath: '/'
      },
    
      // externals: {
      //   "firebase-admin": true,
      //   "firebase-functions": true
      // },
    
      target: 'node',
      externals: [nodeExternals(),'firebase-functions', 'firebase-admin','firebase'],
    
      plugins:[
        new CleanWebpackPlugin(),
        new webpack.HashedModuleIdsPlugin(),
        new webpack.DefinePlugin({
            'process.env.ON_SERVER': true
        }),
        new Dotenv()
      ],
    
      module: {
        rules:[
          {
            test: /\.js$/,
            include: path.resolve(__dirname, 'src'),
            use: ['babel-loader']
          },   
        ]
      }
    };
    

    我读到您不应该将 node_modules 捆绑到后端,这就是我使用 externals 属性的原因。

    bundle.js (使用上述配置运行 webpack 后的结果包)
    /******/ (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 = "oFca");
    /******/ })
    /************************************************************************/
    /******/ ({
    
    /***/ "4ouX":
    /*!******************************************!*\
      !*** ./functions/src/myCloudFunction.js ***!
      \******************************************/
    /*! no static exports found */
    /***/ (function(module, exports) {
    
    module.exports = (req,res) => {
      console.log('myCloudFunction is executing...');
      res.status(200).send('From myCloudFunction...');
    }
    
    /***/ }),
    
    /***/ "O8Wp":
    /*!*************************************!*\
      !*** external "firebase-functions" ***!
      \*************************************/
    /*! no static exports found */
    /***/ (function(module, exports) {
    
    module.exports = firebase-functions;
    
    /***/ }),
    
    /***/ "oFca":
    /*!********************************!*\
      !*** ./functions/src/index.js ***!
      \********************************/
    /*! no static exports found */
    /***/ (function(module, exports, __webpack_require__) {
    
    const functions = __webpack_require__(/*! firebase-functions */ "O8Wp");
    const myCloudFunction = __webpack_require__(/*! ./myCloudFunction */ "4ouX");
    
    module.exports.myCloudFunction = functions.https.onRequest(myCloudFunction);
    
    /***/ })
    
    /******/ });
    

    它应该可以工作,但我收到此错误:

    我希望复制 bundle.js 的内容并将其粘贴到 index.js 并使其工作。但是当我这样做时,当我尝试提供该功能时会出现此错误。请参阅下图中的错误行。
    >>> firebase serve --only hosting,functions
    
    +  functions: Using node@10 from host.
    +  functions: Emulator started at http://localhost:5001
    i  functions: Watching "C:\Projects\test-ssr\functions" for Cloud Functions...
    i  hosting: Serving hosting files from: public
    +  hosting: Local server: http://localhost:5000
    !  ReferenceError: firebase is not defined
        at Object.O8Wp (C:\Projects\test-ssr\functions\index.js:110:20)
    

    enter image description here

    问题

    我究竟做错了什么?任何帮助,将不胜感激!

    更新

    我刚刚发现这解决了问题,但我不知道为什么这是必要的。我仍然希望对这个问题有更好的理解。

    webpack.prod.server.js
    output: {
        filename: '[name].[contenthash:5].js',
        // filename: 'index.js',
        path: path.resolve(__dirname, './functions/dist'),
        publicPath: '/',
        libraryTarget: 'commonjs'   // <--- THIS FIXED IT
      },
    

    最佳答案

    如您所见,您需要设置 libraryTarget 为了构建一个 webpack 包,该包本身可以由 webpack 构建之外的另一个模块导入(例如,从云函数)。
    出于很多原因,使用 webpack 捆绑您的函数应用程序是一个好主意。正如您所指出的,这意味着您可以以一致的方式为不同的目的编译相同的代码 - 例如。 SSR 和浏览器端。其他福利:

  • 访问 webpack 加载器/插件
  • 使用 HMR 获得更好的开发人员体验(比函数运行时的实现效果更好)
  • 更好的部署和运行性能(一个或几个优化 block 与成百上千个未优化/未使用的文件)

  • 无论如何,使用 webpack-cloud-functions 可能会更轻松一些。 (我是作者)。它抽象了您需要执行此操作的大部分配置,包括配置 libraryTarget .

    关于javascript - 与 webpack 捆绑的 Firebase 云功能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58596845/

    相关文章:

    node.js - NODE JS - 永远的启动路径问题

    node.js - 如何摆脱 : Warning: Cannot find any files matching pattern "dotenv_config_path=.env.test"

    firebase - 未找到访问 token 受众中的 OAuth2 客户端 ID

    javascript - Firebase 多路径更新只会覆盖假定的节点

    javascript - 使用rails如何将 Controller 中的变量同步到 View ,其中 Controller 是更新的发起者

    javascript - angular 2 transient 提供者而不是单例

    javascript - 在控制台上打印链接的名称

    javascript - UIWebView elementFromPoint js方法返回 'wrong'元素

    javascript - 将 TypeAhead 与 jQuery 和 Bootstrap 2.1 结合使用

    javascript - React 不执行组件中的函数