Kịch bản concat theo thứ tự với Gulp


191

Ví dụ, bạn đang xây dựng một dự án trên Backbone hoặc bất cứ điều gì và bạn cần tải các tập lệnh theo một thứ tự nhất định, ví dụ như underscore.jscần phải được tải trước đó backbone.js.

Làm thế nào để tôi có được nó để ghép các tập lệnh sao cho chúng theo thứ tự?

// JS concat, strip debugging and minify
gulp.task('scripts', function() {
    gulp.src(['./source/js/*.js', './source/js/**/*.js'])
    .pipe(concat('script.js'))
    .pipe(stripDebug())
    .pipe(uglify())
    .pipe(gulp.dest('./build/js/'));
});

Tôi có thứ tự đúng các tập lệnh trong tôi source/index.html, nhưng vì các tệp được sắp xếp theo thứ tự chữ cái, gulp sẽ nối underscore.jssau backbone.jsvà thứ tự của các tập lệnh trong tôi source/index.htmlkhông quan trọng, nó nhìn vào các tệp trong thư mục.

Vì vậy, có ai có một ý tưởng về điều này?

Ý tưởng tốt nhất tôi có là để đổi tên các kịch bản cung cấp với 1, 2, 3để cung cấp cho họ theo đúng thứ tự, nhưng tôi không chắc chắn nếu tôi như thế này.

Khi tôi tìm hiểu thêm, tôi thấy Browserify là một giải pháp tuyệt vời, ban đầu nó có thể là một nỗi đau nhưng thật tuyệt vời.


4
Tôi có thể đề cập rằng bây giờ tôi đang sử dụng browserify. Nó có đường cong học tập nhỏ IMO. Tôi đã vật lộn lúc đầu nhưng gulp browserify là một cách hay để đi! Cho phép mã của bạn được mô-đun! Bạn xử lý thứ tự trong một shim, vì vậy không cần thiết phải ghép nối khi sử dụng browserify.
Michael Joseph Aubry

Muốn cung cấp thêm chi tiết cho giải pháp của bạn hoặc một liên kết?
Dmitri Zaitsev

kroltech.com/2013/12/ trên đây là một liên kết đến một dự án nồi hơi thực sự giúp tôi bắt đầu với việc quản lý dự án tốt. Sau khi chịu đựng với việc học tất cả những điều này, tôi có thể quản lý các dự án của mình tốt hơn nhiều. Anh ấy có dự án trên github và bạn có thể thấy cách anh ấy sử dụng browserify. Youtube luôn giúp đỡ và tất nhiên bản thân nguồn này luôn bị đánh giá thấp github.com/substack/node-browserify#usage
Michael Joseph Aubry

Về cơ bản, ý tưởng có thể sử dụng cú pháp như npm requireở mặt trước vì tất nhiên nếu bạn đã sử dụng npm ở phía máy chủ của bạn, bạn sẽ thấy cách bạn có thể yêu cầu các mô-đun, nhưng browserify cho phép bạn thực hiện điều đó trên mã phía máy khách, giữ để bắt đầu, nó đòi hỏi một chút mày mò, nhưng chủ yếu là bên trong gói.json và nếu bạn muốn sử dụng với gulp.js hoặc grunt.js. Nếu bạn cài đặt gói browserify gulp / grunt, bạn có thể chạy gulp/grunt browserifyvà biến tập lệnh của mình thành một tập lệnh chính, đó là một đường cong học tập nhẹ nhưng đáng để IMO.
Michael Joseph Aubry

Cảm ơn! Trên thực tế tôi đã xem qua bài viết tuyệt vời medium.com/@dickeyxxx/... thực hiện một điểm tốt mà bạn không thực sự cần browserifycho Angularmô-đun, nơi công trình nối đơn giản và trật tự không quan trọng :)
Dmitri Zaitsev

Câu trả lời:


198

Gần đây tôi đã gặp vấn đề tương tự với Grunt khi xây dựng ứng dụng AngularJS của mình. Đây là một câu hỏi tôi đã đăng.

