webpack 5 maxing out on RAM when bundling for karma tests - node.js

I recently updated webpack to version 5, and now when compiling a bundle for karma tests my system is maxing out of RAM and I get the JavaScript heap out of memory error. This happens both on my local machine that has 8gb RAM, and also on a gitlab runner hosted on digital ocean which has 4gb RAM.
Locally, if I kill all other apps, and set the memory allocation options node --max-old-space-size=4096 testscript.js I can sometimes get past the bundling, so I think it currently requires around 4gb+ RAM just to bundle, and this worries me. On the gitlab runner, linux terminates the docker container and I get the "killed" error
Before updating to weback 5 and therefore also before the memory issue my webpack configuration looked a bit differently, because webpack 5 doesn't include node libs by default, I have had to add some polyfills.
These are new in the configuration
crypto: false,
fs: false,
http: false,
path: require.resolve('path-browserify'),
stream: require.resolve('stream-browserify')
and these:
new webpack.ProvidePlugin({ Buffer: ['buffer', 'Buffer'] }),
new webpack.ProvidePlugin({ process: 'process/browser' }),
This is what the final webpack configuration for the karma bundling looks like:
const path = require('path');
const webpack = require('webpack');
const { excludeNodeModulesExcept } = require('../src/webpack/config');
const moduleListToTranspileForIE11 = ['debug', 'loader-utils', 'query-string', 'split-on-first', 'strict-uri-encode'];
const devModuleListToTranspileForIE11 = ['fetch-mock', 'proxy-polyfill', 'sinon', 'tr46', 'webidl-conversions', 'whatwg-url'];
module.exports = {
context: path.resolve(__dirname, '..'),
devtool: 'source-map',
entry: [
'./test/karma-webpack.main.js'
],
externals: {
'react/addons': true,
'react/lib/ExecutionEnvironment': true,
'react/lib/ReactContext': true
},
module: {
rules: [
{
test: /\.css$/,
use: [ 'css-loader', 'postcss-loader']
},
{
test: /\.js$/,
exclude: excludeNodeModulesExcept([].concat(devModuleListToTranspileForIE11, moduleListToTranspileForIE11)),
use: {
loader: 'babel-loader',
options: {
plugins: [
['#babel/plugin-transform-for-of', { assumeArray: true }]
],
presets: [
['#babel/preset-env', {}]
],
cacheDirectory: true // Note: for faster rebuilds
}
}
},
{
test: /\.svg$/,
loader: 'svg-react-loader'
}
]
},
mode: process.env.NODE_ENV || 'development',
resolveLoader: {
modules: [
'node_modules',
path.resolve(__dirname, '../src/webpack/loader')
]
},
output: {
path: path.resolve(__dirname, '../output/test'),
publicPath: '/',
filename: 'karma-webpack.js'
},
resolve: {
fallback: {
crypto: false,
fs: false,
http: false,
path: require.resolve('path-browserify'),
stream: require.resolve('stream-browserify')
}
},
performance: {
hints: false
},
plugins: [
new webpack.ProvidePlugin({ Buffer: ['buffer', 'Buffer'] }),
new webpack.ProvidePlugin({ process: 'process/browser' }),
new webpack.IgnorePlugin(/style\/demoHack\/\w+\.css/),
new webpack.IgnorePlugin(/app\.css/),
new webpack.IgnorePlugin(/config\/output\/build\/clientConfig\.json/),
new webpack.IgnorePlugin(/output\/local\/\w+\.json/)
]
};
The entry point ./test/karma-webpack.main.js looks like this:
require('./mocha.main');
var appReq = require.context('../src', true, /\.js$/);
appReq.keys().filter(function (key) {
return ['./react.main.js', './src/helper/polyfill.js'].indexOf(key) === -1 && !key.startsWith('./tool') && !key.startsWith('./src/test');
}).map(appReq);
// Only start mocha in browser.
if (!window.__karma__) {
window.mocha.run();
}
and is based on: https://github.com/FormidableLabs/full-stack-testing/blob/master/test/client/main.js
This seems to be including all mocha (file.test.js) files in the bundling, which makes it very slow, as those files also includes a lot of devDependencies. However, this was not a problem prior to the update. I have tried filtering out all files that are .test.js - then the bundling is fast, and I don't see any memory issues, however, karma is not running any tests then, the test suite is simply empty.
I am looking for advice with anything that could look suspicious about this configuration, and why it cannot bundle with less than 4gb memory available.

