Skrypty Concat w porządku z Gulpem

192

Powiedzmy, na przykład, że budujesz projekt w sieci szkieletowej lub czymkolwiek innym i musisz załadować skrypty w określonej kolejności, np. Trzeba underscore.jsje wcześniej załadować backbone.js.

Jak uzyskać powiązanie skryptów, aby były w porządku?

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

Mam prawo kolejność skryptów w moim source/index.html, ale ponieważ pliki są zorganizowane według kolejności alfabetycznej, łyk będzie Concat underscore.jspo backbone.js, a kolejność skryptów w moim source/index.htmlnie ma znaczenia, to wygląda na pliki w katalogu.

Czy ktoś ma na to pomysł?

Najlepszy pomysł mam jest do zmiany nazwy skryptów dostawcy z 1, 2, 3aby dać im właściwej kolejności, ale nie jestem pewien, czy mi się to podoba.

Gdy dowiedziałem się więcej, odkryłem, że Browserify to świetne rozwiązanie, na początku może być uciążliwe, ale jest świetne.

Michael Joseph Aubry
źródło
4
Mógłbym wspomnieć, że teraz używam Browserify. Ma własną małą krzywą uczenia się IMO. Na początku walczyłem, ale przełknięcie przeszukiwania to świetny sposób! Umożliwiając modułowy kod! Obsługujesz zamówienie w mgnieniu oka, więc łączenie nie jest konieczne podczas korzystania z Browserify.
Michael Joseph Aubry
Chcesz podać więcej szczegółów na temat swojego rozwiązania lub linku?
Dmitri Zaitsev
kroltech.com/2013/12/… tutaj jest link do projektu, który naprawdę pomógł mi zacząć od dobrego zarządzania projektem. Po cierpieniu z tego wszystkiego mogę znacznie lepiej zarządzać swoimi projektami. Ma projekt na githubie i możesz zobaczyć, jak korzysta z przeglądania. Youtube zawsze pomaga i oczywiście samo źródło jest zawsze niedoceniane github.com/substack/node-browserify#usage
Michael Joseph Aubry
Zasadniczo pomysł polega na możliwości użycia npm ze składnią requirena frontonie, ponieważ oczywiście, jeśli używałeś npm po stronie serwera, widzisz, jak możesz wymagać modułów, ale Browserify pozwala ci to zrobić po stronie klienta, zachowaj aby zacząć, wymaga trochę majsterkowania, ale głównie w pakiecie.json i jeśli chcesz używać go z gulp.js lub grunt.js. Jeśli zainstalujesz pakiet przeszukiwania gulp / grunt, możesz uruchomić gulp/grunt browserifyi zamienić skrypt w jeden główny skrypt, jest to niewielka krzywa uczenia się, ale warto IMO.
Michael Joseph Aubry
Dzięki! Faktycznie natknąłem wielki artykuł medium.com/@dickeyxxx/... dokonywania punkt dobrze, że tak naprawdę nie potrzeba browserifydo Angularmodułów, gdzie proste prace konkatenacji i kolejność nie ma znaczenia :)
Dmitrij Zajcew

Odpowiedzi:

199

Miałem podobny problem z Gruntem podczas tworzenia mojej aplikacji AngularJS. Oto pytanie, które opublikowałem.

Skończyło się na jawnym wyświetleniu listy plików w kolejności w konfiguracji gruntu. Plik konfiguracyjny będzie wyglądał następująco:

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

Grunt jest w stanie dowiedzieć się, które pliki są duplikatami, a nie uwzględnić ich. Ta sama technika będzie również działać z Gulpem.

