Webpack using perf_hooks for node/browser module - node.js

I'm making a module that I would like to be available in the browser and Node. It relies on performance, which is giving me trouble with Webpack and the perf_hooks module in Node. No matter what I do I can only get it where it works in one or the other, but not both.
Below are most of the things I've tried. My question is, how do I configure Webpack to require perf_hooks in node, but use the built in performance global when in the browser?
Here is my base Webpack config:
const path = require('path');
module.exports = {
entry: './src/UpdateLoop.js',
mode: 'development',
output: {
library: 'UpdateLoop',
libraryTarget: 'umd',
path: path.resolve(__dirname, 'dist'),
filename: 'updateloop.js',
globalObject: 'this',
},
};
Code thats giving me trouble:
const { performance } = require('perf_hooks');
This errors in webpack with:
Field 'browser' doesn't contain a valid alias configuration
resolve as module
C:\Users\joe.jankowiak\projects\update-loop\src\node_modules doesn't exist or is not a directory
I've seen suggestions for 'fs' to do the following:
// configuration.node has an unknown property 'perf_hooks'
node: {
perf_hooks: false,
},
// configuration has an unknown property 'browser'.
browser: {
perf_hooks: false,
},
I then saw people recommending using 'resolve':
// Compiles, but complains performance doesn't exist in node or browser.
resolve: {
fallback: {
perf_hooks: false,
}
},
// Works in browser but doesn't work in node. Node complains about using performance before its defined:
performance = performance || require('perf_hooks').performance;
// Doesn't work in either
const performance = performance || require('perf_hooks').performance;
// Trying to check if its node, but with resolve its making perf_hooks null in node
if(typeof __webpack_require__ === 'function') {
global.performance = require('perf_hooks').performance;
}

I ended up doing this out of laziness because I still don't quite understand how to use NodeJS functions with Webpack:
function portableMsecTimer () {
if (process.hrtime) {
return Number(process.hrtime.bigint()) / 1e6;
} else {
return window.performance.now();
}
}

Related

Using crypto.randomInt() in React

I am trying to use crypto.randomInt() Nodejs API in a project bootstrapped with create-react-app that uses Webpack 5. I have tried multiple options like this so far:
// webpack.config.js
module.exports = {
resolve: {
fallback: { crypto: require.resolve('crypto-browserify') },
}
};
And then, npm i crypto-browserify as recommended by the error message.
// Returns Uncaught TypeError: randomInt is not a function
const { randomInt } = import('crypto');
console.log(randomInt(4));
From some threads, I tried:
// package.json
...
"browser": {
"crypto": false
}
...
Still, no luck. I tried import {randomInt} from 'crypto-browserify'. This didn't work either.
What should I do to make this work?

How can I debug this Webpack error - ERROR in bundle.js from Terser

I am trying to use webpack to bundle up a Node JS project, for the benefits it offers in terms of minimising the size of the code etc. and bundling together all of the dependencies.
My webpack job is failing with the following error:
ERROR in bundle.js from Terser
Invalid function parameter [bundle.js:186393,23]
This is my webpack.config file:
const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
target: "node",
mode: "production",
entry: {
app: ["./src/vitaq_client.js"]
},
// https://webpack.js.org/configuration/node/
// node: {
// global: false,
// __filename: true,
// __dirname: true,
// },
module: {
// https://github.com/ivan-aksamentov/reactlandia-bolerplate-lite/issues/5#issuecomment-413306341
exprContextCritical: false,
rules: [
{
test: /\.node$/,
use: 'node-loader'
},
{
test: /coffee/,
use: 'node-loader'
},
{
test: /\.coffee$/,
use: [ 'coffee-loader' ]
},
// {
// test: /\.map$/,
// use: ["source-map-loader"],
// enforce: "pre"
// },
]
},
plugins: [
new CleanWebpackPlugin(),
],
output: {
path: path.resolve(__dirname, "./build"),
filename: "bundle.js"
},
};
and this is the command I am using to run it:
webpack --config webpack.config.js
From the searching I have done it seems that there is a Terser plugin for code minification, but as you can see from my config file I am not loading that plugin, so does webpack use that plugin by default? If not how could I be getting an error from Terser ?
If I set the mode to "development" in the config file, then I do not get the problem, but I suspect that is because development code would not get minified.
I am a bit stuck as to how I set about debugging this problem - are there ways of getting more output from Webpack. I have tried using the --json > compilation-stats.json command line argument when I invoke webpack, but I get a huge output file (43Mb) and I can't find anything in all of that to help.
Any suggestions would be gratefully received.
This is an error with assignment where you have an invalid function parameter at the given line of bundle.js.
You can solve this by not minimizing the webpack build:
optimization: {
minimize: false
}
Then finding the assignment error line from the error output, in the non minified bundle.
Invalid function parameter [bundle.js:186393,23]
Hope this helps someone else.

Module not found: Error: Can't resolve 'fs' Using Webpack

