I need to add source-maps to a Webpack 4 production build.
I am using the following config:
{
…
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
sourceMap: true,
}),
],
},
devtool: 'source-map'
…
}
However, although this minimises the bundle, it results in a virtually empty source-map at main.js.map:
{"version":3,"file":"main.js","sources":["webpack://AdminFrontend/main.js"],"mappings":";AAAA","sourceRoot":""}
If i set minimize to false, I get a full source-map, but the bundle is enormous.
What do I need to do to both minimize the source AND generate a full sourcemap?
you can customize webpack minimizer config like this
const minify = (input, sourceMap, minimizerOptions, extractsComments) => {
const { sourceMap: uglifySourceMap, code } = require('uglify-js').minify(input);
return { map: sourceMap, code, warnings: [], errors: [], extractedComments: [] };
}
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
sourceMap: true,
parallel: true,
minify: minify,
}),
],
},
after do that you will get full content map file
Related
I have a React/Node + SSR application, I am trying to create a production build, I have managed to do that but the problem is that the files that I have in the build are too large.
I use latest version of react + webpack 4.
Here is my webpack configuration:
clientConfig.js
const path = require('path');
const common = require('./webpack.common-config');
const clientConfig = {
...common,
mode: 'production',
name: 'client',
target: 'web',
devtool: false,
entry: {
client: [
'#babel/polyfill',
'./src/client.js'
],
},
output: {
path: path.resolve(__dirname, 'build'),
filename: '[name].js',
},
optimization: {
splitChunks: {
cacheGroups: {
vendor: {
chunks: 'all',
name: 'vendor',
test: module => /node_modules/.test(module.resource),
enforce: true
},
common: {
chunks: 'all',
name: 'client'
}
},
},
},
node: {
fs: 'empty',
net: 'empty',
tls: 'empty',
}
};
module.exports = clientConfig;
serverConfig.js
const nodeExternals = require('webpack-node-externals');
const path = require('path');
const common = require('./webpack.common-config');
const serverConfig = {
...common,
mode: 'production',
name: 'server',
target: 'node',
devtool: false,
externals: [nodeExternals()],
entry: {
server: ['#babel/polyfill', path.resolve(__dirname, 'src', 'server.js')],
},
optimization: {
splitChunks: {
chunks: 'all',
}
},
output: {
path: path.resolve(__dirname, 'build'),
filename: '[name].js',
chunkFilename: "[id].chunk.js"
},
node: {
console: false,
global: false,
process: false,
Buffer: false,
__filename: false,
__dirname: false,
},
};
module.exports = serverConfig;
commonConfig.js
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const common = {
module: {
rules: [
{
test: /\.jsx?$/,
loader: 'babel-loader',
include: [path.resolve(__dirname, 'src')],
query: {
presets: [
['#babel/preset-env', {loose: true, modules: false}],
"#babel/preset-react"
],
plugins: [
"#babel/plugin-proposal-class-properties"
]
},
},
{
test: /\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
},
'css-loader'
]
},
{
test: /\.(woff(2)?|ttf|eot|svg)(\?v=\d+\.\d+\.\d+)?$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'fonts/'
}
}
]
}
]
},
plugins: [
new OptimizeCSSAssetsPlugin(),
new MiniCssExtractPlugin({
filename: "styles.css",
})
],
optimization: {
minimize: true,
minimizer: [new TerserPlugin()]
},
};
module.exports = common;
And another file which basically merges the client and the server config.
I run npm run build after that I run webpack -p --mode=production --optimize-minimize && node ./build/server.js
I get the following warning:
WARNING in asset size limit: The following asset(s) exceed the recommended size limit (244 KiB).
This can impact web performance.
Assets:
vendor.js (667 KiB)
WARNING in entrypoint size limit: The following entrypoint(s) combined asset size exceeds the recommended limit (244 KiB). This can impact web performance.
Entrypoints:
client (928 KiB)
vendor.js
styles.css
client.js
Any advice or idea for the above size warning would be great! Thank you!
I recommend that you try core-js instead of babel/pollyfill this can help you to reduce your bundle size.
Also, I recommend that you try dynamic importing with react-loadable which supports SSR. there are different strategies for splitting your code. you can read more here(most important one)
In case you are using CSS frameworks such as bootstrap you should only use parts that you need and avoid importing all of them. there is a tool for purging unused CSS named purgecss but use it with caution and you have to know what are you doing.
In case you are using libraries such as lodash or material-ui you should import your module specifically to avoid importing all the packages into your bundle.
exp:
import debounce from 'lodash/debounce'
npm dedup or yarn dedup can help to remove duplicate dependencies inside bundle.
You may be able to get some reduction through adjusting your babel configuration. For instance, specifying some options for the "preset-env", such as bugfixes, targets if you don't have support older browsers, and using corejs polyfills instead of babel/polyfill.
"#babel/preset-env", {
"targets": {
"browsers": [
"last 2 years"
]
},
"bugfixes": true,
"useBuiltIns": "entry", // experiment with "entry" vs. "usage"
"corejs": 3
...
Depending on your codebase, the babel-plugin-transform-runtime may help too. I had some projects where it made a substantial difference, but other where it hasn't.
"#babel/plugin-transform-runtime",
{
"corejs": 3,
"version": "7.9.2"
}
Additional options for Webpack include using the webpack-cdn-plugin. This can greatly reduce your vendor bundle size. Of course, users will still have to download those same libraries, but they will be cached and don't need to re-downloaded every time your bundle changes or updates.
A little additional savings can be had by specifying runtimeChunk: true, and optionally inlining that chunk in your index.html with
new HTMLWebpackPlugin({
inlineSource: 'runtime~.+[.]js',
...
and the html-webpack-inline-source-plugin or similar.
You can split files to lower size to remove warning using splitChunks:
optimization: {
splitChunks: {
chunks: 'all',
minSize: 10000,
maxSize: 250000,
}
}
Check more for minSize and maxSize.
If you want to disable the warning, you can do it using performance
performance: {
hints: false
}
or remove warning for certain size limit like 1 MB:
performance: {
maxAssetSize: 1000000
}
I managed to switch to Next.js so all of this is not necessary anymore.
I'm attempting to use webpack to compress my code (remove new lines and whitespaces) and nothing else. I don't want any webpack__require__, no mangling, no uglifying, simply just remove whitespace and new lines.
What options in terser/webpack do I have to put to achieve this?
let bundle = {
mode: 'production',
target: 'web',
entry: path.resolve(__dirname, './res/') + '/bundle.js',
output: {
path: path.resolve(__dirname, './res/'),
filename: 'minified.js',
},
optimization: {
minimizer: [
new TerserPlugin({
terserOptions: {
ecma: undefined,
warnings: false,
parse: {},
compress: {},
mangle: false,
module: false,
toplevel: false,
keep_classnames: true,
keep_fnames: true,
}
})
]
}
};
Doesn't seem to do it. Thank you in advance.
Just to build on felismosh's answer for the CLI you will want to not include the --mangle or --compress commands if all you want to do is remove whitespace and newlines.
So it would be something more like:
terser original-file.js -o minified-file.js.
Mangle and compress are disabled unless turned on explicitly in the CLI command.
This will disable compression and use the output option for removing comments. The extractComments property prevents the plugin from extracting comments to a text file.
module.exports = {
/* ... */
optimization: {
minimizer: [
new TerserPlugin({
terserOptions: {
compress: false,
output: {
comments: false,
},
},
extractComments: false,
}),
],
},
};
just use terser directly without webpack.
Run npm i terser to install it, then you will have 2 choices:
Using it's cli, terser --compress --mangle -- input.js.
Using it's api from node,
const Terser = require('terser');
const code = {
'file1.js': 'function add(first, second) { return first + second; }',
'file2.js': 'console.log(add(1 + 2, 3 + 4));',
};
const options = {
ecma: undefined,
warnings: false,
parse: {},
compress: {},
mangle: false,
module: false,
toplevel: false,
keep_classnames: true,
keep_fnames: true,
};
const result = Terser.minify(code, options);
console.log(result.code);
Is it possible to minimize my bundle file and all of the used modules. I use import in javascript but I want webpack to minimize all the imported js files as well. This means removing all unused code from the imported external libraries. Is this possible. Especially plotly is a really large librarie but I use pie charts only. I don't think my bundle needs all of the code from plotly. Here is my webpack configuration file:
const path = require('path');
const webpack = require('webpack');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const config = {
entry:
{
cash: './js/page/cash.js'
},
output:
{
filename: "[name].bundle.js",
path: path.resolve(__dirname, 'dist')
},
resolve:
{
modules: [
path.resolve(__dirname, 'js')
],
alias : {
knockout: path.resolve(__dirname, 'js/knockout-3.4.2.js'),
moment: path.resolve(__dirname,'js/moment.js')
}
},
module:
{
rules: [
{
test: /\.js$/,
use: 'babel-loader'
}
]
},
plugins: [
new webpack.LoaderOptionsPlugin({
minimize: true
}),
new UglifyJSPlugin({
comments: false,
sourceMap: false,
compress: {
unused: true,
dead_code: true,
warnings: false,
drop_debugger: true,
conditionals: true,
evaluate: true,
drop_console: true,
sequences: true,
booleans: true
},
mangle: true
}),
new webpack.optimize.AggressiveMergingPlugin(),
new webpack.optimize.OccurrenceOrderPlugin()
]
};
module.exports = config;
The best way to do this is to selectively import the members (functions) you require with ES6 import syntax. Webpack's documentation describes how. If you do that, Webpack should do the Tree Shaking automagically.
I'm migrating my plugin from gulp to webpack 2 and I have an issue with the completed js file.
the file is minified & compressed.
My web pack config file :
// webpack.config.js
const webpack = require('webpack');
const config = {
entry: './src/ts/amt-rating.ts',
resolve: {
extensions: ['.ts', '.js']
},
module: {
rules: [
{
test: /\.tsx?$/,
exclude: /node_modules/,
loader: 'ts-loader?tsconfig=tsconfig.json'
}
]
},
plugins:[
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify(process.env.NODE_ENV)
}
})
]
}
//if production
if (process.env.NODE_ENV === 'production') {
config.output = {
filename: 'dist/js/amt-rating.min.js'
}
//uglify js options
config.plugins.push(
new webpack.optimize.UglifyJsPlugin({
compress: {
screw_ie8: true,
minimize: true
}
})
)
}
else{
config.output = {
filename: 'dist/js/amt-rating.js'
}
config.devtool = "#cheap-module-source-map"
}
module.exports = config;
And here my tsconfig file :
{
"compilerOptions": {
"target": "es5",
"noImplicitAny": true,
"removeComments": true,
"preserveConstEnums": true,
"sourceMap": true
},
"include": [
"src/ts/*.ts"
],
"exclude": [
"node_modules"
]
}
I wan't to compile my typescript into a very simple javascript file without any dependencies.
This enables minification and compression:
//uglify js options
config.plugins.push(
new webpack.optimize.UglifyJsPlugin({
compress: {
screw_ie8: true,
minimize: true
}
})
)
and is set to run if NODE_ENV is set to production. Make sure you have set it to development to get the not minified version.
I have a webpack grunt task building my app for me. It's been working great, however I notices my jenkins job logs a huge blob of text from the prod buil (specifically the webpack part), and I'm looking into if i can fix that.
The problem is it logs out this :
...0% compile 10% 0/1 build modules 70% 1/1 build modules 40% 1/2 build modules 30% 1/3...
I cut this short, its around 600 modules, so the text block is gigantic.
From googling around I found something, and tried to add this to my prod webpack file
stats: {
assets: false,
colors: true,
modules: false,
version: false,
hash: false,
timings: false,
chunks: false,
chunkModules: false
},
However, this did not seem to work. I found this thread which seemed to be the right direction https://github.com/webpack/webpack/issues/476 , however I could not get any of those suggested fixes to work. I am using grunt-webpack, and just incase it may help, here is my prod task :
return {
prod: {
entry: {
index: './client/app.jsx'
},
output: {
path: path.join(__dirname, '../client'),
publicPath: "/client/",
filename: 'bundle.js'
},
module: {
loaders: [{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'babel-loader'
}]
},
resolve: {
extensions: ['', '.js', '.jsx']
},
stats: {
assets: false,
colors: true,
modules: false,
version: false,
hash: false,
timings: false,
chunks: false,
chunkModules: false
},
plugins: [
new webpack.DefinePlugin({
"process.env": {
"NODE_ENV": JSON.stringify("production")
}
}),
new webpack.optimize.DedupePlugin(),
new webpack.optimize.UglifyJsPlugin()
]
}
}
I am just trying to change it so the prod task doesn't everything, if it just said something like 'build complete' that would be ideal. Is there any way to accomplish this? Thanks!