I am facing an issue with my Terser configuration, causing the compressed version of my page to break. The problem arises from functional declarations in my index.js that need to be accessible from Bootstrap modal windows loaded at a later time.
For instance, in my index.js
, there is a function declared as follows:
function doThis() { }
Imagine a user opens an address form in a modal window, loading a different JavaScript file called 'address-form.js'. In this form, there is a button with an onclick handler calling doThis()
. While the button works fine in uncompressed index.js, it throws an error after compression stating that doThis()
does not exist.
This seems to be a scoping issue, possibly due to doThis()
being wrapped in parentheses within index.js
. I am uncertain how to elevate the scope of doThis()
to the top-level window without significant tinkering with the large file containing numerous function declarations and variables.
Changing the function declaration to an expression appears to solve the problem:
window.doThis = function() {
}
However, altering the scopes of all variables, consts, lets, and functions in the extensive file is impractical for ensuring compression works effectively.
This snippet outlines my webpack.config.js:
const TerserPlugin = require("terser-webpack-plugin")
const glob = require('glob')
const path = require('path')
const webpack = require('webpack')
module.exports = {
entry: glob.sync('./js/Pages/*.js').reduce((object, element) => {
object[path.parse(element).name] = element
return object
}, {}),
output: {
filename: '[name].js',
path: path.resolve(__dirname, './js/Pages/minified')
},
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
parallel: true,
test: /\.js(\?.*)?$/i,
terserOptions: {
mangle: false,
compress: true,
keep_fnames: true,
keep_classnames: true,
ie8: false,
safari10: false,
toplevel: false
}
})
]
},
plugins: [
new webpack.optimize.LimitChunkCountPlugin({
maxChunks: 1
})
]
}
The command I execute is:
webpack --mode=production --config webpack.config.js
SOLUTION
The accepted solution involves using terser-cli directly. I have created a script running terser on every file in a directory for anyone who may find it beneficial:
const fs = require('fs')
const path = require('path')
const exec = require('child_process').exec;
const Terser = require('terser')
const srcDir = '../js/Pages'
const destDir = '../js/Pages/minified'
function minifyPagesDir() {
let srcFileNames = fs.readdirSync(srcDir).filter(path => path.match(/\.js$/)) || []
let srcFilePaths = []
let destFilePaths = srcFileNames.map((item, i) => {
srcFilePaths[i] = `${srcDir}/${srcFileNames[i]}`
return `${destDir}/${item}`
})
if (!fs.existsSync(destDir))
fs.mkdirSync(destDir)
srcFileNames.forEach((item, i) => {
exec(
`terser ${srcFilePaths[i]} -c -o ${destFilePaths[i]} --ecma 2021`,
(error, stdout, stderr) => {
if (error !== null)
console.log(`RUHROH: ${error}`, ' stderr: ', stderr);
}
)
console.log(`Minified '${srcFilePaths[i]}' to '${destFilePaths[i]}'!`)
})
console.log('Minification complete!')
}
minifyPagesDir()