React-app-rewired: Multiple entries rewire error: Cannot read property 'filter' of undefined

Created on 8 Nov 2019  路  5Comments  路  Source: timarney/react-app-rewired

I need to have multiple entries with create-react-app, but I also don't want to eject. There is a minimal reproducible sample repo here: https://github.com/vl4d1m1r4/cra-multi-entry.
The modifications follow the weback v4 configuration documentation and consist only of adding a separate entry for admin.js and separate HtmlWebpackPlugin to add the bundle in different admin.html.

When doing yarn start it just hangs on starting development environment.
When running with yarn build it shows the following error:

yarn build
yarn run v1.19.1
$ react-app-rewired build
Creating an optimized production build...
Failed to compile.

Cannot read property 'filter' of undefined


error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

Any hints on what might be the issue?

Most helpful comment

Thank you very much for the hints! I was finally able to find the issue. The problem was in the ManifestPlugin configuration from CRA. It assumes that the entry point will be called main, the default from Webpack:

`` // Generate an asset manifest file with the following content: // - "files" key: Mapping of all asset filenames to their corresponding // output file so that tools can pick it up without having to parse //index.html // - "entrypoints" key: Array of files which are included inindex.html`,
// can be used to reconstruct the HTML if necessary
new ManifestPlugin({
fileName: 'asset-manifest.json',
publicPath: publicPath,
generate: (seed, files, entrypoints) => {
const manifestFiles = files.reduce((manifest, file) => {
manifest[file.name] = file.path;
return manifest;
}, seed);
const entrypointFiles = entrypoints.main.filter( // <--- This line here
fileName => !fileName.endsWith('.map')
);

      return {
        files: manifestFiles,
        entrypoints: entrypointFiles,
      };
    },
  }),
I was able to make a successful build after adapting the generate method to take into consideration the multiple entries:

...
const entrypointFiles = {};
Object.keys(entrypoints).forEach(entrypoint => {
entrypointFiles[entrypoint] = entrypoints[entrypoint].filter(fileName => !fileName.endsWith('.map'));
});
...
```
I will check tomorrow if the generated manifest is useful with the change and update the issue.

Here is the commit on the sample repository for full details: 8c62e91

All 5 comments

A huge thank you for the reproducible sample - it enabled me to at least narrow down where the issue was occurring (which would have been impossible without it).

Since the yarn build gave some output rather than just seeming to hang, I've tried tracing through the build function calls. As far as I have been able to trace, it's failing inside Webpack when Webpack tries to emit (write out) the files produced by the compilation, but it isn't making into the actual per-file emit code (so either prior to stepping through the list of files to emit, or maybe in a beforeEmit hook).

Inside node_modules/webpack/Compiler.js, in the function emitAssets:

  • The error is reported in the final call to this.hooks.emit.callAsync.
  • The emitFiles function defined inside emitAssets never gets run.
    (As determined by sprinkling that file with console.log statements starting at the run function and narrowing down as far as I could).

I was able to get the list of file names it was supposed to be trying to emit, which looked sensible:

[
  "static/media/logo.25bf045c.svg",
  "static/js/0.b4c4e099.chunk.js",
  "static/css/admin.b100e6da.chunk.css",
  "static/js/admin.73e3d81d.chunk.js",
  "static/css/index.b100e6da.chunk.css",
  "static/js/index.23cf0cae.chunk.js",
  "static/js/runtime-admin.8b8bd490.js",
  "static/js/runtime-index.ea3b42c9.js",
  "static/css/index.b100e6da.chunk.css.map",
  "static/css/admin.b100e6da.chunk.css.map",
  "static/js/0.b4c4e099.chunk.js.map",
  "static/js/admin.73e3d81d.chunk.js.map",
  "static/js/index.23cf0cae.chunk.js.map",
  "static/js/runtime-admin.8b8bd490.js.map",
  "static/js/runtime-index.ea3b42c9.js.map"
]

I haven't been able to work out what gets called with the hooks.emit function, so I couldn't trace what was happening any further.

My guess is that a plugin that has defined a compilation step for hooks.emit (or maybe hooks.beforeEmit) is throwing the error. It didn't seem to be HtmlWebpackPlugin - I tried checking that one and the emit function there was running to completion.

Possible directions to go from here: check the other plugins (e.g. the css one) for any additional config they may need for the multiple entry fields, or if a specific version is required for multiple entry fields to work.

I believe that something somewhere inside the Webpack emit hook is expecting to have/use an array, but instead the variable used is undefined and the function using that variable isn't testing whether it exists prior to trying to filter it.

React-app-rewired itself isn't responsible for the error - it's being generated inside the Webpack compiler so it is likely to be either a missing configuration snippet for a plugin, a plugin that isn't compatible with multiple entry points, or a bug in Webpack or a plugin. Best of luck finding the problem from here, hopefully the above helps you to know what to look for/ask about upstream.

Thank you very much for the hints! I was finally able to find the issue. The problem was in the ManifestPlugin configuration from CRA. It assumes that the entry point will be called main, the default from Webpack:

`` // Generate an asset manifest file with the following content: // - "files" key: Mapping of all asset filenames to their corresponding // output file so that tools can pick it up without having to parse //index.html // - "entrypoints" key: Array of files which are included inindex.html`,
// can be used to reconstruct the HTML if necessary
new ManifestPlugin({
fileName: 'asset-manifest.json',
publicPath: publicPath,
generate: (seed, files, entrypoints) => {
const manifestFiles = files.reduce((manifest, file) => {
manifest[file.name] = file.path;
return manifest;
}, seed);
const entrypointFiles = entrypoints.main.filter( // <--- This line here
fileName => !fileName.endsWith('.map')
);

      return {
        files: manifestFiles,
        entrypoints: entrypointFiles,
      };
    },
  }),