Hi im using socket io in my application. Which is requiring fs. when i try to bundle my javascript using below webpack config. im getting error can not resolve 'fs'.
Module not found: Error: Can't resolve 'fs' in 'my application path/node_modules/socket.io/lib'
i found by adding target:'node' and node:{fs:'empty'}. this issue got resolved.
But there is an issue in sass-loader. Getting below error.
ERROR in javascript/bundle.js from UglifyJs
Unexpected token: name (zlibLimiter) [javascript/bundle.js:60019,4]
Child extract-text-webpack-plugin ../../../node_modules/extract-text-webpack-plugin/dist ../../../node_modules/css-loader/index.js??ref--2-2!../../../node_modules/sass-loader/lib/loader.js!s
running the application ignoring above error. getting below error.
external "crypto":1 Uncaught ReferenceError: require is not defined
at Object.__decorate (external "crypto":1)
at __webpack_require__ (bootstrap 93620a17882f7a2aa1d3:19)
at Object.byteToHex (rng.js:4)
at __webpack_require__ (bootstrap 93620a17882f7a2aa1d3:19)
Below is my webpack config and versions. Can some one please help me to resolve this issue.
"webpack": "~3.6.0",
npm -v 5.8.0
node -v v8.4.0
const webpack = require('webpack');
const env = process.env.NODE_ENV;
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const path = require('path');
const extractSass = new ExtractTextPlugin({
filename: 'css/[name].css',
allChunks: false
});
let output = {
path: __dirname + '/src/main/resources/static/',
filename: 'javascript/[name].js'
};
if (env === 'debug' || env === 'nondev') {
output = {
path: __dirname + '/target/classes/static/',
filename: 'javascript/[name].js'
};
}
let config = {
context: __dirname + '/app/js/src',
entry: {
bundle: './index.jsx',
application: './static/scss/application.scss',
'application-pdap': './static/scss/application-pdap.scss'
},
output: output,
devtool: 'cheap-module-source-map',
module: {
rules: [
{
test: /.jsx?$/,
loader: 'babel-loader',
exclude: /node_modules/,
query: {presets: ['es2015', 'react']}
},
{
test: /\.(woff|woff2|eot|ttf|svg|png|jpg|gif)$/,
loader: 'file-loader?limit=1024&name=images/[name].[ext]'
},
{
test: /\.(scss|css)$/,
include: [path.resolve(__dirname, 'app/js/src/static/scss')],
use: ExtractTextPlugin.extract({
publicPath: '../',
use: [
{
loader: 'css-loader',
options: {
minimize: true,
sourceMap: false
}
},
{loader: 'sass-loader'}
],
fallback: 'style-loader'
})
}
]
},
plugins: [extractSass],
};
if (env === 'production' || env === 'nondev') {
config.devtool = 'nosources-source-map';
config.plugins.push(
new webpack.DefinePlugin({
'process.env': {NODE_ENV: '"production"'}
})
);
config.plugins.push(new webpack.optimize.UglifyJsPlugin({
compress: {warnings: false},
comments: false,
sourceMap: false,
minimize: false
}));
}
module.exports = config;
The solution depends on the type of application you want to build. Usually front-end and back-end JavaScript code are bundled separately, effectively creating two output bundles.
Front-end
For a frontend/web project, add the socket.io client libary to your app bundle. There is no need to include any node dependencies (fs) or mock entries like node: { fs:'empty' }. You can choose target:'web' or leave it out, as it is the default.
Back-end
Pick target:'node' and install socket.io server library. You do not need to specify externals: ["fs"] as shown in the other answer, because target: 'node' will take care of not bundling path, fs and other built-in modules.
Better avoid npm i fs - this is a needless escape hatch and a security risk. There have already happened cases of malicious npm packages with common package names.
You could even deliberate about, wether a node backend bundle is needed at all. An alternative is to install webpack-node-externals, which treats either all or specific npm packages as "externals" and excludes them from the bundle:
var nodeExternals = require('webpack-node-externals');
module.exports = {
target: 'node', // ignore built-in modules like path, fs, etc.
externals: [nodeExternals()], // ignore all modules in node_modules folder
// ...
};
This makes sense for the back-end, as all dependencies are installed in node_modules at server start time and don't need to be included in the bundle.
Exclude files from loaders
To exclude files from certain loaders and their transformations, you can use exclude module rule. An example is to omit node_modules from babel-loader transformations:
{ test: /\.(jsx|js)$/, exclude: /node_modules/, loader: "babel-loader" }
Further reading
Just install fs (npm i fs), and add at your webpack config
externals: ["fs"],
If someone is still facing this issue, you can try the following workaround. Update your webpack file to including the following configuration:
node: {
fs: 'empty',
}
We had a similar issue within our project and adding this specific configuration resolved the 'fs' related error in webpack.
It's also worth checking the version of Webpack version. we had to revert back the webpack and webpack cli versions to 4.0.0 and 4.2.0 respectively.

How to include Mongoose/MongoDB in an Express.JS-App (the ES2015 way)