Related

Vite serves up jsx files in network traffic

I'm not sure what is going on but I have a very basic Vite setup, yet I'm seeing the local server serve up all my jsx files, which takes a good 10-15s when I do a fresh reload. At first I thought this just might be the way Vite works for development but even when trying to build for production it does the same thing and doesn't minimize or uglify the files but just serves the jsx as is.
enter image description here
The following is my vite.config.js. The commented out code is other things that I've tried with no success:
export default ({mode}) => {
return defineConfig({
root: 'app',
define: {global: 'window'},
// esbuild: {
// loader: "jsx",
// minify: true,
// minifySyntax: true,
// },
// optimizeDeps: {
// esbuildOptions: {
// minify: true,
// minifySyntax: true,
// loader: {
// ".js": "jsx",
// ".ts": "tsx",
// },
// },
// },
plugins: [react()],
// build: {
// outDir: '../dist',
// minify: true,
// },
server: {
host: '127.0.0.1',
port: 3000
}
})
};
I've tried numerous configuration options and tried every rollup/vite config option I could find on stack overflow and the internet. I'd expect vite to serve only the produced index.html and generated index.jsx file, not get all my source files as is.
This project originally did use webpack, but even then I wasn't doing anything special. Here is my webpack config incase that's helpful:
const path = require('path');
const webpack = require('webpack');
module.exports = {
mode: 'development',
devtool: 'eval-source-map',
entry: [
'webpack-dev-server/client?http://vesta-dev.localhost.com:3000',
'webpack/hot/dev-server',
'react-hot-loader/patch',
path.join(__dirname, 'app/index.js')
],
output: {
path: path.join(__dirname, '/dist/'),
filename: '[name].[hash].js',
publicPath: '/'
},
plugins: [
new webpack.ProvidePlugin({
process: 'process/browser',
}),
new webpack.DefinePlugin({
...
})
],
module: {
rules: [
{
enforce: 'pre',
test: /\.js$/,
exclude: [/node_modules/, /__tests__/],
loader: 'eslint-loader',
options: {
configFile: path.resolve(__dirname, '.eslintrc'),
failOnWarning: false,
failOnError: false,
emitError: false,
emitWarning: true
}
},
{
test: /\.js?$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
cacheDirectory: true,
plugins: ['react-hot-loader/babel']
}
},
{
test: /\.css$/,
use: [ 'style-loader', 'css-loader' ]
},
{
test: /\.scss$/,
use: ['style-loader','css-loader','sass-loader?modules&localIdentName=[name]---[local]---[hash:base64:5]']
},
{ test: /\.(jpe?g|png|gif)$/i, loader: 'file-loader' },
{
test: /\.woff(2)?(\?[a-z0-9#=&.]+)?$/,
loader: 'url-loader',
options: {
limit: '10000',
mimetype: 'application/font-woff'
}
},
{ test: /\.(ttf|eot|svg)(\?[a-z0-9#=&.]+)?$/, loader: 'file-loader' },
]
}
};
Looks like this is normal for when you use vite serve as that always serves the development environment, no matter what flags you set or command line options you pass in.
I thought it was interesting that no one talks about the jsx files actually being served in the network traffic and even with all my searching never came across anyone talking about this, nor in the Vite documents so I thought something was wrong.

Cannot find module "fs" - at webpackMissingModule

My server starts and runs correctly, but when I hit the URL in the browser it gives an error "cannot find module 'fs'".
I tried to setting:
target: 'node', but it starts another error
node: { fs: 'empty' }, but then it gives an error "cannot find exports"
"use strict";
const webpack = require('webpack');
const argv = require('minimist')(process.argv.slice(2));
const DEBUG = !argv.release;
const path = require('path');
var plugins = [
new webpack.optimize.CommonsChunkPlugin({
names: ['common', 'vendors'],
filename: '[name].js',
minChunks: Infinity
}),
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.DefinePlugin({
'process.env.NODE_ENV': DEBUG ? '"development"' : '"production"',
"process.argv.verbose": !!DEBUG
}),
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
jquery: "jquery"
})
].concat(DEBUG ? [] : [
new webpack.optimize.DedupePlugin(),
new webpack.optimize.UglifyJsPlugin({
minimize: true,
compress: {
warnings: true
}
}),
new webpack.optimize.AggressiveMergingPlugin()
]);
module.exports = {
entry: {
app: path.join(__dirname, '..', 'app', 'app.js'),
vendors: [
'react',
'react-dom',
'react-bootstrap',
'react-router',
'alt',
'lodash',
'superagent',
'react-router-role-authorization',
'react-validation-decorator'
]
},
output: {
publicPath: '/js/',
path: './wwwroot/js/',
filename: '[name].js',
chunkFilename: "[id].[name].js"
},
context: path.join(__dirname, '..'),
plugins: plugins,
cache: DEBUG,
debug: DEBUG,
watch: DEBUG,
stats: {
colors: true
},
resolve: {
extensions: ['', '.webpack.js', '.web.js', '.js', '.jsx', '.json']
},
module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loaders: ['babel-loader']
},
{
test: /\.(less|css)$/,
loaders: ["style", "css", "less"]
},
{
test: /\.(png|jpg|jpeg|gif|svg|woff|woff2)$/,
loader: 'url-loader?limit=10000'
},
{
test: /\.(eot|ttf|wav|mp3|mp4)$/,
loader: 'file-loader'
},
{
test: /\.json$/,
loader: 'json-loader'
}
]
},
node: {
net: 'mock',
dns: 'mock'
}
};
It should not give this error and work correctly.
I don't see any mention of the fs module in your posted webpack setup. So, my guess is that your output application (app.js?) is trying to require and use fs. Webpack is building a client-side, front-end application, one that will be loaded in the browser; fs is not available in the browser.
(Double-check and make sure you aren't trying to, for example, read and write files on the user's machine using fs inside your client-side application. That is not possible in a browser-based application. For an intro to the concept of web applications with a front end and back end, check out the article React App With Node Backend.)

