Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
97 views
in Technique[技术] by (71.8m points)

javascript - Confused by module exports/requires

I am working on a piece where I am basically refactoring existing code. I have two files: index and server. My index is:

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');

My server is like:

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();

The server should run a REST service when executed locally, and export the server instance for the inject method. This way a proxy can attach to it when running under AWS Lambda.

I used the same setup before, multiple times. Only the two pieces were in the same file eg the server was inside the index. A single file version works fine - require.main comparison tells the program how it is running and module.exports exposes the server instance [server] with the needed inject method when running under Lambda and runs the REST service with a direct invocation.

However, since I need to import react-loadable this time, I split the files in two pieces.

Now, I probably need to figure out how the code is running inside index.js as server.js is not being invoked directly then pass it to the server. It is probably not too difficult.

My main problem is that when if I do console.log(require('./server')) from index, it prints {}. While the server instance is created successfully, and the inject() is present; I am somehow unable to export it from the server.js file and import into index.js correctly, and therefore [re-]export it from index.js for the proxy to attach.

Obviously, I am doing something incorrectly. To me, seems that my require does not have the server instance because the instance gets created after the require finished. Since my main() is async, it is plausible. What is the right way to accomplish this?

question from:https://stackoverflow.com/questions/65886374/confused-by-module-exports-requires

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

First, notice that your main() function in ./server.js is async and you're defining module.exports from within that asynchronous function. Second, you're calling require('./server.js') from ./index.js without waiting for the asynchronous work to finish. Node resolves require()-d modules as a blank object immediately (that's the {} you're getting), and then extends the object when any async or cyclic material becomes available. So that's why you're seeing what you're seeing.

Which solutions will or will not fit your use case will depend on the details of how your AWS/direct invocation is supposed to work. Here's a suggestion:

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();

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...