Điều cuối cùng tôi làm là liệt kê rõ ràng các tệp theo thứ tự trong cấu hình grunt. Các tập tin cấu hình sau đó sẽ trông như thế này:

[
  '/path/to/app.js',
  '/path/to/mymodule/mymodule.js',
  '/path/to/mymodule/mymodule/*.js'
]

Grunt có thể tìm ra tập tin nào trùng lặp và không bao gồm chúng. Kỹ thuật tương tự cũng sẽ làm việc với Gulp.


74
Điều này cũng hoạt động tốt dưới gulp. Gulp sẽ không lặp lại các tập tin.
OverZealous

1
Những người tuyệt vời, hai kiệt tác này là tuyệt vời. Cuối cùng tôi cũng đã thiết lập tệp gulp.js của mình để hoạt động theo cách tôi muốn, đã viết bằng một số html, lưu tệp và làm bùng nổ một trang web được xây dựng với các khung tốt nhất và thực hành tốt chỉ bằng một nút bấm. Cộng với các bản cập nhật sẽ dễ dàng, nếu bạn không sử dụng một trong những thứ bạn cần!
Michael Joseph Aubry

1
Đúng! Tôi đã bắt đầu sử dụng Grunt gần đây, và nó thật tuyệt vời. Không còn nhúng các ứng dụng JavaScript bên trong các khung phụ trợ.
Chad Johnson

3
Gulp đã sao chép các tập tin trong nỗ lực của tôi, nhưng tôi nhận ra rằng tôi có trường hợp khác biệt trong gulp so với hệ thống tập tin, vì vậy hãy chú ý điều đó! Với trường hợp chính xác, gulp sẽ không sao chép các tập tin.
Chris

2
Đặt hàng thủ công là một cơn ác mộng trong một dự án nghiêm trọng. Có các trình sắp xếp tập tin đặc biệt - cho angularjs và những người khác.
zhekaus

135

Một điều hữu ích khác nếu bạn cần một số tệp đến sau một loạt tệp, là loại trừ các tệp cụ thể khỏi toàn cầu của bạn, như vậy:

[
  '/src/**/!(foobar)*.js', // all files that end in .js EXCEPT foobar*.js
  '/src/js/foobar.js',
]

Bạn có thể kết hợp điều này với việc chỉ định các tệp cần đến trước như được giải thích trong câu trả lời của Chad Johnson.


Ah tôi thực sự đã thấy bài viết của bạn sớm hơn và nó đã giúp tôi tiêm mã cho tôi srcbuildtôi thấy bạn sử dụng cú pháp đó, cuối cùng tôi đã xóa phần đó bởi vì tôi không chắc chắn chính xác tại sao tôi cần nó, bây giờ có ý nghĩa.
Michael Joseph Aubry

Oh okay vậy quan điểm của bạn ở đây chỉ đánh tôi, sẽ không làm cho foobar.js kéo dài? Không nên là cách khác. ['./source/js/*.js', './source/js/**/underscore.js', './source/js/**/!(underscore)*.js']
Michael Joseph Aubry

Vâng, đây không chỉ là một chút trợ giúp. Nó hữu ích nhất khi bạn cần hoặc muốn mã ứng dụng cốt lõi của mình xuất hiện sau khi mọi thứ khác được tải. Không có lý do để sử dụng nó ( !(foobar)) nếu bạn đã bao gồm một tệp cụ thể trước đó.
OverZealous

Đối với một ứng dụng AngularJS nơi các định nghĩa mô-đun của tôi nằm trong các tệp có 'không dấu gạch ngang' trong tên, mẫu toàn cầu Gulp này đã hoạt động; ['src/app/**/!(*-)*.js', 'src/app/**/*.js']
Sam T

17

