How to reduce bundle size of react app even further - javascript

I am trying to reduce the size of my build file ( main.js ) to 500kb or less.
Initially it was 1.2MB and with some code splitting and webpack I managed to reduce it to around 600kb but I need to reduce it by another 100kb.
I am fairly new to webpack and I would appreciate any feedback.
Bellow you can find my webpack.prodduction.config.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const webpack = require('webpack')
const UglifyJSPlugin = require('uglifyjs-webpack-plugin')
const LodashModuleReplacementPlugin = require('lodash-webpack-plugin')
console.log(`Building for: ${process.env.NODE_ENV}`)
module.exports = {
module: {
rules: [
{
test: /.jsx?$/,
loader: 'babel-loader',
exclude: /node_modules/
}, {
test: /\.css$/,
loader: 'style-loader!css-loader'
}, {
test: /\.(jpe?g|png|gif|woff|woff2|eot|ttf|svg)(\?[a-z0-9=.]+)?$/,
loader: 'url-loader?limit=100000' },
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
options: {
presets: [
['#babel/preset-env', {
useBuiltIns: false,
modules: false
}]
],
plugins: [
'#babel/plugin-transform-runtime',
'#babel/plugin-proposal-class-properties',
'inline-react-svg'
]
},
loader: 'babel-loader'
}
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /\.module\.s(a|c)ss$/,
loader: [
{
loader: 'style-loader',
options: {
attrs: { class: 'BasebotTag' }
}
},
{
loader: 'css-loader',
options: {
modules: true,
localIdentName: '[name]__[local]___[hash:base64:5]',
camelCase: true
}
},
{
loader: 'sass-loader'
}
]
},
{
test: /\.(woff(2)?|ttf|eot|svg|otf)(\?v=\d+\.\d+\.\d+)?$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'fonts/'
}
}
]
},
{
test: /\.s(a|c)ss$/,
exclude: /\.module.(s(a|c)ss)$/,
loader: [
{
loader: 'style-loader',
options: {
attrs: { class: 'BasebotTag' }
}
},
'css-loader',
{
loader: 'sass-loader'
}
]
}
]
},
resolve: {
extensions: ['.js', '.jsx', '.scss']
},
plugins: [
new UglifyJSPlugin(),
new LodashModuleReplacementPlugin(),
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('production')
}
}),
new webpack.ContextReplacementPlugin(/moment[\/\\]locale$/, /en/),
new webpack.optimize.ModuleConcatenationPlugin(),
new MiniCssExtractPlugin({
filename: '[name].[hash].css',
chunkFilename: '[id].[hash].css'
}),
new LodashModuleReplacementPlugin({
caching: true,
cloning: true
})
]
}
EDIT:
This is my build script:
"build": "NODE_ENV=production webpack --config webpack.production.config",

You are inlining images and other assets up to 0.1MB (100000 Bytes) with url-loader. It would not take many assets with a size of this upper limit to increase your bundle size significantly. In fact, reducing this limit and un-inlining just one asset of 100KB would mean you meet your target bundle size.
I would suggest only inlining assets that are less than 10KB (10000 Bytes). Everything larger than this can be fetched with an HTTP request when it is needed.
{
test: /\.(jpe?g|png|gif|woff|woff2|eot|ttf|svg)(\?[a-z0-9=.]+)?$/,
loader: 'url-loader?limit=10000' }, // <= lower the limit here to 10000
}

Related

Problem with styled-jsx/webpack and custom webpack.config.js

