Script concat dalam rangka dengan Gulp

192

Katakan, misalnya, Anda sedang membangun proyek di Backbone atau apa pun dan Anda perlu memuat skrip dalam urutan tertentu, misalnya underscore.js harus dimuat sebelumnya backbone.js.

Bagaimana cara saya membuatnya untuk skrip sehingga mereka dalam rangka?

// 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/'));
});

Saya memiliki urutan skrip yang tepat dalam source/index.htmlfile saya , tetapi karena file disusun berdasarkan urutan alfabet, tegukan akan underscore.jsselesai setelahnya backbone.js, dan urutan skrip pada saya source/index.htmltidak masalah, ia melihat file dalam direktori.

Jadi apakah ada yang punya ide tentang ini?

Ide terbaik yang saya miliki adalah untuk mengubah nama script penjual dengan 1, 2, 3untuk memberi mereka urutan yang tepat, tapi saya tidak yakin apakah saya seperti ini.

Ketika saya belajar lebih banyak, saya menemukan Browserify adalah solusi yang hebat, pada awalnya bisa sangat menyebalkan, tetapi itu bagus.

Michael Joseph Aubry
sumber
4
Saya mungkin menyebutkan bahwa sekarang-a-hari saya menggunakan browserify. Ini memiliki kurva belajar kecil itu sendiri IMO. Saya berjuang pada awalnya tetapi menelan browserify adalah cara yang keren untuk pergi! Mengizinkan kode Anda menjadi modular! Anda menangani pesanan dalam shim, jadi penggabungan tidak perlu saat menggunakan browserify.
Michael Joseph Aubry
Ingin memberikan detail lebih lanjut untuk solusi atau tautan Anda?
Dmitri Zaitsev
kroltech.com/2013/12/... berikut adalah tautan ke proyek boilerplate yang benar-benar membantu saya memulai dengan manajemen proyek yang baik. Setelah menderita dengan mempelajari semua ini saya dapat mengelola proyek saya jauh lebih baik. Dia memiliki proyek di github dan Anda dapat melihat bagaimana dia menggunakan browserify. Youtube selalu membantu dan tentu saja sumbernya sendiri selalu diremehkan github.com/substack/node-browserify#usage
Michael Joseph Aubry
Pada dasarnya idenya adalah dapat menggunakan npm seperti sintaksis dengan requiredi ujung depan karena tentu saja jika Anda telah menggunakan npm di sisi server Anda, Anda melihat bagaimana Anda dapat memerlukan modul, tetapi browserify memungkinkan Anda untuk melakukan itu pada kode sisi klien, tetap dalam pikiran untuk memulai itu memerlukan sedikit mengutak-atik, tapi itu terutama di dalam package.json dan jika Anda ingin menggunakan dengan gulp.js atau grunt.js. Jika Anda menginstal paket browserify gulp / grunt yang dapat Anda jalankan gulp/grunt browserifydan mengubah skrip Anda menjadi satu skrip utama, itu adalah kurva belajar yang sedikit tetapi layak untuk IMO.
Michael Joseph Aubry
Terima kasih! Sebenarnya saya datang di artikel bagus medium.com/@dickeyxxx/... membuat titik yang baik bahwa Anda tidak benar-benar perlu browserifyuntuk Angularmodul, di mana karya Rangkaian sederhana dan ketertiban tidak peduli :)
Dmitri Zaitsev

Jawaban:

199

Saya memiliki masalah yang sama dengan Grunt saat membangun aplikasi AngularJS saya. Ini pertanyaan yang saya posting.

Apa yang akhirnya saya lakukan adalah secara eksplisit mendaftar file-file tersebut dalam konfigurasi kasar. File config kemudian akan terlihat seperti ini:

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

Grunt dapat mengetahui file mana yang merupakan duplikat dan tidak menyertakannya. Teknik yang sama akan bekerja dengan Gulp juga.

