How to use Webpack & Terser to only compress code - javascript

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);

Related

Why is no sourcemap generated when minimizing source?

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

Minimize bundle with webpack2

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.

Unexpected Token error using UglifyJS with Preact, Webpack 2

I'm building a Chrome extension with Preact/ES6/Webpack. I pack using one of 2 configurations: debug uses ESLint, Babel and CSS + JSON loaders, prod adds 2 plugins: UglifyJS and Zip. Here's the webpack.config.js:
const webpack = require('webpack');
const path = require('path');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const WebpackCleanupPlugin = require('webpack-cleanup-plugin');
const ZipPlugin = require('zip-webpack-plugin');
const manifest = require('./src/manifest');
let options = {
// entry file - starting point for the app
entry: {
popup: './src/scripts/popup.js',
options: './src/scripts/options.js',
background: './src/scripts/background.js'
},
// where to dump the output of a production build
output: {
path: path.join(__dirname, 'build'),
filename: 'scripts/[name].js'
},
module: {
rules: [
{
test: /\.jsx?/i,
exclude: /node_modules/,
loader: 'eslint-loader',
options: {
},
enforce: 'pre'
},
{
test: /\.jsx?/i,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets: [
['env', {
'targets': {
'chrome': 52
}
}]
],
plugins: [
['transform-react-jsx'],
['module-resolver', {
'root': ['.'],
'alias': {
'react': 'preact-compat',
'react-dom': 'preact-compat'
}
}]
]
}
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /\.json$/,
use: 'json-loader'
}
]
},
plugins: [
new WebpackCleanupPlugin(),
new CopyWebpackPlugin([
{from: './src/_locales', to: '_locales'},
{from: './src/icons', to: 'icons'},
{from: './src/manifest.json', flatten: true},
{from: './src/*.html', flatten: true}
])
],
// enable Source Maps
devtool: 'source-map',
};
if(process.env.NODE_ENV === 'production') {
options.plugins.push(
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false,
drop_console: false,
screw_ie8: true,
conditionals: true,
unused: true,
comparisons: true,
sequences: true,
dead_code: true,
evaluate: true,
if_return: true,
join_vars: true,
},
output: {
comments: false,
},
}),
new ZipPlugin({
path: '../dist',
filename: `${manifest.name} ${manifest.version}.zip`
})
);
}
console.log(`This is a ${process.env.NODE_ENV === 'production' ? 'production' : 'development'} build with ${options.plugins.length} plugins`);
module.exports = options;
But when I run the prod, I get the following errors:
ERROR in scripts/popup.js from UglifyJs
Unexpected token: name (getLatestValues) [scripts/popup.js:29428,4]
ERROR in scripts/options.js from UglifyJs
Unexpected token: name (getLatestValues) [scripts/options.js:29428,4]
ERROR in scripts/background.js from UglifyJs
Unexpected token: name (getLatestValues) [scripts/background.js:28678,4]
It's worth mentioning that getLatestResults is not the only the only function in my code that has await in front of it. Also, it should only appear in background.js as the other entry points are not supposed to call it.
Also worth mentioning is that if I just comment the UglifyJS code, the resulting zipped extension works well.
What configuration piece am I missing to make these errors go away?
It turns out that currently (5/2017) the built in webpack.optimize.UglifyJsPlugin does not support ES6. When Babel transpiles await/async it turns them into generators, which causes UglifyJS to throw an error.
There are several alternatives to UglifyJS listed in this article, but I'm hoping that the Webpack guys will update the plugin, and I'd be able to leave my code intact.
TL;DR: My code is OK; UglifyJS does not support ES6; Will support in the future, or will be replaced by alternative.
I've replaced uglify-js to uglify-es for ES6 compatibility:
https://www.npmjs.com/package/uglify-es
Works fine for me!

Webpack, html-webpack-plugin, Error: Child compilation failed

