36

我有一个如下目录:

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

我想按顺序将所有这些 js 文件压缩到一个 js 文件

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

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

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

4

9 回答 9

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 + jam,在我的主要玉石布局中,我有:

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"
},

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

两个缺点是:

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

这可以使用以下 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

于 2014-02-11T21:11:16.847 回答
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语句包含)。这将您的代码库减少到您需要的内容,而不会出现您永远不会使用的大量代码。

于 2013-12-12T02:00:04.157 回答
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 代码,因此可能不喜欢它。我会选择选项一。

于 2013-12-12T09:04:25.790 回答
3

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

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

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

幸运的是,angular 和 jquery 句柄被加载了两次。编辑:虽然两次加载如此大的库并不是最佳实践,但会导致您的缩小文件不必要的膨胀。(感谢@Kano 指出这一点!)

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

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

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

于 2014-11-15T18:34:58.730 回答
3

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

于 2016-02-11T13:46:13.467 回答
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 -->

然后将其作为 grunt 作业的一部分通过https://www.npmjs.com/package/grunt-processhtml上的 grunt html 预处理器。

该预处理器将整个块替换为

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

这意味着 html 文件在语义上是等效的 - 在 grunt 作业之前和之后;即,如果页面以本机形式正常工作(用于调试) - 那么转换后的页面必须在 grunt 之后正常工作 - 无需您手动更改任何标签。

于 2015-08-05T04:16:00.757 回答
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: {

        }
      }
    },
于 2015-05-20T22:16:49.890 回答
0

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

concat: {
  options: {
    separator: ';',
  },
  build: {
    files: [
      {
        src: ['js/vendor/**/*.js', 'js/main.min.js'],
        dest: 'js/global.min.js'
      }
    ]
  }
},
于 2015-02-19T06:04:38.647 回答