Tôi đã sử dụng plugin gulp-order nhưng nó không phải lúc nào cũng thành công như bạn có thể thấy bởi mô-đun nút nút xếp chồng bài đăng của tôi với các luồng được hợp nhất . Khi duyệt qua các tài liệu Gulp, tôi đã bắt gặp mô-đun streamque hoạt động khá tốt để chỉ định thứ tự trong trường hợp nối của tôi. https://github.com/gulpjs/gulp/blob/master/docs/recipes/USE-multipl-source-in-one-task.md

Ví dụ về cách tôi sử dụng nó dưới đây

var gulp         = require('gulp');
var concat       = require('gulp-concat');
var handleErrors = require('../util/handleErrors');
var streamqueue  = require('streamqueue');

gulp.task('scripts', function() {
    return streamqueue({ objectMode: true },
        gulp.src('./public/angular/config/*.js'),
        gulp.src('./public/angular/services/**/*.js'),
        gulp.src('./public/angular/modules/**/*.js'),
        gulp.src('./public/angular/primitives/**/*.js'),
        gulp.src('./public/js/**/*.js')
    )
        .pipe(concat('app.js'))
        .pipe(gulp.dest('./public/build/js'))
        .on('error', handleErrors);
});

Xem thêm dòng-series . Nó không yêu cầu bạn chỉ định chế độ đối tượng và hoạt động với gulp-chích. Xem câu trả lời của tôi.
Codebling

Có vẻ như một nửa số plugin chỉ đơn giản là không hoạt động ổn định (như thứ tự như bạn đã chỉ ra), đó là một sự xấu hổ khi khóc vì khái niệm kiến ​​trúc của gulp là ngoạn mục, chỉ có rất nhiều người thực hiện và duy trì các plugin của họ kém ... Tôi thấy các mô-đun nút cơ bản là hữu ích hơn vì vậy thankyou cho giải pháp này! Hoạt động tuyệt vời!
Jimmy Hoffa

1
streamqueue, event-stream không hoạt động với tôi, nhưng merge2 hoạt động như mong đợi npmjs.com/package/merge2
Alexander Shutau

12

Với gulp-useref, bạn có thể ghép mọi tập lệnh được khai báo trong tệp chỉ mục của mình, theo thứ tự bạn khai báo nó.

https://www.npmjs.com/package/gulp-useref

var $ = require('gulp-load-plugins')();
gulp.task('jsbuild', function () {
  var assets = $.useref.assets({searchPath: '{.tmp,app}'});
  return gulp.src('app/**/*.html')
    .pipe(assets)
    .pipe($.if('*.js', $.uglify({preserveComments: 'some'})))
    .pipe(gulp.dest('dist'))
    .pipe($.size({title: 'html'}));
});

Và trong HTML, bạn phải khai báo tên của tệp xây dựng mà bạn muốn tạo, như thế này:

<!-- build:js js/main.min.js -->
    <script src="js/vendor/vendor.js"></script>
    <script src="js/modules/test.js"></script>
    <script src="js/main.js"></script>

Trong thư mục bản dựng của bạn, bạn sẽ có tham chiếu đến main.min.js sẽ chứa Vendor.js, test.js và main.js


2
Đây là hoàn hảo! Tôi ghét câu trả lời mà tôi cần để xác định thứ tự! Bạn biết gì? Thứ tự là có: trong tệp HTML. Giải pháp hoàn hảo.
Ali Ok

6

Các loại dòng cũng có thể được sử dụng để bảo đảm trật tự tệp cụ thể với gulp.src. Mã mẫu đặt backbone.jsluôn luôn là tệp cuối cùng để xử lý:

var gulp = require('gulp');
var sort = require('sort-stream');
gulp.task('scripts', function() {
gulp.src(['./source/js/*.js', './source/js/**/*.js'])
  .pipe(sort(function(a, b){
    aScore = a.path.match(/backbone.js$/) ? 1 : 0;
    bScore = b.path.match(/backbone.js$/) ? 1 : 0;
    return aScore - bScore;
  }))
  .pipe(concat('script.js'))
  .pipe(stripDebug())
  .pipe(uglify())
  .pipe(gulp.dest('./build/js/'));
});