I 've got a problem with my webpack configuration. After implementing html-webpack-plugin I got an Error, there's whole error stack from generated index.html.
Error Stack:
Html Webpack Plugin:
Error: Child compilation failed:
Conflict: Multiple assets emit to the same filename index.html:
Error: Conflict: Multiple assets emit to the same filename index.html
compiler.js:76
[Pre-build]/[html-webpack-plugin]/lib/compiler.js:76:16
Compiler.js:291 Compiler.
[Pre-build]/[webpack]/lib/Compiler.js:291:10
Compiler.js:494
[Pre-build]/[webpack]/lib/Compiler.js:494:13
Tapable.js:138 next
[Pre-build]/[tapable]/lib/Tapable.js:138:11
CachePlugin.js:62 Compiler.
[Pre-build]/[webpack]/lib/CachePlugin.js:62:5
Tapable.js:142 Compiler.applyPluginsAsyncSeries
[Pre-build]/[tapable]/lib/Tapable.js:142:13
Compiler.js:491
[Pre-build]/[webpack]/lib/Compiler.js:491:10
Tapable.js:131 Compilation.applyPluginsAsyncSeries
[Pre-build]/[tapable]/lib/Tapable.js:131:46
Compilation.js:645 self.applyPluginsAsync.err
[Pre-build]/[webpack]/lib/Compilation.js:645:19
Tapable.js:131 Compilation.applyPluginsAsyncSeries
[Pre-build]/[tapable]/lib/Tapable.js:131:46
Compilation.js:636 self.applyPluginsAsync.err
[Pre-build]/[webpack]/lib/Compilation.js:636:11
Tapable.js:131 Compilation.applyPluginsAsyncSeries
[Pre-build]/[tapable]/lib/Tapable.js:131:46
Compilation.js:631 self.applyPluginsAsync.err
[Pre-build]/[webpack]/lib/Compilation.js:631:10
Tapable.js:131 Compilation.applyPluginsAsyncSeries
[Pre-build]/[tapable]/lib/Tapable.js:131:46
Compilation.js:627 sealPart2
[Pre-build]/[webpack]/lib/Compilation.js:627:9
Tapable.js:131 Compilation.applyPluginsAsyncSeries
[Pre-build]/[tapable]/lib/Tapable.js:131:46
Compilation.js:575 Compilation.seal
[Pre-build]/[webpack]/lib/Compilation.js:575:8
Compiler.js:488
[Pre-build]/[webpack]/lib/Compiler.js:488:16
Tapable.js:225
[Pre-build]/[tapable]/lib/Tapable.js:225:11
Compilation.js:477 _addModuleChain
[Pre-build]/[webpack]/lib/Compilation.js:477:11
Compilation.js:448 processModuleDependencies.err
[Pre-build]/[webpack]/lib/Compilation.js:448:13
next_tick.js:73 _combinedTickCallback
internal/process/next_tick.js:73:7
next_tick.js:104 process._tickCallback
internal/process/next_tick.js:104:9
My webpack configuration code:
var webpack = require('webpack'),
path = require('path');
var CopyWebpackPlugin = require('copy-webpack-plugin'),
ExtractTextWebpackPlugin = require('extract-text-webpack-plugin'),
HtmlWebpackPlugin = require('html-webpack-plugin'),
const sourcePath = path.resolve(__dirname, './src');
const staticPath = path.resolve(__dirname, './static');
module.exports = function (env) {
const nodeEnv = env && env.prod ? 'production' : 'development';
const isProd = nodeEnv === 'production';
const postcssLoader = {
loader: 'postcss-loader',
options: {
plugins: function () {
return [
require('autoprefixer')
];
}
}
}
const plugins = [
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: Infinity,
filename: 'vendor.bundle.js'
}),
new webpack.EnvironmentPlugin({
NODE_ENV: nodeEnv,
}),
new HtmlWebpackPlugin({
template: 'index.html',
minify: {
removeComments: true,
collapseWhitespace: true,
removeAttributeQuotes: true
},
chunksSortMode: 'dependency'
})
];
if(isProd) {
plugins.push(
new webpack.LoaderOptionsPlugin({
minimize: true,
debug: false
}),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false,
screw_ie8: true,
conditionals: true,
unused: true,
comparisons: true,
sequences: true,
dead_code: true,
evaluate: true,
if_return: true,
join_vars: true,
},
output: {
comments: false,
},
})
);
} else {
plugins.push(
new webpack.HotModuleReplacementPlugin()
);
}
return {
devtool: isProd? 'source-map' : 'eval',
context: sourcePath,
entry: {
app: './app/entry.ts',
vendor: './app/vendor.ts'
},
output: {
path: staticPath,
filename: '[name].bundle.js',
},
module: {
rules: [
{
test: /\.html$/,
exclude: /node_modules/,
use: {
loader: 'file-loader',
query: {
name: '[name].[ext]'
},
},
},
{
test: /\.css$/,
exclude: /node_modules/,
use: [
'style-loader',
'css-loader',
'postcss-loader'
]
},
{
test: /\.scss$/,
exclude: /node_modules/,
use: [
'style-loader',
'css-loader',
'postcss-loader',
'sass-loader'
]
},
{
test: /\.ts$/,
exclude: /node_modules/,
use: [
'ts-loader'
],
},
],
},
resolve: {
alias: {
Public: path.resolve(__dirname,'src/public'),
Style: path.resolve(__dirname,'src/styles')
},
extensions: ['.ts','.js', '.html'],
modules: [
path.resolve(__dirname, 'node_modules'),
sourcePath
]
},
plugins,
performance: isProd && {
maxAssetSize: 100,
maxEntrypointSize: 300,
hints: 'warning'
},
stats: {
colors: {
green: '\u001b[32m'
}
},
devServer: {
contentBase: './src',
historyApiFallback: true,
port: 3000,
compress: isProd,
inline: !isProd,
hot: !isProd,
stats: {
assets: true,
children: false,
chunks: false,
hash: false,
modules: false,
publicPath: false,
timings: true,
version: false,
warnings: true,
color: {
green: '\u001b[32m'
}
},
}
};
};
I couldn't find any source of that Error, maybe I am little bit tired, but I would like to finish it up, so I hope for your help guys.
Maybe should I use some raw-loader to load .html(?), which does not make me happy.
The problem is indeed the file-loader, because it simply copies the file over. By the time html-webpack-plugin tries to write index.html it has already been written by file-loader, hence resulting in a conflict.
There are several ways to resolve that issue, depending on what your needs are.
You could use html-loader for your HTML, although if you expect your imported HTML to simply be copied, it isn't the correct choice. To be clear, by the imported HTML I don't mean the template used by the html-webpack-plugin.
If you want to keep using the file-loader for your other HTML files, you can exclude the index.html so html-webpack-plugin falls back to its default loader. require.resolve works like require but gives you the full path of the module instead of its content.
{
test: /\.html$/,
exclude: [/node_modules/, require.resolve('./index.html')],
use: {
loader: 'file-loader',
query: {
name: '[name].[ext]'
},
},
},
When no loader matches the template, the html-webpack-plugin uses an ejs loader as a fallback. If you don't need any loader for .html files, you could remove the rule entirely and it would work just fine. That is rather unlikely, otherwise you wouldn't have a .html rule in the first place, but this also means you can use the .ejs extension to not apply the .html rule, as all HTML is valid EJS. You would rename index.html to index.ejs and change your plugin configuration accordingly:
new HtmlWebpackPlugin({
template: 'index.ejs',
minify: {
removeComments: true,
collapseWhitespace: true,
removeAttributeQuotes: true
},
chunksSortMode: 'dependency'
})
I had to upgrade my node version. then the issue is fixed.
upgrade to latest node version(ubuntu)
sudo npm cache clean -f
sudo npm install -g n
sudo n stable
sudo n latest
to check the version
node -v
you might need to restart your terminal to see the latest version.
For my case I had the template file name misspelled.
Solution to my problem was updating node version.
This is may be not ordinary case, but for me, problem was caused by symbol "!" in the path. After I moved all content to the folder without "!" then the error disappeared.
delete node modules package then run npm install all package install then npm start the same problem are face but this process to run solve the problem so this solution is useful
I had the same issue few minutes ago and I switched to a stable version of node to solve it. It worked
sudo npm cache clean -f
sudo npm install -g n
sudo n stable
Simple Updated Node JS Version. And use
npm i
this will update your all libraries
This method works for me you can also try

r.js disable drop_debugger option

I'm trying to create a build config file for r.js with uglify2 as optimizer.
I want to disable the drop_debugger so the debugger statement does not get removed.
Below is my build.js file, the build process works fine but the debugger statements have been removed.
Is maybe r.js removing these, what am i doing wrong ?
({
appDir: ".",
baseUrl: ".",
dir: "../app-build",
paths: {
'css-builder': 'lib/require/css-builder'
},
optimize: "uglify2",
uglify2: {
"screw-ie8": true,
compress: {
sequences: true,
dead_code: true,
drop_debugger: false,
}
},
mainConfigFile: "main.js",
modules: [
{
name: "main",
include: "signalR"
}
]
})
Remove the trailing comma from:
drop_debugger: false

Categories

Resources