The Problem
TypeError: fetch is not a function
at DigestClient.fetch (webpack-internal:///./node_modules/digest-fetch/digest-fetch-src.js:48:24)
at User.create (webpack-internal:///./node_modules/mongodb-atlas-api-client/src/user.js:53:26)
at Function.createOrgDBUser (webpack-internal:///./src/OrgUtils.ts:87:51)
at Function.createOrg (webpack-internal:///./src/apis/OrgAPI.ts:373:39)
at processTicksAndRejections (internal/process/task_queues.js:97:5)
at async APIResponse.processHandlerFunction (webpack-internal:///./node_modules/apilove/lib/APIResponse.ts:27:31)
That's the error I'm getting trying to use [email protected]
to create indexes on a collection. I'm seeing this error locally and in aws-lambda.
atlasClient.user.create({...})
I use webpack to bundle my api so I think the issue is in how I'm bundling but in my research I haven't been able to come up with a solution.
digest-fetch
, used by mongodb-atlas-api-client
, uses node-fetch
in absence of the native fetch
function. However, I believe my webpack configuration coupled with the way digest-fetch
imports the library is what's causing the issue.
The following line of code is from node-modules/digest-fetch/digest-fetch-src.js:8
if (typeof(fetch) !== 'function' && canRequire) var fetch = require('node-fetch')
If I change that to the below, everything works fine. In other words, it's importing the module not the main exported fetch function from node-fetch
.
if (typeof(fetch) !== 'function' && canRequire) var fetch = require('node-fetch').default
The node-fetch/package.json
describes three entry points.
"main": "lib/index.js",
"browser": "./browser.js",
"module": "lib/index.mjs",
I think what's happening is my webpack configuration is telling webpack to use the .mjs
module entry point to build its output from node-fetch
, which does export default fetch;
.
My webpack.config.js
const path = require('path')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const CopyPlugin = require('copy-webpack-plugin')
const NodemonPlugin = require('nodemon-webpack-plugin')
const ZipPlugin = require('zip-webpack-plugin')
module.exports = (env, argv) => {
const config = {
target: 'node',
watchOptions: {
ignored: ['node_modules', '*.js', '*.js.map', '*.d.ts'],
},
entry: './src/APIHandler.ts',
output: {
path: path.resolve(__dirname, 'dist'),
filename: `APIHandler.js`,
libraryTarget: 'commonjs',
},
optimization: {
minimize: false,
// minimizer: [new TerserPlugin({})],
},
resolve: {
extensions: ['.ts', '.json', '.mjs', '.js'],
},
module: {
rules: [
{
test: /\.tsx?$/,
use: {
loader: 'ts-loader',
options: {
transpileOnly: true,
allowTsInNodeModules: true,
},
},
},
],
},
plugins: [
new CleanWebpackPlugin(),
new CopyPlugin([
{ from: path.join(__dirname, 'src/certs'), to: path.resolve(__dirname, 'dist', 'certs') },
]),
new NodemonPlugin(),
],
}
// eslint-disable-next-line no-console
console.log({ mode: argv.mode })
if (argv.mode === 'development') {
config.devtool = 'eval-cheap-module-source-map'
}
if (argv.mode === 'production') {
config.plugins.push(
new ZipPlugin({
filename: 'handler',
})
)
}
return config
}
FWIW, here's the version of each library currently installed in my node_modules. I'm using node v12.22.7
locally.
"digest-fetch": "1.2.1",
"mongodb-atlas-api-client": "2.31.0",
"node-fetch": "2.6.7",
"webpack": "4.46.0"
The Question
What am I missing? What change do I need to make to my webpack.config.js
to have the require properly resolve to the main module export from node-fetch
?
NOTE: In my research I've found other people having this problem but no resolutions that have helped me.
CodePudding user response:
The solution was pretty simple. I added mainFields
to the webpack config's resolve
property.
resolve: {
extensions: ['.ts', '.json', '.mjs', '.js'],
mainFields: ['main', 'module'],
}
This tells webpack to first use the main
property of a module's package.json
, then fallback to the module
property if it's not found.
For more information, see webpack's documentation.