Webpack final bundle size is too big - node.js

Making build using webpack 4.9.1 using npm run build
Package.json file command
"build": "webpack --mode production --config webpack.config.prod.js",
After build my bundle size is 1010 KiB which is too huge. trying to figure out since day but no success so finally putting here
webpack.config.prod.js
var path = require('path');
var webpack = require('webpack');
var CopyWebpackPlugin = require('copy-webpack-plugin');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
mode: 'production',
devtool: 'none',
entry: {
index: './src/index.js',
},
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js',
publicPath: '/'
},
optimization: {
minimize: true,
},
plugins: [
new webpack.LoaderOptionsPlugin({ options: {} }),
new webpack.optimize.AggressiveMergingPlugin(),
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
new CopyWebpackPlugin([
{
from: 'style.css',
},
{
from: 'bootstrap.min.css',
},
{
from: 'index.html',
}
]),
new BundleAnalyzerPlugin(),
],
module: {
noParse:[ /node_modules\/localforage\/dist\/localforage.js/],
rules: [
{
test: /\.js$/,
enforce: "pre",
loaders: ['eslint-loader'],
include: path.join(__dirname, 'src')
},
{
test: /\.js$/,
loaders: ['babel-loader'],
include: [path.join(__dirname, 'src'), path.join(__dirname, 'translations')]
},
{
// do not exclude node_modules, since map.json is in node_modules
test: /\.json$/,
loader: 'json'
},
{
test: /\.css$/,
loaders: [ 'style-loader', 'css-loader' ]
},
]
}
};
my .babelrc looks like below
{
"presets": ["react", "es2015", "stage-2"],
"env": {
"development": {
"plugins": [
["react-transform", {
"transforms": [{
"transform": "react-transform-hmr",
"imports": ["react"],
"locals": ["module"],
"preventFullImport": true
}, {
"transform": "react-transform-catch-errors",
"imports": ["react", "redbox-react"],
"preventFullImport": true
}]
}]
]
}
},
"plugins": [
["transform-object-rest-spread"],
["transform-react-display-name"],
["module-resolver", {
"root": ["./src"]
}]
]
}
I know I am missing something here.
Should be somewhere near to or more than webpack recommendations but 1010 KB is too much
FROM BUILD LOGS
WARNING in entrypoint size limit: The following entrypoint(s) combined asset size exceeds the recommended limit (244 KiB). This can impact web performance.
Entrypoints:
index (1010 KiB)
bundle.js
Other relevant information:
webpack version: webpack 4.9.1
Node.js version: v6.10.0 Operating
System: mac OS Additional
tools: npm -v = 4.1.2

You might want to consider splitting your chunks. Like you can have separate chunk for your own code and node_modules.
You might want to minify your code in production mode to reduce the bundle size.
Here's what you can do with your webpack config file:
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
optimization: splitChunks: {
cacheGroups: {
vendor: {
chunks: "initial",
test: path.resolve(process.cwd(), "node_modules"),
name: "vendor",
enforce: true
}
}
},
minimizer: [
new UglifyJSPlugin({
uglifyOptions: {
sourceMap: true,
compress: {
drop_console: true,
conditionals: true,
unused: true,
comparisons: true,
dead_code: true,
if_return: true,
join_vars: true,
warnings: false
},
output: {
comments: false
}
}
})
]
This will create separate bundle for your node_module which you can include in your main file.

Related

Critical dependency: require function is used in a way in which dependencies cannot be statically extracted - NodeJS, Express & Webpack