I was able to make a successful build after adapting the generate method to take into consideration the multiple entries:

...
const entrypointFiles = {};
Object.keys(entrypoints).forEach(entrypoint => {
entrypointFiles[entrypoint] = entrypoints[entrypoint].filter(fileName => !fileName.endsWith('.map'));
});
...
```
I will check tomorrow if the generated manifest is useful with the change and update the issue.

Here is the commit on the sample repository for full details: 8c62e91

Fantastic! Thank you for the update on what the cause of the issue was - it can serve as a reference for anyone else that tries to set up multiple entry points. :)

Solve my problem perfectly!

Thank you very much for the hints! I was finally able to find the issue. The problem was in the ManifestPlugin configuration from CRA. It assumes that the entry point will be called main, the default from Webpack:

    // Generate an asset manifest file with the following content:
     // - "files" key: Mapping of all asset filenames to their corresponding
     //   output file so that tools can pick it up without having to parse
     //   `index.html`
     // - "entrypoints" key: Array of files which are included in `index.html`,
     //   can be used to reconstruct the HTML if necessary
     new ManifestPlugin({
       fileName: 'asset-manifest.json',
       publicPath: publicPath,
       generate: (seed, files, entrypoints) => {
         const manifestFiles = files.reduce((manifest, file) => {
           manifest[file.name] = file.path;
           return manifest;
         }, seed);
         const entrypointFiles = entrypoints.main.filter(  // <--- This line here
           fileName => !fileName.endsWith('.map')
         );

         return {
           files: manifestFiles,
           entrypoints: entrypointFiles,
         };
       },
     }),

I was able to make a successful build after adapting the generate method to take into consideration the multiple entries:

...
const entrypointFiles = {};
Object.keys(entrypoints).forEach(entrypoint => {
  entrypointFiles[entrypoint] = entrypoints[entrypoint].filter(fileName => !fileName.endsWith('.map'));
});
...

I will check tomorrow if the generated manifest is useful with the change and update the issue.

Here is the commit on the sample repository for full details: 8c62e91

Thanks! Really helped with my problem!

I use a similar interface for two different applications and build them in one script.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

artalar picture artalar  路  4Comments

jaggerwang picture jaggerwang  路  4Comments

001123 picture 001123  路  4Comments

bilthon picture bilthon  路  5Comments

InsOpDe picture InsOpDe  路  5Comments