Webpack 2: can't resolve node.js native modules

After bundling I have following errors:
Module not found: Error: Can't resolve 'crypto' in //filePath
It can't resolve five modules: crypto, fs, path, vm and constants - from any file which requires them
I thought it could be because of nvm which I use, but I switched to system nodejs via nvm use system command and webpack still throws these errors.
I also thought it could be target property, so I changed it to node, but it didn't help too (anyway I need electron-renderer, not node).
Important note: I've just migrated from webpack 1. It all works well before I migrated. But these are the only errors I have. Moreover, webpack seems to work fine, it even watches files when I pass --watch option.
Here is my webpack.config.js:
const config = {
target: 'electron-renderer',
context: __dirname,
entry: { app: './app.js', vendor: [/*vendors*/]},
cache: true,
devtool: 'source-map',
watch: false
resolve: {
extensions: ['.js', '.json', '.jsx'],
modules: ["node_modules"]
},
module: {
rules: [
{test: /\.html/, loader: 'html-loader'},
{
test: /\.less$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: ["css-loader?sourceMap", "less-loader?sourceMap"]
})
},
{
test: /\.css/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: "css-loader?sourceMap"
})
},
{test: /\.(jpg|png|gif|jpeg|svg|otf|ttf|eot|woff)$/, loader: 'url-loader?limit=10000'}
]
},
plugins: [
new ExtractTextPlugin('styles.[contenthash].css'),
new webpack.optimize.CommonsChunkPlugin({
names: ['commons', 'vendor', 'manifest'],
minChuncks: Infinity
}),
new HtmlWebpackPlugin({
template: './index.html',
filename: 'index.html',
hash: false,
inject: 'head',
cashe: true,
showErrors: true
})
],
output: {
publicPath: './',
path: path.join(__dirname, 'dist'),
filename: '[name].[chunkhash].js',
chunkFilename: '[name].[chunkhash].js'
}
};
module.exports = config;
The problem was in worker-loader, which is not in my webpack.config.js (I used it directly when importing file). See this issue for details (not fixed yet).