Chad Johnson
źródło
74
Nawiasem mówiąc, działa to również dobrze w przypadku łyku. Gulp też nie powtórzy plików.
OverZealous
1
Fajni ludzie, te dwa arcydzieła są niesamowite. Właśnie w końcu skonfigurowałem mój plik gulp.js, aby działał tak, jak chcę, napisałem w html, zapisałem plik i przebudziłem witrynę zbudowaną z najlepszych ram i dobrych praktyk za naciśnięciem jednego przycisku. Plus aktualizacje będą łatwe, jeśli nie używasz żadnego z nich, musisz!
Michael Joseph Aubry
1
Tak! Ostatnio zacząłem używać Grunta i jest niesamowity. Nigdy więcej osadzania aplikacji JavaScript w ramach backendów.
Chad Johnson
3
Gulp kopiował pliki podczas mojej próby, ale zdałem sobie sprawę, że mam inny przypadek w gulp niż w systemie plików, więc uważaj na to! Dokładnie, gulp nie powiela plików.
Chris,
2
Ręczne zamawianie to koszmar w poważnym projekcie. Istnieją specjalne sortowniki plików - dla angularjs i innych.
zhekaus
135

Kolejną rzeczą, która pomaga, jeśli potrzebujesz niektórych plików po kropli plików, jest wykluczenie określonych plików z globu, na przykład:

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

Możesz to połączyć z określeniem plików, które muszą być na pierwszym miejscu, jak wyjaśniono w odpowiedzi Chada Johnsona.

OverZealous
źródło
Ach, faktycznie widziałem twój post wcześniej i pomogło mi to w wstrzykiwaniu kodu do mojego, srca do mojego buildwidziałem, jak używasz tej składni, skończyłem z usuwaniem tej części, ponieważ nie byłem pewien, dlaczego go potrzebowałem, ma to teraz sens.
Michael Joseph Aubry
No dobrze, więc twój punkt tutaj po prostu mnie uderzył, czy to nie sprawi, że plik foobar.js będzie trwał? Nie powinno być na odwrót. ['./source/js/*.js', './source/js/**/underscore.js', './source/js/**/!(underscore)*.js']
Michael Joseph Aubry
Tak, to była tylko dodatkowa pomoc. Jest to najbardziej przydatne, gdy potrzebujesz lub chcesz, aby Twój główny kod aplikacji pojawił się po załadowaniu wszystkiego innego. Nie ma powodu, aby go używać ( !(foobar)), jeśli wcześniej zawarłeś konkretny plik.
OverZealous
W przypadku aplikacji AngularJS, w której moje definicje modułów znajdują się w plikach bez „myślnika” w nazwie, działał ten wzorzec globu Gulpa; ['src/app/**/!(*-)*.js', 'src/app/**/*.js']
Sam T
17

Użyłem wtyczki gulp-order, ale nie zawsze się to udaje, jak widać po moim przepełnieniu stosu moduł węzła zamówienia gulp ze scalonymi strumieniami . Przeglądając dokumenty Gulpa natknąłem się na moduł streamque, który całkiem dobrze działał w określaniu kolejności konkatenacji w moim przypadku.https://github.com/gulpjs/gulp/blob/master/docs/recipes/using-multiple-sources-in-one-task.md

Przykład tego, jak go użyłem, znajduje się poniżej

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
źródło
Zobacz także serie strumieniowe . Nie wymaga określania trybu obiektowego i działa z gulp-inject. Zobacz moją odpowiedź.
Codebling
wygląda na to, że połowa wtyczek Gulp po prostu nie działa konsekwentnie (jak porządek, jak wskazałeś), co jest płaczącym wstydem, ponieważ koncepcja architektoniczna Gulp jest spektakularna, tak wielu ludzi źle wdraża i utrzymuje swoje wtyczki, myślę ... Uważam, że podstawowe moduły węzłów są bardziej przydatne, więc dziękuję za to rozwiązanie! Działa świetnie!
Jimmy Hoffa
1
streamqueue, event-stream nie działał dla mnie, ale merge2 działał zgodnie z oczekiwaniami npmjs.com/package/merge2
Alexander Shutau
12

Dzięki gulp-useref możesz połączyć każdy skrypt zadeklarowany w pliku indeksu w kolejności, w której go deklarujesz.

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

