如何通过grunt contrib uglify按顺序缩小js文件

how to minify js files in order via grunt-contrib-uglify?

本文关键字:顺序 缩小 js 文件 uglify 何通过 grunt contrib      更新时间:2023-09-26

我有一个如下目录:

/文件夹/b.js
/folder/jQuery.js
/文件夹/a.js
/folder/sub/c.js

我想在一个js文件中缩小所有这些js文件,按顺序

jQuery.js->a.js->b.js->c.js

问:
1.我怎样才能通过咕哝的方式来完成它?(事实上,有很多文件,单独指定所有源文件路径是不切实际的)

2.btw,如何在调试时获得未缩小的文件,在发布时获得缩小的单个文件,并且无需更改html中的脚本标记(以及如何编写脚本标记)?

好问题!

1) Uglify将对目标文件中的函数进行重新排序,使函数定义位于顶部,函数执行位于底部,但它似乎将保留函数执行的顺序。

这意味着,如果您确保在Gruntfile中的Uglify配置中首先提到jQuery,那么jQuery运行以定义其全局函数的函数将被放在第一位。

我使用这个配置:

uglify: {
    options: {
        sourceMap: true
    },
    build: {
        files: {
            'public/all.min.js': ['public/js/vendor/jquery-1.10.2.min.js', 'public/js/*.js'],
        }
    }
}

2) 我认为没有一种确切的方法可以做到这一点。这取决于你有什么样的web框架、模板框架和什么样的需求。我使用快递+翡翠,在我的主要翡翠布局中,我有:

if process.env.NODE_ENV === 'production'
  script(src='/all.min.js')
else
  script(src='/js/vendor/jquery-1.10.2.min.js')
  script(src='/js/someScript.js')
  script(src='/js/otherScript.js')

在我的包.json中,我有:

"scripts": {
  "postinstall": "grunt"
},

这意味着,当我在deploy(在Heroku上)上运行npm install时,会运行grunt来缩小/concat文件,当应用程序使用NODE_ENV=production启动时,会使用缩小的客户端javascript。在本地,我得到了原始的客户端java脚本,以便于调试。

两个缺点是:

  • 我必须保持脚本文件的两个列表同步(在Gruntfile和layout.js中)。我通过在Gruntfile中使用*.js来解决这个问题,但这可能不适合所有人。您可以将javascript的列表放在Gruntfile中,并由此创建一个jade模板,但对于大多数项目来说,这似乎有些过头了
  • 如果你不信任你的Grunt配置,你基本上必须在本地使用NODE_ENV=production测试运行应用程序,以验证缩小是否按你的预期工作

这可以使用以下Grunt任务来完成:

  1. https://github.com/gruntjs/grunt-contrib-concat连接文件
  2. https://github.com/gruntjs/grunt-contrib-uglify迷你型串联文件

编辑

我通常使用Grunt contrib-concat通过Grunt串联任务运行所有文件。然后我有另一个任务,使用grunt contrib uglify对连接的文件进行uglify。

你可能不会喜欢这样,但最好的方法是将js源文件定义为AMD模块,并使用Requirej来管理它们的加载顺序。grunt contrib requirejs任务将递归依赖树,并按必要的顺序将js文件连接到一个大的js文件中。然后,您将使用uglify(实际上r.js内置了uglify)来缩小大文件。

https://github.com/danheberden/yeoman-generator-requirejs有一个很好的示例gruntfile和模板js文件可供使用。

编辑

我最近开始使用CommonJS模块而不是AMD,因为它更接近ES6模块规范。通过Browserify运行CommonJS模块可以获得相同的结果(1个大的composed+级联的js文件)。grunt和gullow都有插件可以为您管理任务。

编辑

我想补充一点,如果你的网站是使用ES6编写的,那么Rollup是最好的新连接包。除了绑定文件外,它还将执行树抖动,删除通过import语句包含的库的部分。这将减少你的代码库,使其满足你的需求,而不会出现你永远不会使用的代码膨胀。