Tôi muốn mô-đun này hoạt động vì nó có vẻ như là câu trả lời đơn giản nhất đối với tôi, nhưng trong trường hợp của tôi, nơi tôi đã đánh số tên tệp và một chức năng so sánh rất đơn giản, điều này không hoạt động.
Jeremy John

5

Tôi chỉ cần thêm số vào đầu tên tập tin:

0_normalize.scss
1_tikitaka.scss
main.scss

Nó hoạt động trong gulp mà không có bất kỳ vấn đề.


1
Vâng tôi thấy điều này dễ dàng hơn một chút, ý tôi là nếu bạn biên dịch tất cả các tệp của mình để sản xuất thì sẽ không có gì khác biệt khi bạn đặt tên cho các tệp của mình trong quá trình phát triển.
Michael Joseph Aubry

2
Tôi chỉ phát hiện ra điều này không hoạt động chính xác. thử sử dụng 1_xx, 2_xx, 10_xx, 11_xx. Trong Windows ít nhất, nó sẽ là 1_xx, 10_xx, 11_xx, 2_xx
dbinott

17
Cá nhân tôi hoàn toàn không đồng ý với tuyên bố rằng việc bạn đặt tên cho các tệp của bạn trong quá trình phát triển là không quan trọng. Tất cả sự phát triển nên tập trung vào con người trước tiên, không tập trung vào máy tính. Thay đổi tệp của bạn để phù hợp với công cụ xây dựng của bạn đánh bại mục đích của công cụ xây dựng. Thay đổi bản dựng của bạn để phù hợp với dự án của bạn, không phải cách khác.
Jon Hieb

2
@JonHieb Theo một cách nào đó, tiền tố các tệp của bạn bằng một số cũng sẽ giúp nhà phát triển tiếp theo biết được sự phụ thuộc của từng tệp, phải không? Nếu tôi mở một thư mục và xem 1_foo.js, 2_bar.js, 3_baz.js, tôi sẽ mở các tập tin theo thứ tự đó, và đọc bắt đầu đọc mã tại 1_foo.js
sqram

Tôi đã thấy rằng gulp.src chạy async, điều đó có nghĩa là điều này không hoạt động nhất quán trong trường hợp có nhiều tệp để xử lý trong một thư mục.
Jeremy John

5

Tôi có các tập lệnh của mình được sắp xếp trong các thư mục khác nhau cho mỗi gói tôi lấy từ bower, cộng với tập lệnh riêng cho ứng dụng của tôi. Vì bạn sẽ liệt kê thứ tự của các tập lệnh này ở đâu đó, tại sao không liệt kê chúng trong tập tin gulp của bạn? Đối với các nhà phát triển mới trong dự án của bạn, thật tuyệt khi tất cả các điểm cuối tập lệnh của bạn được liệt kê ở đây. Bạn có thể làm điều này với gulp-add-src :

gulpfile.js

var gulp = require('gulp'),
    less = require('gulp-less'),
    minifyCSS = require('gulp-minify-css'),
    uglify = require('gulp-uglify'),
    concat = require('gulp-concat'),
    addsrc = require('gulp-add-src'),
    sourcemaps = require('gulp-sourcemaps');

// CSS & Less
gulp.task('css', function(){
    gulp.src('less/all.less')
        .pipe(sourcemaps.init())
        .pipe(less())
        .pipe(minifyCSS())
        .pipe(sourcemaps.write('source-maps'))
        .pipe(gulp.dest('public/css'));
});

// JS
gulp.task('js', function() {
    gulp.src('resources/assets/bower/jquery/dist/jquery.js')
    .pipe(addsrc.append('resources/assets/bower/bootstrap/dist/js/bootstrap.js'))
    .pipe(addsrc.append('resources/assets/bower/blahblah/dist/js/blah.js'))
    .pipe(addsrc.append('resources/assets/js/my-script.js'))
    .pipe(sourcemaps.init())
    .pipe(concat('all.js'))
    .pipe(uglify())
    .pipe(sourcemaps.write('source-maps'))
    .pipe(gulp.dest('public/js'));
});