Chad Johnson
sumber
74
Ini bekerja dengan baik di bawah tegukan juga. Gulp juga tidak akan mengulangi file.
OverZealous
1
Kawan, kedua karya ini luar biasa. Saya akhirnya mengatur file gulp.js saya untuk bekerja seperti yang saya inginkan, menulis dalam beberapa html, menyimpan file dan menggebrak situs yang dibangun dengan kerangka kerja terbaik dan praktik yang baik dengan satu sentuhan tombol. Plus pembaruan akan mudah, jika Anda tidak menggunakan salah satu yang Anda butuhkan!
Michael Joseph Aubry
1
Iya! Saya mulai menggunakan Grunt baru-baru ini, dan itu luar biasa. Tidak ada lagi aplikasi JavaScript embedding di dalam kerangka backends.
Chad Johnson
3
Gulp menduplikasi file dalam upaya saya, tetapi saya menyadari saya memiliki kasus yang berbeda dalam tegukan vs sistem file, jadi hati-hati! Dengan kasus yang tepat, tegukan tidak akan menggandakan file.
Chris
2
Pemesanan manual adalah mimpi buruk dalam proyek yang serius. Ada penyortir file khusus - untuk angularjs dan lainnya.
zhekaus
135

Hal lain yang membantu jika Anda memerlukan beberapa file untuk datang setelah gumpalan file, adalah mengecualikan file tertentu dari bola Anda, seperti:

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

Anda dapat menggabungkan ini dengan menentukan file yang harus didahulukan seperti yang dijelaskan dalam jawaban Chad Johnson.

Terlalu bersemangat
sumber
Ah saya benar-benar melihat posting Anda sebelumnya dan itu membantu saya dengan menyuntikkan kode ke saya srcdan saya buildsaya melihat Anda menggunakan sintaks itu, saya akhirnya menghapus bagian itu karena saya tidak yakin persis mengapa saya membutuhkannya, masuk akal sekarang.
Michael Joseph Aubry
Oh oke jadi maksud Anda di sini hanya memukul saya, bukankah itu membuat foobar.js bertahan? Bukankah seharusnya sebaliknya. ['./source/js/*.js', './source/js/**/underscore.js', './source/js/**/!(underscore)*.js']
Michael Joseph Aubry
Ya, ini lebih dari sekadar bantuan. Ini paling berguna ketika Anda membutuhkan atau ingin kode aplikasi inti Anda masuk setelah semua yang lain dimuat. Tidak ada alasan untuk menggunakannya ( !(foobar)) jika Anda sudah memasukkan file tertentu sebelumnya.
OverZealous
Untuk aplikasi AngularJS di mana definisi modul saya berada di file yang memiliki 'no dash' dalam namanya, pola Gulp glob ini berfungsi; ['src/app/**/!(*-)*.js', 'src/app/**/*.js']
Sam T
17

Saya telah menggunakan plugin gulp-order tetapi tidak selalu berhasil seperti yang Anda lihat dengan stack overflow saya pasca modul node gulp-order dengan aliran gabungan . Ketika browsing melalui dokumen Gulp saya menemukan modul streamque yang telah bekerja dengan sangat baik untuk menentukan urutan dalam rangkaian kasus saya.https://github.com/gulpjs/gulp/blob/master/docs/recipes/using-multiple-sources-in-one-task.md

Contoh bagaimana saya menggunakannya di bawah ini

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);
});
dtothefp
sumber
Lihat juga stream-series . Itu tidak mengharuskan Anda untuk menentukan mode objek, dan bekerja dengan gulp-inject. Lihat jawaban saya.
Codebling
tampaknya setengah dari tegukan plugin tidak bekerja secara konsisten (seperti pesanan seperti yang Anda tunjukkan), yang memalukan karena konsep arsitektur tegukan itu spektakuler, begitu banyak orang yang menerapkan dan mempertahankan plugin mereka dengan buruk, saya pikir ... Saya menemukan modul simpul yang mendasarinya lebih berguna jadi terima kasih untuk solusi ini! Bagus sekali!
Jimmy Hoffa
1
streamqueue, event-stream tidak bekerja untuk saya, tetapi merge2 bekerja seperti yang diharapkan npmjs.com/package/merge2
Alexander Shutau
12