W HTML musisz zadeklarować nazwę pliku kompilacji, który chcesz wygenerować:

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

W twoim katalogu kompilacji będziesz mieć odniesienie do main.min.js, który będzie zawierał vendor.js, test.js i main.js

SuperIRis
źródło
2
To jest doskonałe! Nienawidziłem odpowiedzi, w których potrzebowałem zdefiniować porządek! Wiesz co? Kolejność jest tam: w pliku HTML. Idealne rozwiązanie.
Ali Ok
6

Strumień sortowania można również wykorzystać do zapewnienia określonej kolejności plików gulp.src. Przykładowy kod, który umieszcza backbone.jszawsze jako ostatni plik do przetworzenia:

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
źródło
Chciałbym, żeby ten moduł działał, ponieważ wydaje mi się to najprostszą odpowiedzią, ale w moim przypadku, gdzie mam ponumerowane nazwy plików i bardzo prostą funkcję porównania, to nie działa.
Jeremy John
5

Po prostu dodaję cyfry na początku nazwy pliku:

0_normalize.scss
1_tikitaka.scss
main.scss

Działa w łyku bez żadnych problemów.

użytkownik3360496
źródło
1
Tak, uważam, że jest to trochę łatwiejsze, to znaczy, jeśli kompilujesz wszystkie swoje pliki do produkcji, nie ma znaczenia, jak je nazywasz w fazie projektowania.
Michael Joseph Aubry
2
Właśnie się dowiedziałem, że to nie działa poprawnie. spróbuj użyć 1_xx, 2_xx, 10_xx, 11_xx. Przynajmniej w systemie Windows będzie to 1_xx, 10_xx, 11_xx, 2_xx
dbinott
17
Osobiście całkowicie nie zgadzam się ze stwierdzeniem, że nie ma znaczenia, jak nazwiesz swoje pliki w fazie rozwoju. Cały rozwój powinien skupiać się przede wszystkim na człowieku, a nie na komputerze. Zmiana plików tak, aby pasowała do narzędzia do budowania, przeczy celowi tego narzędzia. Zmień kompilację, aby pasowała do projektu, a nie na odwrót.
Jon Hieb
2
@JonHieb W pewnym sensie prefiksowanie plików numerem pomoże również następnemu programistowi poznać zależności między poszczególnymi plikami, prawda? Jeśli otworzę folder i zobaczę 1_foo.js, 2_bar.js, 3_baz.js, otworzę te pliki w tej kolejności i przeczytam zacznij czytać kod na 1_foo.js
sqram
Odkryłem, że gulp.src działa asynchronicznie, co oznacza, że ​​nie działa to konsekwentnie w przypadkach, gdy w katalogu jest więcej plików do przetworzenia.
Jeremy John
5

Skrypty mam uporządkowane w różnych folderach dla każdego pakietu, który ściągam z altany, oraz własny skrypt dla mojej aplikacji. Skoro zamierzasz podać gdzieś kolejność tych skryptów, dlaczego nie po prostu wymienić ich w pliku gulp? Dla nowych deweloperów twojego projektu fajnie jest, że wymieniono tutaj wszystkie punkty końcowe skryptu. Możesz to zrobić za pomocą 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']);

Uwaga: Dodano jQuery i Bootstrap dla celów demonstracyjnych porządku. Prawdopodobnie lepiej jest używać CDN dla tych, ponieważ są one tak szeroko stosowane, a przeglądarki mogą już je buforować z innych stron.

prograhammer
źródło
3

Wypróbuj serie strumieniowe . Działa jak merge-stream / event-stream.merge () z tym wyjątkiem, że zamiast przeplatania dołącza się do końca. Nie wymaga to określania trybu obiektowego, takiego jak streamqueue , więc kod jest czystszy.

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
źródło
2

merge2 wygląda obecnie na jedyne działające i utrzymywane narzędzie do scalania uporządkowanych strumieni.

Aktualizacja 2020

