被模块导出/需求所迷惑

问题描述

我正在研究一个基本上重构现有代码的部分。我有两个文件:索引和服务器。我的索引是:

const md5File = require('md5-file');
const fs = require('fs');
const path = require('path');
const ignoreStyles = require('ignore-styles');
const register = ignoreStyles.default;
const extensions = ['.gif','.jpeg','.jpg','.png','.svg'];
...
require('@babel/polyfill');
require('@babel/register')({
  ignore: [/\/(build|node_modules)\//],presets: ['@babel/preset-env','@babel/preset-react'],plugins: [
    '@babel/plugin-Syntax-dynamic-import','@babel/plugin-proposal-class-properties','dynamic-import-node','react-loadable/babel'
  ]
});
// Now that the nonsense is over... load up the server entry point
require('./server');

我的服务器就像:

import path from 'path';
import Loadable from 'react-loadable';
...
const main = async () => {
  // tell React Loadable to load all required assets
  await Loadable.preloadAll();

  process.on('unhandledRejection',err => {
    console.error(err);
    process.exit(1);
  });

  const server = fastify(config.fastify);
  server.register(require('./routes'),config);
  server.register(fastifyStatic,{
    root: path.resolve(__dirname,'../build')
  });
  if (require.main === module) {
    // called directly i.e. $ node index.js
    const address = await server.listen(config.address);
    // start listening - ROCK AND ROLL!
    server.log.info(`Server running at: ${address}`);
  } else {
    // required as a module => executed on aws lambda
    module.exports = server;
  }
};
main();

服务器在本地执行时应运行 REST 服务,并为 inject 方法导出服务器实例。这样,代理可以在 AWS Lambda 下运行时附加到它。

我之前多次使用相同的设置。只有两个部分在同一个文件中,例如服务器在索引内。单个文件版本工作正常 - require.main 比较告诉程序它是如何运行的,并且 module.exports 在 Lambda 下运行时使用所需的 server 方法公开服务器实例 [inject]并通过直接调用运行 REST 服务。

但是,由于我这次需要导入 react-loadable,所以我将文件分成两部分。

现在,我可能需要弄清楚代码是如何在 index.js 内部运行的,因为 server.js 没有被直接调用,然后将其传递给服务器。应该不会太难。

我的主要问题是,当我从索引执行 console.log(require('./server')) 时,它会打印 {}。当服务器实例创建成功并且存在 inject() 时;我不知何故无法从 server.js 文件中导出它并正确导入到 index.js,因此 [re-] 将它从 index.js 导出以供代理附加。

显然,我做错了一些事情。对我来说,似乎我的 require 没有服务器实例,因为在 require 完成后创建了实例。由于我的 main() 是异步的,这是合理的。 实现这一目标的正确方法是什么?

解决方法

首先,请注意 ./server.js 中的 main() 函数是 async,并且您正在从该异步函数中定义 module.exports。其次,您无需等待异步工作完成即可从 ./index.js 调用 require('./server.js')。 Node 立即将 require()-d 模块解析为空白对象(这就是您获得的 {}),然后在任何异步或循环材料可用时扩展该对象。所以这就是为什么你会看到你所看到的。

哪些解决方案适合或不适合您的用例将取决于您的 AWS/直接调用应该如何工作的详细信息。这是一个建议:

const md5File = require('md5-file');
const fs = require('fs');
const path = require('path');
const ignoreStyles = require('ignore-styles');
const register = ignoreStyles.default;
const extensions = ['.gif','.jpeg','.jpg','.png','.svg'];
// ...
require('@babel/polyfill');
require('@babel/register')({
  ignore: [/\/(build|node_modules)\//],presets: ['@babel/preset-env','@babel/preset-react'],plugins: [
    '@babel/plugin-syntax-dynamic-import','@babel/plugin-proposal-class-properties','dynamic-import-node','react-loadable/babel'
  ]
});

process.env.serverRunLocally = require.main === module;

// Now that the nonsense is over... load up the server entry point
require('./server').then(listen => listen());
import path from 'path';
import Loadable from 'react-loadable';
// ...
const main = async () => {
  // tell React Loadable to load all required assets
  await Loadable.preloadAll();

  process.on('unhandledRejection',err => {
    console.error(err);
    process.exit(1);
  });

  const server = fastify(config.fastify);
  server.register(require('./routes'),config);
  server.register(fastifyStatic,{
    root: path.resolve(__dirname,'../build')
  });
  if (process.env.serverRunLocally) {
    // called directly i.e. $ node index.js
    return () => {
       const address = await server.listen(config.address);
       // start listening - ROCK AND ROLL!
       server.log.info(`Server running at: ${address}`);
    }
  } else {
    // required as a module => executed on aws lambda
    return server;
  }
};

module.exports = main();