Why webpack gives an error for about NODE_ENV?

I am using webpack+react+redux on a web application. And I am using webpack-dev-server to launch dev web server. When I access my application on a browser, it gives below error messages on the console:
Warning: It looks like you're using a minified copy of the development build of React. When deploying React apps to production, make sure to use the production build which skips development warnings and is faster.
You are currently using minified code outside of NODE_ENV === 'production'. This means that you are running a slower development build of Redux. You can use loose-envify to ensure you have the correct code for your production build.
Below is my webpack.config.js file. I didn't specify production mode, why webpack gives me such warning message? And how can I get rid of it?
const webpack = require('webpack');
const path = require('path');
const NpmInstallPlugin = require('npm-install-webpack-plugin');
const WebpackShellPlugin = require('webpack-shell-plugin');
var CompressionPlugin = require("compression-webpack-plugin");
const PATHS = {
react: path.join(__dirname, 'node_modules/react/dist/react.min.js'),
app: path.join(__dirname, 'src'),
build: path.join(__dirname, './dist')
};
module.exports = {
entry: {
app: './app/index.jsx',
android: './app/utils/platform_android.js',
ios: './app/utils/platform_ios.js',
web: './app/utils/platform_web.js',
vendor: [
'axios',
'react',
'react-dom',
'react-redux',
'react-router',
'react-router-redux',
'redux',
'redux-thunk',
'react-alert',
'sha1',
'moment',
'nuka-carousel',
'react-cookie',
'material-ui',
'react-spinkit',
'react-tap-event-plugin',
'react-tappable',
],
},
output: {
path: PATHS.build,
filename: '[name].bundle.js',
},
watch: true,
devtool: 'source-map',
relativeUrls: true,
resolve: {
extensions: ['', '.js', '.jsx', '.css', '.less'],
modulesDirectories: ['node_modules'],
alias: {
normalize_css: __dirname + '/node_modules/normalize.css/normalize.css',
}
},
module: {
preLoaders: [
{
test: /\.js$/,
loader: "source-map-loader"
},
// {
// test: /\.js$/,
// exclude: /node_modules/,
// loader: 'jshint-loader'
// }
],
loaders: [
{
test: /\.html$/,
loader: 'file?name=[name].[ext]',
},
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'babel-loader?presets=es2015',
},
{
test: /\.less$/,
loader: "style!css!less",
},
{test: /\.css$/, loader: 'style-loader!css-loader'},
{test: /\.png$/, loader: "url-loader?limit=100000"},
{
test: /\.js$/,
exclude: /node_modules/,
loaders: ['babel-loader?presets=es2015']
},
{
test: /\.svg$/,
loader: 'svg-sprite',
include: /public\/icons/
}
]
},
plugins: [
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false,
},
output: {
comments: false,
},
}),
new NpmInstallPlugin({
save: true // --save
}),
new CompressionPlugin({
asset: "[path].gz[query]",
algorithm: "gzip",
test: /\.js$|\.html$/,
threshold: 10240,
minRatio: 0.8
}),
new webpack.optimize.CommonsChunkPlugin(/* chunkName= */["vendor"], /* filename= */"[name].bundle.js", Infinity),
],
devServer: {
colors: true,
contentBase: __dirname,
historyApiFallback: true,
hot: true,
inline: true,
port: 9093,
progress: true,
stats: {
cached: false
}
}
}
EDIT1:
I removed this line:
react: path.join(__dirname, 'node_modules/react/dist/react.min.js'),
Then updated the NODE_ENV to development as below:
new webpack.DefinePlugin({
"process.env": {
NODE_ENV: JSON.stringify("development")
}
})
Then I still got the same warning.
warning.js:14You are currently using minified code outside of NODE_ENV === 'production'. This means that you are running a slower development build of Redux. You can use loose-envify (https://github.com/zertosh/loose-envify) for browserify or DefinePlugin for webpack (http://stackoverflow.com/questions/30030031) to ensure you have the correct code for your production build.
I don't know how to say it more clear than webpack does...
You are not in a production build mode, but using a minified version of React. Use a non-minified one, so replace
react: path.join(__dirname, 'node_modules/react/dist/react.min.js'),
with
react: path.join(__dirname, 'node_modules/react/dist/react.js'),
or whatever place where you have your react not minified.
And this is not an error - it is a warning, so you can still work with this one.
Just another thing by the way: path.join adds proper slashes for each operating system. What you do here is
path.join(__dirname, 'node_modules/react/dist/react.min.js')
when you should go with
path.join(__dirname, 'node_modules', 'react', 'dist', 'react.min.js')
This is how the path should be properly used
The warning you get now is because you are letting Webpack minify your build, but you are still setting NODE_ENV to development.
If you use UglifyJsPlugin you should always set NODE_ENV to production. If you're not building for production, remove UglifyJsPlugin to not get any warnings.
Webpack, React and Redux try to give you some best practice hints here. In development mode (NODE_ENV not set to production), they all give more warnings and have lower performance. When you minify them they assume you're running a production build. For production builds, they really expect NODE_ENV to be set correctly.
So in short:
Production builds: set NODE_ENV to production and use UglifyJsPlugin.
Dev builds: set NODE_ENV to development and don't use any minification plugins.
I fixed it by removing below configuration from webpack.config.js for development build. It seems that this plugin will compress the js code which is not suitable for development mode.
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false,
},
output: {
comments: false,
},
})