Interfejsy API zawsze się zmieniają, niektóre biblioteki stają się bezużyteczne lub zawierają luki, lub ich zależności zawierają luki, które nie są naprawiane przez lata. Do manipulacji plikami tekstowymi lepiej jest używać niestandardowych skryptów NodeJS i popularnych bibliotek, takich jak globbyi fs-extrainne biblioteki bez Gulp, Grunt itp.

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
źródło
1

Alternatywną metodą jest użycie wtyczki Gulp stworzonej specjalnie dla tego problemu. https://www.npmjs.com/package/gulp-ng-module-sort

Pozwala sortować skrypty, dodając .pipe(ngModuleSort())jako takie:

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

Zakładając konwencję katalogów:

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

Mam nadzieję że to pomoże!

Dąb
źródło
1

Dla mnie miałem natualSort () i angularFileSort () w potoku, który zmieniał kolejność plików. Usunąłem go i teraz działa dla mnie dobrze

$.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
źródło
1

Po prostu używam gulp-angular-fileort

function concatOrder() {

    return gulp.src('./build/src/app/**/*.js')
        .pipe(sort())
        .pipe(plug.concat('concat.js'))
        .pipe(gulp.dest('./output/'));
}
Maccurt
źródło
Ups, właśnie zdałem sobie sprawę, że nie pytasz o kątowe, przepraszam
Maccurt
0

Jestem w środowisku modułowym, w którym wszyscy są zależni od rdzenia za pomocą gulp. Tak więccore moduł należy dołączyć przed innymi.

Co ja zrobiłem:

  1. Przenieś wszystkie skrypty do srcfolderu
  2. Tylko gulp-renametwój corekatalog do_core
  3. gulp.srcmój łyk utrzymuje porządek , mój konkat srcwygląda następująco:

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

Oczywiście zajmie to _jako pierwszy katalog z listy (sortowanie naturalne?).

Uwaga (angularjs): Następnie używam gulp- angular -extender, aby dynamicznie dodawać moduły do coremodułu. Skompilowane wygląda to tak:

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

Gdzie Administrator i Produkty to dwa moduły.

soja
źródło
0

jeśli chcesz zamówić zależności bibliotek stron trzecich, wypróbuj wiredep . Ten pakiet w zasadzie sprawdza każdą zależność pakietu w bower.json, a następnie łączy je za Ciebie.

zak.http
źródło
0

Próbowałem kilka rozwiązań z tej strony, ale żadne nie działało. Miałem serię plików z numerami, które po prostu chciałem uporządkować alfabetycznie nazwa pliku, więc po przesłaniu do concat()nich będą w tej samej kolejności. To znaczy, zachowaj kolejność globowania danych wejściowych. Łatwe, prawda?

Oto mój konkretny kod weryfikacyjny ( printtylko po to, żeby zobaczyć zamówienie wydrukowane na 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());
});

Powód szaleństwa gulp.src? Stwierdziłem, że gulp.srcdziała asynchronicznie, kiedy mogłem korzystać z sleep()funkcji (używając.map z czasem snu zwiększonym o indeks), aby poprawnie uporządkować wyjście strumienia.

Wynik asynchronizacji srcśrednich katalogów z większą liczbą plików nastąpił po katalogach z mniejszą liczbą plików, ponieważ ich przetwarzanie trwało dłużej.

Jeremy John
źródło
1
Czy znalazłeś synchroniczną (przynajmniej deterministyczną) alternatywę?
ELLIOTTCABLE
0

W mojej konfiguracji łyka, najpierw określam pliki dostawcy, a następnie (ogólniej) wszystko, po drugie. I z powodzeniem stawia js dostawcy przed innymi niestandardowymi rzeczami.

gulp.src([
  // vendor folder first
  path.join(folder, '/vendor/**/*.js'),
  // custom js after vendor
  path.join(folder, '/**/*.js')
])    
ProGrammar
źródło
0

Najwyraźniej możesz przekazać opcję „nosort” do gulp.src gulp.src .

Wildhammer
źródło