Dengan gulp-useref, Anda dapat menggabungkan setiap skrip yang dideklarasikan dalam file indeks Anda, sesuai urutan Anda mendeklarasikannya.

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

Dan dalam HTML Anda harus mendeklarasikan nama file build yang ingin Anda hasilkan, seperti ini:

<!-- 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>

Di direktori build Anda, Anda akan memiliki referensi ke main.min.js yang akan berisi vendor.js, test.js, dan main.js

SuperIRis
sumber
2
Ini sempurna! Saya benci jawaban di mana saya perlu menentukan urutan! Kamu tahu apa? Urutannya ada di sana: di file HTML. Solusi sempurna.
Ali Ok
6

The semacam streaming juga dapat digunakan untuk memastikan urutan tertentu dari file dengan gulp.src. Kode contoh yang menempatkan backbone.jsselalu sebagai file terakhir untuk diproses:

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/'));
});
fracz
sumber
Saya berharap modul ini berfungsi karena sepertinya jawaban yang paling sederhana bagi saya, tetapi dalam kasus saya, di mana saya memiliki nama file bernomor dan fungsi perbandingan yang sangat sederhana, ini tidak berfungsi.
Jeremy John
5

Saya hanya menambahkan angka ke awal nama file:

0_normalize.scss
1_tikitaka.scss
main.scss

Ini bekerja dalam tegukan tanpa masalah.

pengguna3360496
sumber
1
Ya saya menemukan ini sedikit lebih mudah, maksud saya jika Anda mengkompilasi semua file Anda untuk produksi, tidak ada bedanya apa nama file Anda dalam pengembangan.
Michael Joseph Aubry
2
Saya baru tahu ini tidak berfungsi dengan benar. coba gunakan 1_xx, 2_xx, 10_xx, 11_xx. Di bawah Windows setidaknya, itu akan menjadi 1_xx, 10_xx, 11_xx, 2_xx
dbinott
17
Secara pribadi saya sangat tidak setuju dengan pernyataan bahwa tidak masalah apa nama file Anda dalam pengembangan. Semua pengembangan harus berfokus pada manusia terlebih dahulu, bukan berfokus pada komputer. Mengubah file Anda agar sesuai dengan alat build Anda mengalahkan tujuan alat build. Ubah bangunan Anda agar sesuai dengan proyek Anda, bukan sebaliknya.
Jon Hieb
2
@JonHieb Di satu sisi, awalan file Anda dengan angka juga akan membantu pengembang berikutnya mengetahui dependensi setiap file, bukan? Jika saya membuka folder dan melihat 1_foo.js, 2_bar.js, 3_baz.js, saya akan membuka file-file itu dalam urutan itu, dan membaca mulai membaca kode di 1_foo.js
sqram
Saya telah menemukan bahwa gulp.src menjalankan async, yang berarti bahwa ini tidak berfungsi secara konsisten dalam kasus di mana ada lebih banyak file untuk diproses dalam sebuah dir.
Jeremy John
5

Saya mengatur skrip saya di folder yang berbeda untuk setiap paket yang saya tarik dari bower, ditambah skrip saya sendiri untuk aplikasi saya. Karena Anda akan membuat daftar urutan skrip-skrip ini di suatu tempat, mengapa tidak mencantumkannya dalam file tegukan Anda? Untuk pengembang baru di proyek Anda, senang bahwa semua titik akhir skrip Anda tercantum di sini. Anda dapat melakukan ini dengan 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']);

Catatan: jQuery dan Bootstrap ditambahkan untuk tujuan demonstrasi pesanan. Mungkin lebih baik menggunakan CDN untuk mereka karena CDN itu sudah sangat banyak digunakan dan browser sudah bisa di-cache dari situs lain.

prograhammer
sumber
3

Coba stream-series . Ia bekerja seperti merge-stream / event-stream.merge () kecuali bahwa alih-alih interleaving, ia menambahkan sampai akhir. Itu tidak mengharuskan Anda untuk menentukan mode objek seperti streamqueue , sehingga kode Anda keluar lebih bersih.

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'))
});
Codebling
sumber
2

