Webpack adding 'no exports provided' to module with exports

Viewed 3017

I'm trying to set up SSR for my React app. I'm using components from a NPM package (private) within my app. The app uses Apollo Client, and makes GraphQL requests. The module in question is a simple apollo-link-state module that returns if a user is logged in, if not it performs a mutation. The app is dynamically loaded using loadable. The problem is that all my link-state modules work correctly except for the user one. I checked the webpack build file and this is what I get:

/*! no exports provided */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _babel_runtime_regenerator__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @babel/runtime/regenerator */ "../my-package/node_modules/@babel/runtime/regenerator/index.js");
/* harmony import */ var _babel_runtime_regenerator__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_babel_runtime_regenerator__WEBPACK_IMPORTED_MODULE_0__);
Object.defineProperty(exports, "__esModule", {
 value: true
});

exports.typeDefs = exports.defaults = exports.resolvers = undefined;

//Do my processing here (using apolloClient for async mutations )

exports.default = {
 resolvers: resolvers,
 defaults: defaults,
 typeDefs: typeDefs
};

My webpack config is pretty simple:

{ entry: './server.js',
 output: {
  filename: 'server.js',    
  path: path.resolve(__dirname, 'build'),        
 },
 resolve: {
   modules: [path.resolve(__dirname, 'src'), 'node_modules'],
   aliases: // my aliases here all work correctly
 },
 target: 'node',
 node: {
   __dirname: false
 },
module: {
 rules: [
  {
    test: /\.js$/,
    exclude: /node_modules/,
    use: 'babel-loader'
  },
  {
    exclude: [/\.js$/, /\.html$/, /\.json$/],
    loader: 'file-loader',
    options: {
      name: 'static/media/[name].[hash:8].[ext]',
      publicPath: '/',
      emitFile: false
    },
  },
  {
    sideEffects: false,    
  },  
],
},
plugins:[new LoadablePlugin()]
};

I have tried setting output fields libraryExport : default, libraryTarget: 'commonjs2'. Is this related to the @babel/transform-runtime plugin? I'm not sure why only one module is tagged as no export provided. When I require the file in the build file it returns an empty object.

This is my .babelrc for good measure:

{
 "presets": [
   ["@babel/preset-env", {"modules": false}], 
    "@babel/preset-react",      
   ],
 "plugins": [
   "@babel/plugin-proposal-class-properties",
   "@babel/plugin-proposal-object-rest-spread",
   "@babel/plugin-syntax-dynamic-import",
   [
    "@babel/transform-runtime",
     {
      "regenerator": true,
      "useESModules": true,
      "absoluteRuntime": true,
     }
   ]
 ]
}

A suggestion on what could be wrong will also be highly appreciated, I'll do the leg work of making it work. I'm not clear on why just one module is exhibiting this behavior, I'm trying to see if setting sideEffects in the package.json of my package will help.

EDIT: sideEffects do not work. I noticed that this is the only file which is using the _babel_runtime_regenerator__. Since I'm using Babel 7, there should be no need for me to use the plugin-add-module-exports but so far no luck. This module still returns an empty object on require

I also tried setting the preset-env option modules : "commonjs", but that did not help either. Why can't webpack detect exports in just this module?

1 Answers

I was encountering a similar problem in a similar scenario:

  • private (local) component library
  • bundling an app (via webpack) that consumed components from the component library
  • some components were loading and executing properly, some weren't

My component library was transpiled prior to use in my app, and all the transpiled code looked fine. However, I am using yalc (https://github.com/whitecolor/yalc) when running locally so that I can more easily build/transpile my component library code and then pseudo-"publish" the component library for use within my app without having to actually publish to an NPM repo somewhere.

When using yalc, it creates a symlink between my component library code and a module folder under node_modules in my app. This allows my app builds to properly resolve @my/library modules to my local component library code. And therein was the cause of my issue.

My webpack config for .js files was similar to yours:

{
  test: /\.m?jsx?$/,
  exclude: /node_modules/,
  use: {
    loader: 'babel-loader',
    options: {
      babelrc: false,
      presets: [env, reactApp],
    },
  },
},

However, in more closely examining the webpack bundle output, it seemed like webpack was adding more code (helpers/polyfills) to some of my components. I realized that when resolving the symlink to my local component library, the resolve path doesn't actually contain node_modules, it's a path to my component library folder instead. Therefore, the exclude test for .js files was not matching and webpack was running babel-loader against code that was already transpiled.

I changed my rule config exclude pattern to include a pattern to match the path to my component library code and that fixed everything:

{
  test: /\.m?jsx?$/,
  exclude: [/node_modules/, /@my\/library/],
  use: {
    loader: 'babel-loader',
    options: {
      babelrc: false,
      presets: [env, reactApp],
    },
  },
},

I realize this may not be the solution for the original question, but hopefully it helps or provides insights for anyone encountering a similar problem.

Related