I am trying to include mongoose/mongodb in my Express.JS app (the ES2015 way).
First, I have the main file:
import path from 'path'
import express from 'express'
import mongoose from 'mongoose'
mongoose.connect('mongodb://localhost/timelines')
const app = express()
app.use(express.static('dist/client/'))
app.get('*', (req, res) => {
res.sendFile(path.resolve('dist/client/index.html'))
})
app.listen(3000)
Then the error message:
[nodemon] starting `node dist/server/app.js`
undefined:8
driver = !(function webpackMissingModule() { var e = new Error("Cannot find module \".\""); e.code = 'MODULE_NOT_FOUND';; throw e; }());
^
Error: Cannot find module "."
My webpack config:
export default [
{
entry: './src/server/app.js',
target: 'node',
output: {
path: './dist/server',
filename: 'app.js'
},
module: {
loaders: [
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
loader: 'babel-loader',
query: {
presets: ['es2015']
}
}
]
}
},
{
entry: './src/client/app.js',
output: {
path: './dist/client',
filename: 'app.js'
},
module: {
loaders: [
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
loader: 'babel-loader',
query: {
presets: ['es2015', 'stage-2', 'react']
}
}
]
}
}
]
Now, the interesting part:
Before I added
import mongoose from 'mongoose'
mongoose.connect('mongodb://localhost/timelines')
everything worked fine!!
Any thoughts how this problem can be fixed?
EDIT 1:
webpack throws a warning:
WARNING in ./~/es6-promise/dist/es6-promise.js
Module not found: Error: Can't resolve 'vertx' in '/Users/timo/Desktop/Timelines/node_modules/es6-promise/dist'
# ./~/es6-promise/dist/es6-promise.js 131:20-30
# ./~/mongodb/lib/mongo_client.js
# ./~/mongodb/index.js
# ./~/mongoose/lib/index.js
# ./~/mongoose/index.js
# ./src/server/app.js
I ran into the same issue, and there were a few key steps in order to resolve it.
Firstly, please check that you have the version of MongoDB server installed that Mongoose is expecting:
Mongoose MongoDB NodeJS driver compatibility
The root cause of the issue is that Webpack is trying to resolve a dynamic require to load the MongoDB NodeJS driver:
if (typeof window === 'undefined') {
driver = require(global.MONGOOSE_DRIVER_PATH || './node-mongodb-native');
} else {
driver = require('./browser');
}
We need to instruct webpack to ignore all external imports as we don't need to bundle them, since they will never be sent down to the client.
We can do that by adding the following webpack config:
module.exports = {
// tell webpack that it is building for the NodeJS environment
...
target: 'node',
output: {
...
// we want the output to use simple require calls for imports as
// nodejs would expect
libraryTarget: 'commonjs'
},
...
externals: [
// consider everything imported from a non-relative path an external
// this will flag everything such as:
// import express from 'express'
// or
// import mongoose from 'mongoose'
/^(?!\.|\/).+/i
]
}
When you run your build again and start up the resultant bundle, you shouldn't receive the cryptic error message from Webpack any longer and find that your server is now running as expected.
I think you're missing a semicolon. Just kidding. (But seriously, if you're not using semicolons then you will experience problems if you're not 100% sure what you're doing. At least lint your code according to eslint-config-npm to make sure that you're not missing a semicolon where it actually matters.)
Make sure that you installed the mongoose module correctly with its dependencies and that you include everything needed in webpack. It looks like some code is trying to import '.' and cannot do it - for example there's no package.json or incomplete package.json there.

Node, Webpack and React Routing using FS filesystem

I want to read and write a file using NodeJS default fs module.
I've almost tried everything I can find on the internet. ES6 and CommonJS examples, editing the Webpack.config file, added packages that should add Promises and so on.. But nothing seems to work out.
Currently this is my webpack.config.js
var webpack = require('webpack');
module.exports = {
entry: './index.js',
output: {
path: 'public',
filename: 'bundle.js',
publicPath: ''
},
node: {
fs: "empty"
},
"browser": { "fs": false },
resolve: {
modulesDirectories: ['web_modules', 'bower_components', 'node_modules']
},
module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader?presets[]=es2015&presets[]=react'
}
]
}
}
As I've mentioned some lines suggested in this topic where added.
I want to use the fs.readFile in the component shown below:
var React = require('react');
var fs = require('fs');
var QuestionList = React.createClass({
handleVote: function(id, state) {
var file = '../public/api/questions';
fs.readSyncFile(file, function(err, data) {
console.log( err );
console.log( data );
});
},
render() {
var rows = []
this.state.questions.forEach( function(question) {
rows.push(
<QuestionItem
onVoteUpdate={this.handleVote}
key={question.id}
up={question.upvotes} down={question.downvotes}
/>
);
}.bind(this));
return (
<section>
<ul className="question-list">{rows}</ul>
</section>
)
}
});
module.exports = QuestionList;
I've removed some functions, like loading the question with jQuery and set the InitialState, for this example.
I'll can imagine webpack can't build any back-end tasks like FS in an front-end js file or something like that, but how is it possible to read and write files using Node, Webpack and React? Is this even possible?
You can't use fs in a front-end JS file, as far as I know, as you don't have access to the filesystem from the browser (it looks like you might be expecting the readFileSync call to get run during Webpack's compilation - this isn't how it works!). You either need a Webpack loader of some kind to make it so you can require() the file, or you'll have to load it via AJAX.

Resources