Gulp - 如何使用gulp-concat控制处理顺序

7
我正在尝试使用gulp-concat将组合的JavaScript和CSS资源生成到单个文件中,如下所示:

我试图使用gulp-concat生成一个类似于以下内容的组合JavaScript和CSS资源的单个文件:

var concatjs = gulp
    .src(['app/js/app.js','app/js/*Controller.js', 'app/js/*Service.js'])
    .pipe(concat('app.js'))
    .pipe(gulp.dest('build'));

我通过合并文件得到了一个文件,但是嵌入到组合输出文件中的javascript文件的顺序是随机的 - 在这种情况下,控制器在初始app.js文件之前出现,这在试图加载期望在加载任何相关资源之前先加载app.js的Angular应用程序时会导致问题。同样,CSS资源也会以随机的顺序进行组合,而且顺序有些重要 - 例如,bootstrap需要在主题和任何自定义样式表之前加载。
我该如何设置串联过程,使顺序保持不变?
更新 所以事实证明上述排序确实可以工作,即通过在文件规范数组中显式指定文件顺序来实现。因此,在这种情况下,关键的事情是首先列出app/js/app.js,然后让其余的脚本任意排列,其中顺序无关紧要。
我未能看到这种行为的原因(哎呀!)是Gulp Watch正在运行,gulpfile.js更新并没有实际反映在输出中。重新启动gulp确实更新了脚本。新手错误...
其他想法: 仍然在想 - 这是指定构建顺序的正确位置吗?它似乎你正在将应用程序逻辑(加载顺序)放入构建脚本中,这感觉不对。还有其他方法来解决这个问题吗?

你尝试过按顺序命名文件,而不是传递正则表达式来读取所有文件吗? - pankajanand18
这看起来像是一个类似的问题 https://dev59.com/UWEh5IYBdhLWcg3w1mfs - CMR
1
我的原始脚本包含显式文件名,最初没有起作用。后来发现问题在于 gulp-watch 正在运行而没有刷新 gulpfile.js 的更改(duh!)。使用更新的文件重新运行确实尊重了源文件规范顺序。谢谢! - Rick Strahl
你尝试过使用Browserify或RequireJS来处理你的JS依赖吗?这样你就可以让你的加载顺序独立于构建过程。 - Doodlebot
2个回答

5
对于像你示例中的Angular应用程序(以及其依赖项管理),我通常使用这种语法:gulp.src(['app\js\app.js', 'app\js\**\*.js'])
如果您的app.js文件按字母顺序排列是第一个文件,那么您也可以只使用gulp.src('app\js\**\*.js')
我理解您提出将加载文件顺序移入构建脚本的观点:直到我开始使用gulp-inject在开发时注入未最小化文件引用并在生产索引文件中注入捆绑的、最小化的和版本化的文件之前,我都有同样的感觉。使用那个glob排序解决方案在我所有的开发周期中都很有意义,所以我对它不再考虑了。
最后,解决这种“排序痕迹”的可能方法是使用browserify,但对我来说,这只是为Angular应用程序增加了复杂性:最终,正如您所说,您只需要在所有其他文件之前调用一个特定的文件。

3

我使用一种特定的结构/命名约定来编写我的js代码,这有助于提高代码质量。我将代码按照功能分成多个目录,在每个“功能”中则将其作为一个单独的封装模块进行处理。

因此,对于我的项目,我会有不同的文件夹来存放各自的功能模块。

app/js/

    - app.js
    - app.routes.js
    - app.config.js

    /core/

        - core.js
        - core.controllers.js
        - core.services.js

        /test/

           - .spec.js test files for module here

    /feature1/

        - feature1.js
        - feature1.controllers.js

    /feature2/

        - feature2.js
        - feature2.controllers.js

    ...

每个目录都有一个同名文件,其中仅包含初始的模块定义,这就是整个应用程序在app.js中所包含的内容。因此,在feature1.js中也是如此。

angular.module('feature1', [])

接着该模块中的后续文件会获取该模块并向其中添加内容(如控制器/服务/工厂等)。

angular.module('feature1')
       .controller(....)

无论如何,我会直接点到正题...
由于我有预定义的结构,并且知道每个模块需要先处理特定的文件,因此在gulp处理之前,我可以使用下面的函数将所有内容排序。
这个函数依赖于 "npm install file" 和 "npm install path"。
function getModules(src, app, ignore) {

    var modules = [];

    file.walkSync(src, function(dirPath, dirs, files) {

        if(files.length < 1)
            return;

        var dir = path.basename(dirPath)
            module;

        if(ignore.indexOf(dir) === -1) {
            module = dirPath === src ? app : dir;

            files = files.sort(function(a, b) {
                return path.basename(a, '.js') === module ? -1 : 1;
            })
            .filter(function(value) {
                return value.indexOf('.') !== 0;
            })
            .map(function(value) {
                return path.join(dirPath, value);
            })

            modules = modules.concat(files);
        }
    })

    return modules;
}

它遍历传递给它的目录结构,从每个目录(或模块)中取出文件并按正确顺序进行排序,确保模块定义文件始终排在第一位。 它还忽略任何出现在“ignore”数组中的目录,并删除以“.”开头的任何隐藏文件。
使用方式如下:
getModules(src, appName, ignoreDirs);
  • src是您希望递归的目录
  • appName是您的app.js文件的名称 - 因此为'app'
  • ignoreDirs是您想要忽略的目录名称数组

因此,

getModules('app/js', 'app', ['test']);

它会按正确的顺序返回应用程序中所有文件的数组,您可以像以下方式使用它:

gulp.task('scripts', function() {
    var modules = getModules('app/js', 'app', ['test']);

    return gulp.src(modules)
               .pipe(concat('app.js'))
               .pipe(gulp.dest('build'));
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接