我不认为你可以单独使用uglify任务来做到这一点,但你有很多选择,可能会得到你想要的结果。

一个可能的工作流程是首先将文件按顺序连接到一个文件中,然后将连接的文件通过uglify。你可以在Gruntfile中定义concat的顺序,也可以在其中一个插件上使用:

第一个是https://github.com/yeoman/grunt-usemin,您可以在HTML文件中指定顺序,在脚本块周围放置一些注释。谷歌的人做了它,使用起来很舒服。

第二个是https://github.com/trek/grunt-neuter,在这里你可以用require定义一些依赖项,但不需要大量的require.js。它需要在js代码中进行更改,所以可能不喜欢它。我选择选项一。

我遇到了同样的问题。一个快速的解决方案就是更改文件名-我使用了1.jquery.min.js2.bootstrap.min.js等。

这可能与您的问题有很大关系,但我想要类似的东西。只有我的订单在以下方面很重要:

我用通配符(['vendor/**/*.js'])加载所有供应商文件(angular、jquery和它们各自的相关插件)。但有些插件的名称使它们在angular和jquery之前加载。解决方案是先手动加载它们。

['vendor/angular.js', 'vendor/jquery.js', 'vendor/**/*.js]

幸运的是,angular和jquery句柄加载两次就足够了编辑:虽然两次加载这样大的库并不是最好的做法,但会导致缩小后的文件出现不必要的膨胀(感谢@Kano指出这一点!)

另一个问题是客户端js-顺序很重要,因为它要求在加载所有依赖项后最后加载主应用程序文件。解决方案是排除然后包括:

['app/**/*.js', '!app/app.js', 'app/app.js']

这可以防止app.js与所有其他文件一起加载,并且只有在最后才包括它。

看起来您的问题的第二部分仍然没有答案。但让我一个接一个地试试。

首先,您可以将大量的js文件连接并丑化为一个文件,正如前面的concat答案所解释的那样。还应该可以使用https://github.com/gruntjs/grunt-contrib-uglify因为它似乎确实有通配符。您可能需要尝试使用"expand=true"选项和通配符。这就解决了你的第一个问题。

对于第二部分,假设您加入并丑化了big-ugly.js

现在,在您的html中,您可以添加以下指令:

<!-- build:js:dist big-ugly.js -->
<script src="js1.js"></script>
<script src="js2.js"></script>
<!-- etc etc --> 
<script src="js100.js"></script>
<!-- /build -->

然后在https://www.npmjs.com/package/grunt-processhtml作为你繁重工作的一部分。

这个预处理器将用替换整个块

<script src="big-ugly.js"></script>

这意味着html文件在语义上是等价的——在grunt作业之前和之后;即,如果页面以原生形式正常工作(用于调试),则转换后的页面必须在发出咕哝声后正常工作,而无需手动更改任何标记。

这是@1469的答案,但他没有明确说明为什么这样做。使用concat将所有js文件放在一个文件中,这个模块按照文件名的顺序来做这件事,所以我根据顺序为文件名加了一个前缀。我相信它甚至还有其他的订购选择。

concat: {
        js: {
            options: {
                block: true,
                line: true,
                stripBanners: true
            },
            files: {
                'library/dist/js/scripts.js' : 'library/js/*.js',
            }
        }
    },

然后使用uglify创建缩小的丑陋版本:

uglify: {
      dist: {
        files: {
          'library/dist/js/scripts.min.js': [
            'library/js/scripts.js'
          ]
        },
        options: {
        }
      }
    },

如果您的问题是您有需要按顺序加载的供应商(假设jquery先于任何jquery插件)。我通过将jquery放在它自己的名为"!jquery’,有效地将其放在堆栈的顶部。然后我只是像你平时一样使用concat:

concat: {
  options: {
    separator: ';',
  },
  build: {
    files: [
      {
        src: ['js/vendor/**/*.js', 'js/main.min.js'],
        dest: 'js/global.min.js'
      }
    ]
  }
},