digest-fetch and webpack - fetch is not a function - javascript

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 mongodb-atlas-api-client#2.3.1 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.

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.

Related

React : You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file(Local Node module)

I have babel loader in the library. Still after I add the library to the react application while yarn serve, I get the above error.
This is the webpack.dev.config.js (required in the webpack.config.js) in library-
//webpack.dev.config.js
const babelRCPath = require('#appfabric/infra-scripts').getConfigPath('babel', 'plugin');
const babelRCGenerator = require(babelRCPath);
const babelRC = babelRCGenerator([]);
module.exports = {
{
BaseModule: `${process.cwd()}/src/BaseModule`,
BaseObject: `${process.cwd()}/src/BaseObject`,
BaseWidget: `${process.cwd()}/src/widgets/BaseWidget`,
HOCWidget: `${process.cwd()}/src/widgets/HOCWidget`,
PortalWidget: `${process.cwd()}/src/widgets/PortalWidget`,
BaseActivator: `${process.cwd()}/src/application/BaseActivator`,
CorePlugin: `${process.cwd()}/src/application/CorePlugin`,
BaseAppDelegate: `${process.cwd()}/src/application/appdelegates/BaseAppDelegate`,
EmbeddedAppDelegate: `${process.cwd()}/src/default/appdelegates/embedded/EmbeddedAppDelegate`,
ActionType: `${process.cwd()}/src/application/appdelegates/actions/ActionType`,
types: `${process.cwd()}/src/application/appdelegates/actions/types`,
CommandActionType: `${process.cwd()}/src/application/appdelegates/actions/CommandActionType`,
CommandForResponseActionType: `${process.cwd()}/src/application/appdelegates/actions/CommandForResponseActionType`,
PluginRegistryService: `${process.cwd()}/src/default/PluginRegistryService`,
},
mode: 'development',
externals: [
'dcl',
'react',
'react-dom',
'prop-types',
'pubsub',
'semver',
'#appfabric/ui-profiler',
].map(
// Add this regex to each entry to ensure we don't miss any imports like 'web-shell-core/...`
(value) => new RegExp(`^(${value})((\\\\|/|!).+)?$`),
),
output: {
path: `${process.cwd()}/build/dist`,
filename: '[name].js',
library: 'web-shell-core',
libraryTarget: 'umd',
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
use: {
loader: 'babel-loader',
options: babelRC,
},
},
],
},
};
This is the webpack.config.js
const developmentConfig = require('./webpack.dev.config.js');
module.exports = merge(developmentConfig, {
mode: 'production',
output: {
filename: '[name].min.js',
chunkFilename: '[name].min.js',
},
});
First I add a new file Secure.jsx(having the tags) in the library. I do npm install --save <path-to-library> on my application. After I do yarn install. Then I can see the new file Secure.jsx in the node modules in the application. When I try to run the application, I get the error.
Please let me know what am I missing and also which side(library / application) I have to add the code.
You can view my full config here
I think you also need to add this
resolve: {
modules: [
path.resolve('./node_modules')
]
},
Then import like this
import "jquery/dist/jquery.min.js";
import "bootstrap/dist/js/bootstrap.min.js";

Configuring Webpack to Execute TypeScript + Mocha Tests

I'd like to configure webpack to transpile (mocha + chai) tests written in typescript to javascript and them execute them. To that end, I have the webpack.test.config.js file below. Note: I've currently configured webpack to use ts-loader and mocha-loader.
Unfortunately, when I execute webpack --config webpack.test.config.js --env.dev, I receive the error:
Module parse failed: Unexpected token (2:10) You may need an
appropriate loader to handle this file type.
How can resolve this error and achieve my aforementioned goal?
const path = require('path');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const outputPath = './bin/test';
module.exports = env => {
return {
mode: env && env.pro ? 'production' : 'development',
context: path.resolve('src'),
entry: {
core: './test/typescript/core.spec.ts'
},
output: {
filename: '[name].js',
path: path.join(__dirname, outputPath)
},
devtool: 'source-map',
plugins: [
new CleanWebpackPlugin({
dry: true,
cleanOnceBeforeBuildPatterns: ['./bin/test/**/*']
})
],
module: {
rules: [
{
test: /\.spec\.tsx?$/,
use: ['mocha-loader', 'ts-loader'],
exclude: /node_modules/
}
]
},
resolve: {
extensions: ['.tsx', '.ts', '.js']
}
};
};