"npm run" hanging on ts-loader (webpack)

I am building a web app that consists of static HTML and other assets using webpack on Mac OS X 10.11.3. The app talks to an API that is on another server.
I am having trouble building my app using webpack. The build process appears to hang at or around the ts-loader execution. I am running my build like this:
npm run go --loglevel verbose
which executes this command from my package.json:
./node_modules/.bin/webpack-dev-server --display-reasons --display-chunks --watch
The output in the Terminal window ends with
ts-loader: Using typescript#1.7.5 and /Users/mn/Documents/source/J/appstore/store-front/app/ts/tsconfig.json
I have tried deleting the node_modules folder and reinstalling these; I have tried uninstalling webpack and reinstalling; I have tried reverting my webpack.config.js to a version I know works; but it just hangs here!
My webpack.config.js looks like this:
var webpack = require('webpack'),
ReloadPlugin = require('webpack-reload-plugin'),
path = require('path'),
ChunkManifestPlugin = require('chunk-manifest-webpack-plugin'),
HtmlWebpackPlugin = require('html-webpack-plugin'),
WebpackNotifierPlugin = require('webpack-notifier'),
ExtractTextPlugin = require("extract-text-webpack-plugin");
/**
* optimist has been depracted. Find an alternative? minimist?
*/
var argv = require('optimist')
.alias('r', 'release').default('r', false)
.argv;
/**
* Useful variables
*/
var cwd = process.cwd();
var DEBUG = !argv.release;
var isDevServer = process.argv.join('').indexOf('webpack-dev-server') > -1;
var version = require(path.resolve(cwd, 'package.json')).version;
var reloadHost = "0.0.0.0";
var npmRoot = __dirname + "/node_modules";
var appDir = __dirname + "/app";
var entry = ["./app/ts/bootstrap"]
if (isDevServer) {
entry.unshift("webpack-dev-server/client?http://" + reloadHost + ":8080");
}
function makeConfig(options) {
return {
cache: true,
debug: true,
verbose: true,
displayErrorDetails: true,
displayReasons: true,
displayChunks: true,
context: __dirname,
entry: {
app: entry,
vendor: './app/ts/vendor.ts'
},
stats: {
colors: true,
reasons: DEBUG
},
devtool: 'source-map',
recordsPath: path.resolve('.webpack.json'),
devServer: {
inline: true,
colors: true,
contentBase: path.resolve(cwd, "build"),
publicPath: "/"
},
output: {
path: path.resolve(cwd, "build"),
filename: "[name].js",
publicPath: "/",
chunkFilename: "[id].bundle.js",
// Hot Module Replacement settings:
hotUpdateMainFilename: "updates/[hash].update.json",
hotUpdateChunkFilename: "updates/[hash].[id].update.js"
},
plugins: [
new webpack.IgnorePlugin(/spec\.js$/),
new webpack.optimize.CommonsChunkPlugin({ name: 'vendor', filename: 'vendor.js', minChunks: Infinity }),
new webpack.optimize.CommonsChunkPlugin({ name: 'common', filename: 'common.js', minChunks: 2, chunks: ['app', 'vendor'] }),
new ExtractTextPlugin("styles.css"),
new webpack.DefinePlugin({
VERSION: JSON.stringify(version),
ENV: JSON.stringify(options.env)
}),
new HtmlWebpackPlugin({
template: path.join(appDir, "index.html"),
}),
new ReloadPlugin(isDevServer ? 'localhost' : ''),
new WebpackNotifierPlugin({
title: "Jisc AppStore App"
}),
],
resolveLoader: {
root: path.join(__dirname, 'node_modules'),
modulesDirectories: ['node_modules'],
fallback: path.join(__dirname, "node_modules")
},
resolve: {
root: [path.resolve(cwd)],
modulesDirectories: [
'node_modules', 'app', 'app/ts', '.'
],
extensions: ["", ".ts", ".js", ".json", ".css"],
alias: {
'app': 'app',
'scripts': npmRoot
}
},
module: {
preLoaders: [
{ test: /\.ts$/, loader: "tslint" }
],
loaders: [
{ test: /\.(png|jp?g|gif)$/, loaders: ["url", "image"] },
{ test: /\.json$/, loader: 'json' },
{ test: /^(?!.*\.min\.css$).*\.css$/, loader: ExtractTextPlugin.extract("style-loader", "css-loader?sourceMap") },
{ test: /\.scss$/, loaders: ['style', 'css?sourceMap', 'sass?sourceMap'] },
å { test: /\.html$/, loader: "html" },
{ test: /\.ts$/, loader: 'ts', exclude: [/test/, /node_modules/] },
{ test: /vendor\/.*\.(css|js)/, loader: 'file-loader?name=[path][name].[ext]', exclude: [/node_modules/] },
{ test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: "file-loader?limit=10000&minetype=application/font-woff" },
{ test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: "file-loader" }
],
noParse: [
/\.min\.js/,
/vendor[\/\\].*?\.(js|css)$/
]
},
tslint: {
emitErrors: false,
failOnHint: false
}
}
}
var config = makeConfig(argv)
console.log(require('util').inspect(config, { depth: 10 }))
module.exports = config;
My tsconfig.json looks like this:
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"removeComments": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"noEmitHelpers": false,
"sourceMap": true
},
"filesGlob": [
"./app/**/*.ts",
"!./node_modules/**/*.ts"
],
"compileOnSave": false,
"buildOnSave": false
}
Can anyone suggest what might be happening? I don't seem to be able to produce any logs from either the webpack dev server or the npm build.
After hours of reverse-engineering ts-loader I finally found out what was causing this "freeze" (as it may seem) in my case:
I am building a web scraper and had amassed around 40Gb of cached data in a hashed directory structure between the previous, successful deployment and the now failing/freezing deployment.
Turned out, since I'd forgotten to include the root cache directory in the "exclude" option in my tsconfig.json, ts-loader was going through all sub-folders in the cache directory. So, it wasn't actually hanging, it was just looking through millions of files.
When I added the cache directory to the excluded files option, everything went back to normal.
Hope this helps you with your issue. In case you want to look into what's going on with typescript, I'd recommend to experiment with some console.logs in the visitDirectory-function in typescript.js. This was what finally helped me resolve this problem.
Cheers
Sam

Resources