merge2 sepertinya satu-satunya alat penggabungan aliran yang dipesan dan dikelola saat ini.

Perbarui 2020

API selalu berubah, beberapa perpustakaan menjadi tidak dapat digunakan atau mengandung kerentanan, atau dependensinya mengandung kerentanan, yang tidak diperbaiki selama bertahun-tahun. Untuk manipulasi file teks, Anda sebaiknya menggunakan skrip NodeJS khusus dan pustaka populer seperti globbydan fs-extrabersama pustaka lainnya tanpa Gulp, Grunt, dll.

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');
Alexander Shutau
sumber
1

Metode alternatif adalah dengan menggunakan plugin Gulp yang dibuat khusus untuk masalah ini. https://www.npmjs.com/package/gulp-ng-module-sort

Ini memungkinkan Anda untuk menyortir skrip Anda dengan menambahkan .pipe(ngModuleSort())seperti:

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/));
});

Dengan asumsi konvensi direktori:

|——— 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

Semoga ini membantu!

ek
sumber
1

Bagi saya, saya memiliki natualSort () dan angularFileSort () di pipa yang mengatur ulang file. Saya menghapusnya dan sekarang berfungsi dengan baik untuk saya

$.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}))
casper123
sumber
1

Saya hanya menggunakan gulp-angular-filesort

function concatOrder() {

    return gulp.src('./build/src/app/**/*.js')
        .pipe(sort())
        .pipe(plug.concat('concat.js'))
        .pipe(gulp.dest('./output/'));
}
Maccurt
sumber
oops, saya baru sadar Anda tidak bertanya tentang sudut, maaf
Maccurt
0

Saya berada di lingkungan modul di mana semua orang bergantung pada inti menggunakan tegukan. Jadi, coremodul perlu ditambahkan sebelum yang lain.

Apa yang saya lakukan:

  1. Pindahkan semua skrip ke srcfolder
  2. Hanya direktori gulp-renameAndacore_core
  3. tegukan menjaga pesanan Anda gulp.src, konser saya srcterlihat seperti ini:

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

Jelas akan mengambil _sebagai direktori pertama dari daftar (sort natural?).

Catatan (angularjs): Saya kemudian menggunakan gulp-angular-extender untuk secara dinamis menambahkan modul ke coremodul. Dikompilasi terlihat seperti ini:

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

Di mana Admin dan Produk adalah dua modul.

soyuka
sumber
0

jika Anda ingin memesan dependensi perpustakaan pihak ketiga, coba wiredep . Paket ini pada dasarnya memeriksa setiap ketergantungan paket di bower.json kemudian mengirimkannya untuk Anda.

zak.http
sumber
0

Saya mencoba beberapa solusi dari halaman ini, tetapi tidak ada yang berhasil. Saya memiliki serangkaian file bernomor yang saya hanya ingin dipesan dengan namafabet alfabet sehingga ketika disalurkan keconcat() mereka akan berada dalam urutan yang sama. Artinya, pertahankan urutan input globbing. Mudah kan?

Inilah kode bukti konsep khusus saya ( printhanya untuk melihat urutan yang dicetak ke 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());
});

Alasan kegilaannya gulp.src? Saya menentukan bahwa gulp.srcmenjalankan async ketika saya bisa menggunakan sleep()fungsi (menggunakan a.map dengan sleeptime yang ditambahkan oleh indeks) untuk memesan output stream dengan benar.

Hasil dari async dari srcdirs rata - rata dengan lebih banyak file di dalamnya datang setelah dirs dengan lebih sedikit file, karena mereka butuh waktu lebih lama untuk diproses.

Jeremy John
sumber
1
Apakah Anda menemukan alternatif yang sinkron (baik, setidaknya deterministik)?
ELLIOTTCABLE
0

Dalam pengaturan tegukan saya, saya menentukan file vendor terlebih dahulu dan kemudian menentukan (lebih umum) semuanya, kedua. Dan itu berhasil menempatkan vendor js di atas hal-hal khusus lainnya.

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

Tampaknya Anda dapat meneruskan opsi "nosort" ke gulp.src gulp.src .

Wildhammer
sumber