Webpack - Excluding node_modules with also keep a separated browser and server management

(webpack.config.js file content below)
I'm trying to make a webpack exclusion on node modules.
I found that using webpack-node-externals works for it but using that on my common config causes this other error:
Require is not defined on reflect-metadata - __webpack_require__ issue
So... I was wondering how can i exclude webpack bundling also on the browser side without getting any issue.
My webpack version: 3.11.0
webpack-config.js
const path = require('path');
const webpack = require('webpack');
const merge = require('webpack-merge');
const AotPlugin = require('#ngtools/webpack').AotPlugin;
const CheckerPlugin = require('awesome-typescript-loader').CheckerPlugin;
var nodeExternals = require('webpack-node-externals');
module.exports = (env) => {
// Configuration in common to both client-side and server-side bundles
const isDevBuild = !(env && env.prod);
const sharedConfig = {
//externals: [nodeExternals()], // in order to ignore all modules in node_modules folder
stats: { modules: false },
context: __dirname,
resolve: { extensions: [ '.js', '.ts' ] },
output: {
filename: '[name].js',
publicPath: 'dist/' // Webpack dev middleware, if enabled, handles requests for this URL prefix
},
module: {
rules: [
{ test: /\.ts$/, use: isDevBuild ? ['awesome-typescript-loader?silent=true', 'angular2-template-loader', 'angular2-router-loader'] : '#ngtools/webpack' },
{ test: /\.html$/, use: 'html-loader?minimize=false' },
{ test: /\.css$/, use: [ 'to-string-loader', 'style-loader', isDevBuild ? 'css-loader' : 'css-loader?minimize' ] },
{ test: /\.(png|jpg|jpeg|gif|svg)$/, use: 'url-loader?limit=25000' }
]
},
plugins: [new CheckerPlugin()]
};
// Configuration for client-side bundle suitable for running in browsers
const clientBundleOutputDir = './wwwroot/dist';
const clientBundleConfig = merge(sharedConfig, {
entry: { 'main-client': './ClientApp/boot.browser.ts' },
output: { path: path.join(__dirname, clientBundleOutputDir) },
plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./wwwroot/dist/vendor-manifest.json')
})
].concat(isDevBuild ? [
// Plugins that apply in development builds only
new webpack.SourceMapDevToolPlugin({
filename: '[file].map', // Remove this line if you prefer inline source maps
moduleFilenameTemplate: path.relative(clientBundleOutputDir, '[resourcePath]') // Point sourcemap entries to the original file locations on disk
})
] : [
// Plugins that apply in production builds only
new webpack.optimize.UglifyJsPlugin(),
new AotPlugin({
tsConfigPath: './tsconfig.json',
entryModule: path.join(__dirname, 'ClientApp/app/app.browser.module#AppModule'),
exclude: ['./**/*.server.ts']
})
])
});
// Configuration for server-side (prerendering) bundle suitable for running in Node
const serverBundleConfig = merge(sharedConfig, {
resolve: { mainFields: ['main'] },
entry: { 'main-server': './ClientApp/boot.server.ts' },
plugins: [
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./ClientApp/dist/vendor-manifest.json'),
sourceType: 'commonjs2',
name: './vendor'
})
].concat(isDevBuild ? [] : [
// Plugins that apply in production builds only
new AotPlugin({
tsConfigPath: './tsconfig.json',
entryModule: path.join(__dirname, 'ClientApp/app/app.server.module#AppModule'),
exclude: ['./**/*.browser.ts']
})
]),
output: {
libraryTarget: 'commonjs',
path: path.join(__dirname, './ClientApp/dist')
},
target: 'node',
externals: [nodeExternals()], // in order to ignore all modules in node_modules folder,
devtool: 'inline-source-map'
});
return [clientBundleConfig, serverBundleConfig];
};
GOT IT!
Before posting my solution, I'd like to thanks Aluan Haddad for his useful comment in my question above.
As suggested by Aluan, in fact, the problem was related to the need to use also a module loader, more than a module bundler.
So, the steps that I followed are these:
Installing requireJS ==> http://requirejs.org/docs/node.html
Removing externals: [nodeExternals()], // in order to ignore all modules in node_modules folder from my common webpack configuration and adding it under my server configuration (done before my question, but it's a really important step) [see webpack.config.js content in the question]
Adding target: 'node', before my externals point above, under my server side section (done before my question, but it's a really important step) [see webpack.config.js content in the question]
This makes sure that browser side keeps target:'web' (default target), and target becomes node just for the server.
launched webpack config vendor command manually from powershell webpack --config webpack.config.vendor.js
launched webpack config command manually from powershell webpack --config webpack.config.js
That worked for me! Hope It will works also for anyone else reading this question and encountering this issue!

Webpack - module not found even though module exists

This is a branch off of my previous question and applied suggestions. But I am still having major issues.
I now have my babel transpiler, along with a .babelrc file in place. My import code to import my module looks like this:
var init = require('./app/js/modules/toc');
init();
However I'm getting this:
ERROR in ./app/js/script.js
Module not found: Error: Cannot resolve 'file' or 'directory' ./app/js/modules/toc in /projects/project-root/app/js
# ./app/js/script.js 1:11-42
Webpack config:
var debug = process.env.NODE_ENV !== "production";
var webpack = require('webpack');
module.exports = {
context: __dirname,
devtool: debug ? "inline-sourcemap" : null,
entry: "./app/js/script.js",
module: {
rules: [{
test: /\.js$/,
use: 'babel-loader'
}]
},
output: {
path: __dirname + "public/javascripts",
filename: "scripts.min.js"
},
plugins: debug ? [] : [
new webpack.optimize.DedupePlugin(),
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.optimize.UglifyJsPlugin({ mangle: false, sourcemap: false }),
],
};
.babelrc
{
"presets": ["es2015"]
}
Gulptask
//scripts task, also "Uglifies" JS
gulp.task('scripts', function() {
gulp.src('app/js/script.js')
.pipe(webpack(require('./webpack.config.js')))
.pipe(gulp.dest('public/javascripts'))
.pipe(livereload());
});
I'm totally lost...what am I doing wrong?
For my import code I also tried:
import {toc} from './modules/toc'
toc();
UPDATE: As recommended I needed to add resolve to my config. It looks like this now:
var debug = process.env.NODE_ENV !== "production";
var webpack = require('webpack');
module.exports = {
context: __dirname,
devtool: debug ? "inline-sourcemap" : null,
entry: "./app/js/script.js",
resolve: {
extensions: ['.js']
},
module: {
rules: [{
test: /\.js$/,
use: 'babel-loader'
}]
},
output: {
path: __dirname + "public/javascripts",
filename: "scripts.min.js"
},
plugins: debug ? [] : [
new webpack.optimize.DedupePlugin(),
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.optimize.UglifyJsPlugin({ mangle: false, sourcemap: false }),
],
};
Sadly I still get:
ERROR in Entry module not found: Error: Cannot resolve 'file' or
'directory' ./app/js/script.js in /projects/project-root
Does my file structure need to change?
Whenever you import/require a module without specifying a file extension, you need to tell webpack how to resolve it. This is done by the resolve section inside the webpack config.
resolve: {
extensions: ['.js'] // add your other extensions here
}
As a rule of thumb: whenever webpack complains about not resolving a module, the answer probably lies in the resolve config.
Let me know about any further questions and if this works.
EDIT
resolve directly to the root level of your config:
// webpack.config.js
module.export = {
entry: '...',
// ...
resolve: {
extensions: ['.js']
}
// ...
};
You are specifying an entry point in your webpack config AND in gulp. Remove the entry property in your webpack config.
If you specify it twice, the gulp config will tell webpack to get the file in ./app/js/script.jsand then webpack in ./app/js/script.js which will result in a path like ./app/js/app/js/script.js.
Keep us posted if you fixed it. =)
Given that your script is located at ./app/js/script.js and the requested module is there ./app/js/modules/toc, you would need to call it relatively to your script => ./modules/toc should work.
This is because both your script and module are located in the jsfolder.