gulp.task('default',['css','js']);

Lưu ý: jQuery và Bootstrap được thêm vào cho mục đích trình diễn. Có lẽ tốt hơn để sử dụng CDN cho những người này vì chúng được sử dụng rộng rãi và các trình duyệt có thể lưu chúng từ các trang web khác.


3

Hãy thử stream-series . Nó hoạt động như merge-stream / event-stream.merge () ngoại trừ việc thay vì xen kẽ, nó sẽ nối vào cuối. Nó không yêu cầu bạn chỉ định chế độ đối tượng như streamqueue , vì vậy mã của bạn sẽ sạch hơn.

var series = require('stream-series');

gulp.task('minifyInOrder', function() {
    return series(gulp.src('vendor/*'),gulp.src('extra'),gulp.src('house/*'))
        .pipe(concat('a.js'))
        .pipe(uglify())
        .pipe(gulp.dest('dest'))
});

2

merge2 trông giống như công cụ hợp nhất luồng được duy trì hoạt động và duy trì tại thời điểm này.

Cập nhật 2020

Các API luôn thay đổi, một số thư viện trở nên không sử dụng được hoặc chứa các lỗ hổng hoặc các phụ thuộc của chúng chứa các lỗ hổng, không được sửa trong nhiều năm. Đối với các thao tác tệp văn bản, bạn nên sử dụng các tập lệnh NodeJS tùy chỉnh và các thư viện phổ biến như globbyfs-extracùng với các thư viện khác mà không có các trình bao bọc Gulp, Grunt, v.v.

import globby from 'globby';
import fs from 'fs-extra';