Information: I do not use NextJS in this project.
When I start my devSever I have a problem with styled-jsx/webpack as I mentioned in the title. When I try to add a new rule to CSS about scoped styled I get an error styled-jsx/css: if you are getting this error it means that yourcsstagged template literals were not transpiled.
I tried to fix my config with these topics:
https://github.com/zeit/styled-jsx/issues/537
https://github.com/zeit/styled-jsx/issues/498
https://github.com/zeit/styled-jsx/issues/469#issuecomment-423243758
https://github.com/zeit/styled-jsx/issues/434#issuecomment-415801021
but It doesn't work in my case and I don't know what I'm doing wrong.
My webpack config:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ni = require('os').networkInterfaces();
const host = Object.keys(ni)
.map(interf => ni[interf].map(o => !o.internal && o.family === 'IPv4' && o.address))
.reduce((a, b) => a.concat(b))
.filter(o => o)[0];
const config = {
mode: 'development',
entry: './docs/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
publicPath: '/'
},
resolve: {
alias: {
myPackage: path.resolve('./src/index')
}
},
module: {
rules: [
{
test: /\.css$/i,
use: [
{
loader: require('styled-jsx/webpack').loader,
options: {
type: 'scoped'
}
}
]
},
{
test: /\.js$/,
exclude: /node_modules/,
use: ['babel-loader']
},
{
test: /\.css$/i,
exclude: /\.module\.css$/i,
use: ['style-loader', 'css-loader']
},
{
test: /\.module\.css$/i,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: true
}
}
]
},
{
test: /\.(scss)$/,
use: ['css-loader', 'sass-loader']
},
{ test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: 'file-loader' },
{ test: /\.(woff|woff2)$/, loader: 'url-loader?prefix=font/&limit=5000' },
{
test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
loader: 'url-loader?limit=10000&mimetype=application/octet-stream'
},
{
test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
issuer: {
test: /\.jsx?$/
},
use: ['babel-loader', '#svgr/webpack', 'url-loader']
},
{
test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
loader: 'url-loader'
},
{
test: /\.png(\?v=\d+\.\d+\.\d+)?$/,
loader: 'url-loader?limit=10000&mimetype=image/png'
},
{
test: /\.gif(\?v=\d+\.\d+\.\d+)?$/,
loader: 'url-loader?limit=10000&mimetype=image/gif'
}
]
},
devServer: {
historyApiFallback: true,
open: true,
compress: true,
port: 8080,
host,
hot: true
},
plugins: [
new HtmlWebpackPlugin({
template: 'public/index.html'
})
]
};
module.exports = config;
I tried also to add this styled-jsx/webpack loader in the same rules with babel-loader ( with style-loader and css-loader too) but It doesn't work either. Like this:
{
test: /\.(js?|css)$/,
// exclude: /node_modules/,
use: [
{
// I tried put a style-lodaer and css-lodaer to this rule but It dosent'work
loader: require('styled-jsx/webpack').loader,
options: {
type: 'scoped'
}
},
'babel-loader'
]
},
.babelrc
{
"presets": ["#babel/env", "#babel/preset-react"],
"plugins": [
"#babel/proposal-class-properties",
[
"styled-jsx/babel",
{
"optimizeForSpeed": true
}
]
]
}
I want to have a scoped css styles when import styles from css like a object and put them to the {styles}.
Do you have any advice about what I should do?

`exports is not defined` when using custom webpack config file in Stroybook

I'm using a custom webpack config file in my Storybook config directory .storybook, after run command start-stroybook, I'm getting a exports is not defined error on my page.
Here is the custom webpack config file's content:
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
plugins: [
new webpack.optimize.ModuleConcatenationPlugin(),
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin(),
new webpack.DefinePlugin({
__IS_NATIVE__: JSON.stringify(false),
'process.env.NODE_ENV': JSON.stringify('development'),
}),
],
module: {
rules: [
{
test: /\.js$/,
use: {
loader: 'babel-loader',
},
exclude: path.join(__dirname, '../node_modules'),
},
{
test: /\.svg$/,
issuer: /\.js$/,
use: [
{
loader: 'babel-loader',
},
() => {
this.counter = this.counter || 0;
return {
loader: 'react-svg-loader',
options: {
jsx: true,
svgo: {
plugins: [
{
cleanupIDs: {
prefix: `${this.counter++}`,
},
},
],
},
},
};
},
],
},
{
test: /\.svg$/,
issuer: /\.css$/,
use: 'svg-url-loader',
},
{
test: /\.((png)|(eot)|(woff)|(ttf)|(gif)|(jpg)|(otf))$/,
use: 'url-loader?name=/[hash].[ext]',
},
{
test: /\.ico$/,
use: 'file-loader',
},
{
test: /\.json$/,
use: 'json-loader',
},
{
test: /\.css$/,
exclude: /node_modules/,
use: [
'style-loader',
'css-loader?modules&importLoaders=1' +
'&sourceMap?&localIdentName=[path]-[local]-[hash:base64:5]',
'postcss-loader',
],
},
],
},
resolve: {
modules: ['node_modules', 'pretend_modules'],
},
};
The version of Storybook and optionally any affected addons that I'm running:
#storybook/addon-actions": "^3.4.11
#storybook/addon-centered": "^3.4.11
#storybook/addon-info": "^3.4.11
#storybook/addon-knobs": "^3.4.11
#storybook/react": "^3.4.11
#babel/core": "^7.0.0-beta.42
babel-loader": "^8.0.0-beta.2
#babel/preset-env": "^7.0.0-beta.42

webpack file-loader ouputting corrupted images

Am using the latest file-loader. It's outputting the files to images/css-urls like specified but they're corrupted images.
The config is searching through the sass files and replacing urls with new files that file-loader outputs. That part works, but the files are corrupted.
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const extractSass = new ExtractTextPlugin("./bundle.css");
var mainConfig = {
entry: {
"app": [
"./app/main.ts",
"./static/scss/main.scss",
],
"vendor": "./app/vendor.ts",
"polyfills": "./app/polyfills.ts",
},
output: {
path: path.resolve(__dirname, "static"),
filename: "[name].js"
},
resolve: {
extensions: [".ts", ".js"],
},
devtool: "source-map",
module: {
rules: [{
test: /.*\.(gif|png|jpe?g|svg)$/i,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[hash].[ext]',
outputPath: 'images/css-urls/',
}
},
]
}, {
test: /\.(scss|css)$/,
use: extractSass.extract({
use: [{
loader: "css-loader",
}, {
loader: "sass-loader",
}],
// use style-loader in development
fallback: "style-loader"
})
}, {
test: /\.(png|jpg|gif|svg|eot|ttf|woff|woff2)$/,
loader: "url-loader",
}, {
test: /\.ts$/,
loaders: [
{
loader: "awesome-typescript-loader",
options: { configFileName: root("./", "tsconfig.json") }
} , "angular2-template-loader"
]
}, {
test: /\.html$/,
loader: "html-loader"
}]
},
plugins: [
extractSass,
new webpack.ContextReplacementPlugin(
// The (\\|\/) piece accounts for path separators in *nix and Windows
/angular(\\|\/)core(\\|\/)#angular/,
root("./app"), // location of your src
{} // a map of your routes
),
new webpack.optimize.CommonsChunkPlugin({
name: ["app", "vendor", "polyfills"]
}),
]
}
I got it to work by removing the file-loader rule and replacing the url-loader rule with this
{
test: /\.(png|jpg|gif|svg|eot|ttf|woff|woff2)$/,
loader: "url-loader",
options: {
limit: 8192,
fallback: "file-loader",
// fallback options
name: '[name].[hash].[ext]',
outputPath: 'images/css-urls/',
},
}