Vue.js / webpack: how do I clear out old bundle main-*.js files when hot-reload transpiles them?

I'm using Vue.js to make an SPA application with Django and I transpile, uglify, and bundle the code using webpack (specifically webpack-simple from vue-cli setup).
I use the following to "watch" and hot-reload the code:
$ ./node_modules/.bin/webpack --config webpack.config.js --watch
The problem is every time I change the code and it gets built it generates a new bundle .js file and updates webpack-stats.json to point to that one, but doesn't delete the old ones. How do I have it delete the old (useless) files?
webpack.config.js:
var path = require("path")
var webpack = require('webpack')
var BundleTracker = require('webpack-bundle-tracker')
function resolve (dir) {
return path.join(__dirname, dir)
}
module.exports = {
context: __dirname,
// entry point of our app.
// assets/js/index.js should require other js modules and dependencies it needs
entry: './src/main',
output: {
path: path.resolve('./static/bundles/'),
filename: "[name]-[hash].js",
},
plugins: [
new BundleTracker({filename: './webpack-stats.json'}),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
},
sourceMap: true
}),
],
module: {
loaders: [
{ test: /\.jsx?$/, exclude: /node_modules/, loader: 'babel-loader'}, // to transform JSX into JS
{test: /\.vue$/, loader: 'vue-loader'}
],
},
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'#': resolve('src')
}
},
}
webpack-stats.json:
{
"status":"done",
"chunks":{
"main":[
{
"name":"main-faa72a69b29c1decd182.js",
"path":"/Users/me/Code/projectname/static/bundles/main-faa72a69b29c1decd182.js"
}
]
}
}
Also what's a good way to add this to git/source control? Otherwise it changes everytime and I have to add it like so:
$ git add static/bundles/main-XXXXX.js -f
which gets annoying.
Any pointers? Thanks!
You need clean-webpack-plugin github link
First install it:
npm i clean-webpack-plugin --save-dev
Then in webpack.config.js add these lines(I have added comments the lines I added):
var path = require("path")
var webpack = require('webpack')
var BundleTracker = require('webpack-bundle-tracker')
const CleanWebpackPlugin = require('clean-webpack-plugin'); // require clean-webpack-plugin
function resolve (dir) {
return path.join(__dirname, dir)
}
// the path(s) that should be cleaned
let pathsToClean = [
path.resolve('./static/bundles/'), // same as output path
]
// the clean options to use
let cleanOptions = {
root: __dirname,
exclude: [], // add files you wanna exclude here
verbose: true,
dry: false
}
module.exports = {
context: __dirname,
// entry point of our app.
// assets/js/index.js should require other js modules and dependencies it needs
entry: './src/main',
output: {
path: path.resolve('./static/bundles/'),
filename: "[name]-[hash].js",
},
plugins: [
new CleanWebpackPlugin(pathsToClean, cleanOptions), // add clean-webpack to plugins
new BundleTracker({filename: './webpack-stats.json'}),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
},
sourceMap: true
}),
],
module: {
loaders: [
{ test: /\.jsx?$/, exclude: /node_modules/, loader: 'babel-loader'}, // to transform JSX into JS
{test: /\.vue$/, loader: 'vue-loader'}
],
},
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'vue$': 'vue/dist/vue.esm.js',
'#': resolve('src')
}
},
}
And that's it, now every time you will run npm run build, the plugin will delete the static/bundles/ folder then build, so all your previous files will get removed, only new files will be there. It won't remove old files while watching with npm run watch
The current latest version does not need any options passed in for most cases. Consult the documentation for more specifics https://www.npmjs.com/package/clean-webpack-plugin
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const webpackConfig = {
plugins: [
/**
* All files inside webpack's output.path directory will be removed once, but the
* directory itself will not be. If using webpack 4+'s default configuration,
* everything under <PROJECT_DIR>/dist/ will be removed.
* Use cleanOnceBeforeBuildPatterns to override this behavior.
*
* During rebuilds, all webpack assets that are not used anymore
* will be removed automatically.
*
* See `Options and Defaults` for information
*/
new CleanWebpackPlugin(),
],
};
module.exports = webpackConfig;
You should adjust webpack so a new bundle is only being created when actually building for production.
From the webpack-simple vue-cli template, you'll see that uglifying and minifying only take place when it is set to a production env, not a dev env:
if (process.env.NODE_ENV === 'production') {
module.exports.devtool = '#source-map'
// http://vue-loader.vuejs.org/en/workflow/production.html
module.exports.plugins = (module.exports.plugins || []).concat([
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
new webpack.optimize.UglifyJsPlugin({
sourceMap: true,
compress: {
warnings: false
}
}),
new webpack.LoaderOptionsPlugin({
minimize: true
})
])
}

Categories