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

时间:2013-12-12 01:52:01

标签: javascript node.js gruntjs uglifyjs grunt-contrib-uglify

我有一个如下目录:

/folder/b.js
/folder/jQuery.js
/folder/a.js
/folder/sub/c.js

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

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

问:
1.如何通过grunt-contrib-uglify来实现?(事实上,有很多文件,单独指定所有源文件路径是不切实际的)

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

9 个答案:

答案 0 :(得分:25)

好问题!

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框架,模板框架和您有哪些要求。我使用express + jade,在我的主要玉器布局中我有:

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

在我的package.json中,我有:

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

这意味着当我在部署(在Heroku上)运行npm install时,运行grunt以缩小/连接文件,当使用NODE_ENV=production启动应用程序时,将使用缩小的客户端javascript。在本地,我得到原始客户端javascripts服务,以便于调试。

两个缺点是:

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

答案 1 :(得分:8)

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

  1. https://github.com/gruntjs/grunt-contrib-concat连接 文件
  2. https://github.com/gruntjs/grunt-contrib-uglify缩小 连接文件
  3. 修改

    我通常使用grunt-contrib-concat通过Grunt连接任务运行我的所有文件。然后我还有另一项任务是使用grunt-contrib-uglify uglify连接文件。

答案 2 :(得分:6)

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

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

修改

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

修改

我想补充一点,如果您的网站是使用ES6编写的,那么Rollup是最好的新连接包。除了捆绑文件之外,它还会执行树抖动,删除您使用的部分库(如果包含在import语句中)。这样可以将您的代码库减少到您所需要的范围,而不会使用您永远不会使用的大量代码。

答案 3 :(得分:5)

我认为你不能单独使用uglify任务,但你有很多选择可能会导致你想要的结果。

可能的工作流程首先将文件连接(grunt-contrib-concat)按顺序连接到一个文件中,然后通过uglify放置这个连接文件。您可以在Gruntfile中定义concat的顺序,也可以使用这些插件:

第一个是https://github.com/yeoman/grunt-usemin,您可以在其中指定HTML文件中的顺序,在脚本块周围添加一些注释。谷歌人做了它,使用它非常好。

第二个是https://github.com/trek/grunt-neuter,您可以在其中使用require定义一些依赖项,但不需要大量的require.js。它需要更改JS代码,因此可能不喜欢它。我会选择第一个选择。

答案 4 :(得分:3)

我遇到了同样的问题。快速修复只是更改文件名 - 我使用1.jquery.min.js2.bootstrap.min.js等。

答案 5 :(得分:2)

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

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

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

幸运的是角度和jquery手柄加载两次就好了。 编辑:虽然这不是两次加载这么大的库的最佳做法,但是导致你的缩小文件不必要臃肿。(感谢@Kano指出这一点!)

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

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

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

答案 6 :(得分:2)

看起来问题的第二部分仍未得到答复。但让我逐一尝试。

首先,您可以将大量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的grunt html预处理器,作为你的笨拙工作的一部分。

此预处理器将用

替换整个块
<script src="big-ugly.js"></script>

这意味着html文件在语义上等效 - 在grunt作业之前和之后;即如果页面在本机表单中正常工作(用于调试) - 则转换后的页面必须在grunt之后正常工作 - 无需手动更改任何标记。

答案 7 :(得分:1)

这是@ 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: {

        }
      }
    },

答案 8 :(得分:0)

如果您的问题是您需要按顺序加载供应商(在任何jquery插件之前让我们说jquery)。我通过将jquery放在它自己的名为&#39;!jquery&#39;的文件夹中来解决它,有效地将它放在堆栈顶部。 然后我像往常一样使用concat:

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