I am developing a web application using Node.js, Express & Webpack. Everything was going well until Webpack was upgraded to Webpack 5 and lots of bugs appeared. I have managed to solve all the errors but there is a warning I can't solve. I have seen this post but it's related to Angular so I don't think it helps me much: Critical dependency: require function is used in a way in which dependencies cannot be statically extracted
WARNING in ./node_modules/terser-webpack-plugin/dist/minify.js
Critical dependency: require function is used in a way in which dependencies cannot be statically extracted
This is my webpack.config.js; resolve fields and node-polyfill-webpack-plugin are used to solve Webpack 5 bugs and errors.
const path = require("path")
const NodePolyfillPlugin = require("node-polyfill-webpack-plugin")
const webpack = require('webpack')
const HtmlWebPackPlugin = require("html-webpack-plugin")
module.exports = {
resolve:{
fallback: {
"fs": false,
"path": false,
"worker_threads":false,
"child_process":false,
"http": false,
"https": false,
"stream": false,
"crypto": false,
}
},
entry: {
main: './src/js/main.js',
index:'./src/js/'
},
output: {
path: path.join(__dirname, 'dist'),
//publicPath: '/',
filename: '[name].js'
},
mode:"development",
target: 'web',
devtool: 'source-map',
module: {
rules: [
{
test: /\.(png|jp(e*)g|svg)$/,
use: [{
loader: 'url-loader',
options: {
limit: 8000, // Convert images < 8kb to base64 strings
name: 'images/[hash]-[name].[ext]'
}
}]
},
{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader",
},
{
test: /\.bpmn$/,
use: 'raw-loader'
},
{
// Loads the javacript into html template provided.
// Entry point is set below in HtmlWebPackPlugin in Plugins
test: /\.html$/,
use: [
{
loader: "html-loader",
//options: { minimize: true }
}
]
},
{
test: /\.css$/,
use: [ 'style-loader', 'css-loader' ]
}
]
},
plugins: [
new HtmlWebPackPlugin({
template: '!!raw-loader!./src/views/pages/index.ejs',
filename: "./index.ejs",
excludeChunks: [ 'server', 'main' ]
}),
new HtmlWebPackPlugin({
template: '!!raw-loader!./src/views/pages/bmv.ejs',
filename: "./bmv.ejs",
excludeChunks: [ 'server', 'index' ]
}),
new webpack.NoEmitOnErrorsPlugin(),
new NodePolyfillPlugin()
]
}
configure the webpack:
const path = require('path');
module.exports = {
//...
resolve: {
alias: {
'terser-webpack-plugin': path.resolve(__dirname, 'node_modules/terser-webpack-plugin/dist/minify.js'),
},
},
};

Promise.allSettled is not being pollyfilled or transpiled down by babel

I'm trying to transpile code down to node v10.
It seems to mostly be working, however it seems to leave Promise.allSettled in the bundle and doesn't transpile it in a way that node v10 can interpret.
This is my webpack:
var path = require("path")
module.exports = {
entry: "./index.js",
output: {
path: path.resolve(__dirname, "dist"),
filename: "bundle.js",
},
target: "node",
mode: "production",
module: {
rules: [{
test: /\.m?js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: "babel-loader",
options: {
presets: [
[
"#babel/preset-env", {
targets: { node: "10.15.0" },
}
]
],
},
},
}],
},
}
What can I do in order to get it to transpile down Promise.allSettled?
I have tried to follow this SO answer by changing the #babel/preset-env to this:
[
"#babel/preset-env", {
targets: { node: "10.15.0" },
useBuiltIns: 'usage',
corejs: {version: 3, proposals: true}
}
]
However, that just gives me the error: Module not found: Error: Can't resolve 'core-js/modules/esnext.promise.all-settled'.

Jest tests crash when due to #babylon/core es6 syntax

