I have a situation where I don't have Terser configured correctly and it's causing the compressed version of my page to break. My issue is that I have some functional declarations in my index.js. These declarations need to be accessible from Bootstrap modal windows that can be loaded in at a later time.
For example, in my index.js there is a function declared like this:
function doThis() { }
Then, say, a user opens an address form in a modal window, and a different javascript file called 'address-form.js' is loaded. In this form there is a button with an onclick handler that calls doThis(). The onclick handler lives in 'address-form.js' but is able to access doThis() in the parent index.js. The button works fine when index.js isn't compressed. But after it's compressed, I get an error saying doThis() doesn't exist.
I believe this to be a scoping issue, because I do see the doThis() declaration in index.js, but it appears to be wrapped in a bunch of parentheses. I'm not sure how to make the scope of doThis() the top-level window. The same scoping issue exists for literally hundreds of function declarations and variables in index.js, so I'm looking for a solution where I don't have to tinker too much with the gargantuan file.
Notice if I change the function declaration to an expression, it DOES seem to work:
window.doThis = function() {
}
However, because there are hundreds of vars and const and let variables in the file (in addition to dozens of function declarations), it's not really practical for me to change the scope of all of them just so the compression will work.
Here is 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'm running is:
webpack --mode=production --config webpack.config.js
SOLUTION
Solution as accepted below was to use terser-cli directly. I wrote a little script that runs terser on every file in a directory if anyone should find it helpful:
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()