Webpack doesn't generate app.bundle.css

I have the following webpack file, however, when I run npm run dev the name.bundle.css file doesn't get generated: (no errors either)
const path = require('path');
const webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
context: path.resolve(__dirname, './resources/'),
entry: {
app: './index.jsx'
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, './public/assets/'),
publicPath: '/assets/'
},
module: {
rules: [
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
use: [{
loader: 'css-loader'
}],
}),
},
{
test: /\.jsx|js$/,
exclude: [/node-modules/],
use: [
{
loader: "babel-loader",
options: { presets: ['react', 'es2015', 'stage-1'] }
}
]
},
{
test: /\.(sass|scss)$/,
use: ["style-loader", "css-loader", "sass-loader"]
},
{
test: /\.(jpe?g|png|gif|svg)$/i,
use: ['file-loader?name=[name].[ext]']
},
{
test: /\.(eot|svg|ttf|woff|woff2)$/,
loader: 'file-loader?name=public/fonts/[name].[ext]'
}
]
},
resolve: {
modules: [
path.resolve(__dirname, './resources/'),
'node_modules'
]
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'common'
}),
new ExtractTextPlugin({
filename: '[name].bundle.css'
})
]
}
my CSS folder is:
CSS
- app.scss
COMPONENTS
comp1.scss
comp2.scss
it works this way "import styles from './css/app.scss';" but I would expect this to generate a app.bundle.css:
new ExtractTextPlugin({
filename: '[name].bundle.css'
})
You have 2 rules for both css and sass.
I think in your case you only need one:
test: /\.(sass|scss)$/,
use: ExtractTextPlugin.extract({
use: [{
loader: "css-loader"
}, {
loader: "sass-loader"
}],
fallback: "style-loader"
})
and like you said, you should import the scss files in the js files import './css/app.scss'

Sourcemap Sass with Webpack (2)

I am using Webpack 2 for building my Angular (4) app. I have it working, but I am trying to figure out how to generate sourcemaps for my scss. In my components I load my scss with styleUrls Adding the options: { sourceMap: true } is not working. I do not want to extract the styles for components, because then the ViewEncapsulation is not working anymore. The .global.scss I use are needed everywhere, so I do extract these and this part works fine. Can someone tell me how to generate my sourcemaps (is it even possible with Angular)? Below is my webpack.config.js .
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const autoprefixer = require('autoprefixer');
const path = require('path');
module.exports = {
devtool: 'inline-source-map',
devServer: {
port: 3000,
contentBase: '/www',
inline: true
},
entry: {
polyfills: './src/polyfills.ts',
vendor: './src/vendor.ts',
app: './src/bootstrap.ts'
},
output: {
path: path.join(__dirname, '../www/'),
filename: '[name].bundle.js'
},
resolve: {
modules: [ path.join(__dirname, 'node_modules') ],
extensions: ['.js', '.ts', '.html']
},
module: {
loaders: [{
test: /\.ts$/,
exclude: /node_modules/,
use: ['awesome-typescript-loader', 'angular2-template-loader']
}, {
test: /\.html$/,
use: 'html-loader'
},{
test: /\.global\.scss$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use:[{
loader: 'css-loader',
options: {
sourceMap: true
}
}, {
loader: 'postcss-loader'
}, {
loader: 'sass-loader',
options: {
sourceMap: true,
}
}]
}),
}, {
test: /\.scss$/,
use: [ {
loader: "raw-loader"
}, {
loader: 'resolve-url-loader'
}, {
loader: 'postcss-loader'
}, {
loader: "sass-loader", options: {
sourceMap: true
}
}],
exclude: /node_modules/
}, {
test: /.(png|woff(2)?|eot|ttf|svg)(\?[a-z0-9=\.]+)?$/,
use: 'url-loader'
}]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
}),
new ExtractTextPlugin('global-styles.css'),
new webpack.optimize.CommonsChunkPlugin({
name: 'polyfills',
chunks: ['polyfills']
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
chunks: ['vendor']
}),
new webpack.optimize.CommonsChunkPlugin({
name: ['polyfills', 'vendor'].reverse()
})
]
};

Categories