terser-webpack-plugin选项的范围问题

xoshrz7s  于 2022-11-13  发布在  Webpack
关注(0)|答案(2)|浏览(205)

我有一个情况,我没有正确配置Terser,它导致我的页面的压缩版本中断。我的问题是,我有一些函数声明在我的index.js中。这些声明需要从Bootstrap模态窗口访问,可以在以后的时间加载。
例如,在我的index.js中,有一个如下声明的函数:

function doThis() { }

然后,假设用户在一个模态窗口中打开一个地址表单,并加载了一个名为“address-form.js”的不同javascript文件。在这个表单中有一个按钮,该按钮带有一个onclick处理程序,该处理程序调用doThis()。onclick处理程序位于“address-form.js”中,但可以访问父index.js中的doThis()。当index.js未压缩时,该按钮工作正常。但压缩后,我收到一个错误消息,说doThis()不存在。
我认为这是一个作用域问题,因为我确实在index.js中看到了doThis()声明,但它似乎被一堆括号包围着。index.js中的数百个函数声明和变量都存在同样的作用域问题,所以我在寻找一种不必对庞大的文件进行过多修改的解决方案。
请注意,如果我将函数声明更改为表达式,它看起来确实有效:

window.doThis = function() {
}

但是,由于文件中有数百个varsconstlet变量(以及数十个函数声明),因此更改所有这些变量的作用域以使压缩正常工作对我来说并不实际。
下面是我的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
    })
  ]
}

我正在运行的命令是:
webpack --mode=production --config webpack.config.js

溶液

下面给出的解决方案是直接使用terser-cli。我写了一个小脚本,如果有人觉得它有帮助的话,它可以在目录中的每个文件上运行terser:

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()
brqmpdu1

brqmpdu11#

我创建了一个repro项目与您的配置,并验证了您的问题不是由terser,而是由webpack。
我使用了以下测试文件:

function doThis() { }

minimizedisabled 且未设置minimizer的情况下,以下是使用webpack构建测试文件的结果:

/******/ (() => { // webpackBootstrap
var __webpack_exports__ = {};
function doThis() { }
/******/ })()
;

如果我们重新格式化它并删除注解,很明显文件中的所有内容都是死代码。Webpack是一个捆绑器,将所有内容 Package 在IIFE中。这意味着函数不会被分配到全局范围。

(() => {
  var __webpack_exports__ = {};
  function doThis() { }
})();

因为你没有导出任何东西或者引起任何副作用,比如赋值给window,terser将删除内容。这是正确的,即使没有删除它,你仍然会得到同样的错误,因为webpack输出中的函数没有被赋值给全局作用域,你的处理程序无法访问它。用terser cli压缩webpack的导出结果是一个空文件。
直接在测试输入文件上运行terser cli,得到所需的压缩输出:

function doThis(){}

你说你从命令行运行了terser,遇到了和通过webpack捆绑和压缩时一样的问题。你是通过terser运行源文件还是webpack的输出?因为通过terser运行源文件应该会得到想要的输出。请尝试运行terser foo/bar.js -c -o foo/bar.min.js并测试它是否能解决你的问题。
如果您想使用webpack,您需要分配给window,或者完全不使用全局作用域。

hts6caw3

hts6caw32#

我不知道它是什么时候添加的,但webpack有一个IIFE选项。https://webpack.js.org/configuration/output/#outputiife
但不幸的是,它总是生成不必要的代码var __webpack_exports__ = {}
我不知道如何删除代码。我想知道是否有一个选择。

相关问题