async function bundleScripts() {
    const rootPaths = await globby('./source/js/*.js');
    const otherPaths = (await globby('./source/**/*.js'))
        .filter(f => !rootFiles.includes(f));
    const paths = rootPaths.concat(otherPaths);

    const files = Promise.all(
        paths.map(
            // Returns a Promise
            path => fs.readFile(path, {encoding: 'utf8'})
        )
    );

    let bundle = files.join('\n');
    bundle = uglify(bundle);
    bundle = whatever(bundle);
    bundle = bundle.replace(/\/\*.*?\*\//g, '');

    await fs.outputFile('./build/js/script.js', bundle, {encoding: 'utf8'});
}

bundleScripts.then(() => console.log('done');

1

Một phương pháp khác là sử dụng plugin Gulp được tạo riêng cho vấn đề này. https://www.npmjs.com/package/gulp-ng-module-sort

Nó cho phép bạn sắp xếp các tập lệnh của mình bằng cách thêm vào .pipe(ngModuleSort())như sau:

var ngModuleSort = require('gulp-ng-module-sort');
var concat = require('gulp-concat');

gulp.task('angular-scripts', function() {
    return gulp.src('./src/app/**/*.js')
        .pipe(ngModuleSort())
        .pipe(concat('angularAppScripts.js))
        .pipe(gulp.dest('./dist/));
});

Giả sử một quy ước thư mục của:

|——— src/
|   |——— app/
|       |——— module1/
|           |——— sub-module1/
|               |——— sub-module1.js
|           |——— module1.js
|       |——— module2/
|           |——— sub-module2/
|               |——— sub-module2.js
|           |——— sub-module3/
|               |——— sub-module3.js
|           |——— module2.js
|   |——— app.js

Hi vọng điêu nay co ich!


1

Đối với tôi, tôi đã có natualSort () và angularFileSort () trong đường ống sắp xếp lại các tập tin. Tôi đã gỡ bỏ nó và bây giờ nó hoạt động tốt với tôi

$.inject( // app/**/*.js files
    gulp.src(paths.jsFiles)
      .pipe($.plumber()), // use plumber so watch can start despite js errors
      //.pipe($.naturalSort())
      //.pipe($.angularFilesort()),
    {relative: true}))

1

Tôi chỉ sử dụng gulp-angular-filesort

function concatOrder() {

    return gulp.src('./build/src/app/**/*.js')
        .pipe(sort())
        .pipe(plug.concat('concat.js'))
        .pipe(gulp.dest('./output/'));
}

Rất tiếc, tôi mới nhận ra bạn không hỏi về góc cạnh, xin lỗi
Maccurt

0

Tôi đang ở trong một môi trường mô-đun nơi tất cả đều là những người phụ thuộc cốt lõi bằng cách sử dụng gulp. Vì vậy, coremô-đun cần phải được thêm vào trước những người khác.

Tôi đã làm gì:

  1. Di chuyển tất cả các tập lệnh vào một srcthư mục
  2. Chỉ cần thư mục gulp-renamecủa bạn coređể_core
  3. gulp đang giữ trật tự của bạn gulp.src, concat của tôisrc trông như thế này:

    concat: ['./client/src/js/*.js', './client/src/js/**/*.js', './client/src/js/**/**/*.js']

Nó rõ ràng sẽ lấy _thư mục đầu tiên từ danh sách (sắp xếp tự nhiên?).

Lưu ý (angularjs): Sau đó tôi sử dụng gulp-angular-extender để tự động thêm các mô-đun vào coremô-đun. Tổng hợp nó trông như thế này:

angular.module('Core', ["ui.router","mm.foundation",(...),"Admin","Products"])

Trong đó Admin và Sản phẩm là hai mô-đun.


0

nếu bạn muốn đặt hàng phụ thuộc thư viện của bên thứ ba, hãy thử Wiredep . Gói này về cơ bản kiểm tra từng phụ thuộc gói trong bower.json, sau đó kết nối chúng với bạn.


0

Tôi đã thử một số giải pháp từ trang này, nhưng không có giải pháp nào hiệu quả. Tôi đã có một loạt các tệp được đánh số mà tôi chỉ đơn giản muốn được sắp xếp theo tên người dùng theo thứ tự chữ cái để khi được chuyển đến concat()chúng sẽ theo cùng một thứ tự. Đó là, bảo toàn thứ tự của đầu vào Globing. Dễ thôi phải không?

Đây là mã bằng chứng khái niệm cụ thể của tôi ( printchỉ để xem thứ tự được in cho cli):

var order = require('gulp-order');
var gulp = require('gulp');
var print = require('gulp-print').default;

var options = {};

options.rootPath = {
  inputDir: process.env.INIT_CWD + '/Draft',
  inputGlob: '/**/*.md',
};

gulp.task('default', function(){
  gulp.src(options.rootPath.inputDir + options.rootPath.inputGlob, {base: '.'})
    .pipe(order([options.rootPath.inputDir + options.rootPath.inputGlob]))
    .pipe(print());
});

Lý do cho sự điên rồ của gulp.src? Tôi xác định rằng gulp.srcđã chạy async khi tôi có thể sử dụng một sleep()chức năng (sử dụng một.map tăng tốc độ theo chỉ số) để sắp xếp đầu ra luồng chính xác.

Kết quả không đồng bộ của các thư mục srctrung bình có nhiều tệp trong đó xuất hiện sau các thư mục có ít tệp hơn, vì chúng mất nhiều thời gian hơn để xử lý.


1
Bạn đã tìm thấy một sự thay thế đồng bộ (tốt, ít nhất là xác định)?
ELLIOTTCABLE

0

Trong thiết lập gulp của tôi, tôi chỉ định các tệp của nhà cung cấp trước và sau đó chỉ định mọi thứ (tổng quát hơn), thứ hai. Và nó thành công đặt nhà cung cấp js trước các công cụ tùy chỉnh khác.

gulp.src([
  // vendor folder first
  path.join(folder, '/vendor/**/*.js'),
  // custom js after vendor
  path.join(folder, '/**/*.js')
])    

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.