I'm trying to load a 3d scene in react with babylonjs. And this works excellently in my React app but I am getting failed tests from tests that have previously been passing with the following errors. I have tried exempting babylon from transformations but I am still failing.
● Test suite failed to run
Jest encountered an unexpected token
SyntaxError: Unexpected token export
at compileFunction (<anonymous>)
4 | import styled, { withTheme } from 'styled-components'
5 | import { observer, inject } from 'mobx-react'
> 6 | import * as BABYLON from '#babylonjs/core'
| ^
7 | import { GLTFFileLoader } from '#babylonjs/loaders/glTF/glTFFileLoader'
8 | import '#babylonjs/loaders/glTF'
9 | import '#babylonjs/materials/custom'
Here is my webpack configuration file
const path = require('path')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'index_bundle.js',
},
module: {
rules: [
{
test: /\.(js)$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {
rootMode: 'upward',
presets: [
'#babel/preset-env',
'#babel/react',
{
plugins: [
'#babel/plugin-proposal-class-properties',
],
},
],
},
},
],
},
{
test: /\.css$/,
exclude: /node_modules/,
use: [
{
loader: 'style-loader',
},
{
loader: 'css-loader',
},
],
},
],
},
mode: 'development',
devtool: 'inline-source-map',
plugins: [
new webpack.HotModuleReplacementPlugin(),
new HtmlWebpackPlugin({
template: './src/index.html',
}),
],
devServer: {
contentBase: path.join(__dirname, 'public'),
hot: true,
port: 3000,
open: true,
historyApiFallback: true,
},
}
Here is my babel configuration.
{
"presets": ["#babel/preset-env", "#babel/preset-react"],
"plugins": [
["#babel/plugin-proposal-decorators", { "legacy": true }],
["#babel/plugin-proposal-class-properties", { "loose": true }],
"#babel/plugin-proposal-optional-chaining",
"#babel/plugin-transform-runtime",
[
"styled-components",
{ "ssr": false, "displayName": true, "preprocess": false }
]
],
"env": {
"production": {
"plugins": [
["react-remove-properties", { "properties": ["data-testid"] }]
]
},
"test": {
"presets": ["#babel/preset-env", "#babel/preset-react"],
"plugins": [
"#babel/plugin-proposal-class-properties",
"#babel/plugin-transform-modules-commonjs"
]
}
}
}
Here is my jest configuration
{
"setupFilesAfterEnv": ["jest-expect-message"],
"transformIgnorePatterns": ["/node_modules/(?!#babylonjs)"],
"transform": {
"^.+\\.js$": "babel-jest",
"^.+\\.ts$": "ts-jest"
},
"globals": {
"NODE_ENV": "test"
}
}
I found since I was in a mono-repo structure, I had to change from .babelrc to babel.config.js as recommended in jest docs. This solved the issue of transforming the esNext syntax in the #babylonjs modules
For those who aren't using babel this can be achieved with vanilla ts-jest. Be warned, this can add up to a minute to the initial load time for your tests because jest has to transform the babylonjs library.
const config = {
...
//SLOW - transform javascript
preset: 'ts-jest/presets/js-with-ts-esm',
//SLOW - transform node modules
transformIgnorePatterns: []
}
``

Webpack build fail when adding a specific external lib

It happens on a build for server side, i am already using a lot of external modules and everything worked great until now.
I am trying to add the module auth0-js and the error happens when i add the import on this lib var crypto = require('crypto'); TypeError: require is not a function.
Here is my webpack config (for server side):
const path = require('path');
const webpack = require('webpack');
const StatsPlugin = require('stats-webpack-plugin');
module.exports = {
entry: './handler.js',
target: 'node',
profile: false,
output: {
path: path.resolve(__dirname, '../dist-server'),
publicPath: '/',
filename: 'handler.js',
libraryTarget: 'commonjs'
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
include: path.resolve(__dirname, '..'),
use: 'babel-loader'
},
{
test: /\.pug$/,
use: 'pug-loader'
}
]
},
plugins: [
new webpack.DefinePlugin({
__CLIENT__: false,
__SERVER__: true
}),
new StatsPlugin('stats.json', {
chunkModules: true,
exclude: [/node_modules[\\\/]react/]
})
],
resolve: {
modules: [
path.resolve('./src'),
path.resolve('./node_modules')
]
},
devtool: 'source-map'
};
My .babelrc file is:
{
"presets": [
"react",
"latest"
],
"plugins": [
"transform-object-rest-spread",
"transform-runtime"
]
}
I tried to remove the exclude node_modules but i get other errors.
I am curious to know how a single library can break everything, what should i do?

"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