Складіть сценарії в порядку з Gulp


192

Скажімо, наприклад, ви будуєте проект на «Магістралі» або будь-якому іншому, і вам потрібно завантажити сценарії в певному порядку, наприклад, underscore.jsйого потрібно завантажити раніше backbone.js.

Як змусити його складати сценарії так, щоб вони були в порядку?

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

У мене правильний порядок скриптів у своєму source/index.html, але оскільки файли впорядковані за алфавітом, gulp буде накладений underscore.jsпісля backbone.js, а порядок скриптів у моєму source/index.htmlзначенні не має значення, він переглядає файли в каталозі.

Так хтось має ідею з цього приводу?

Краща ідея у мене є перейменовувати скрипти постачальника з 1, 2, 3щоб дати їм належний порядок, але я не впевнений , якщо я так.

Коли я дізнався більше, я виявив, що Browrify - це чудове рішення, спочатку це може бути болем, але це чудово.


4
Я можу зазначити, що зараз я використовую перегляд веб-сторінок. У нього є своя маленька крива навчання ІМО. Я спробував спочатку, але глотком перегляньте це класний спосіб! Дозвольте ваш код бути модульним! Ви обробляєте замовлення в шифрованому режимі, тому з’єднання не потрібно при використанні браузера.
Майкл Джозеф Обрі

Хочете дати детальну інформацію про ваше рішення чи посилання?
Дмитро Зайцев

kroltech.com/2013/12/… ось посилання на проект котлована, який дійсно допоміг мені почати з гарного управління проектами. Після страждань від навчання всього цього я можу значно краще керувати своїми проектами. У нього є проект на github, і ви можете побачити, як він використовує перегляд веб-сторінок. Youtube завжди допомагає, і, звичайно, саме джерело завжди недооцінюється github.com/substack/node-browserify#usage
Майкл Джозеф Обрі

В основному ідея полягає в тому, щоб використовувати синтаксис npm, як синтаксис requireна передньому кінці, тому що, звичайно, якщо ви використовували npm на стороні свого сервера, ви бачите, як можна вимагати модулі, але перегляд веб-перегляду дозволяє зробити це на коді клієнта. маючи на увазі, щоб почати роботу, потрібно трохи попрацювати, але це, головним чином, всередині пакета.json, і якщо ви хочете використовувати з gulp.js або grunt.js. Якщо ви встановите пакет "gulp / grunt" для перегляду, ви можете запустити gulp/grunt browserifyі перетворити свій скрипт в один основний сценарій, це незначна крива навчання, але варто цього IMO.
Майкл Джозеф Обрі

Дякую! Взагалі -то я натрапив на велику статтю medium.com/@dickeyxxx / ... роблю точку добре , що ви на насправді не потрібні browserifyдля Angularмодулів, де прості роботи конкатенації і порядок не має значення :)
Дмитро Зайцев

Відповіді:


199

Нещодавно у Грунта у мене була подібна проблема під час створення мого додатка AngularJS. Ось питання, яке я опублікував.

Що я в кінцевому підсумку робив - це явно перелічити файли в порядку в конфігурації grunt. Конфігураційний файл буде виглядати приблизно так:

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

Grunt здатний розібратися, які файли є дублікатами, а не включити їх. Ця ж техніка буде працювати і з Gulp.


74
До речі, це добре працює і під залпом. Gulp також не повторюватиме файли.
OverZealous

1
Класні хлопці, ці два шедеври - приголомшливі. Я лише нарешті налаштував свій файл gulp.js, щоб він працював так, як я хочу, написав у якийсь html файл, зберег файл і розгорнув сайт, побудований з найкращими рамками та передовою практикою одним натисканням кнопки. Крім того, оновлення буде легким, якщо ви не використовуєте жодного, що вам потрібно!
Майкл Джозеф Обрі

1
Так! Я почав використовувати Grunt нещодавно, і це приголомшливо. Більше не вставляти програми JavaScript у рамки програм.
Чад Джонсон

3
Gulp копіював файли в моїй спробі, але я зрозумів, що у мене справа відрізняється від gulp порівняно з файловою системою, тому слідкуйте за цим! При точному випадку, gulp не копіюватиме файли.
Кріс

2
Ручне замовлення - це кошмар у серйозному проекті. Існують спеціальні сортувальники файлів - для angularjs та інших.
zhekaus

135

Інша річ, яка допомагає, якщо вам потрібні деякі файли після того, як з'являються певні файли , - це виключити конкретні файли зі свого глобуса, наприклад:

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

Ви можете поєднати це із зазначенням файлів, які повинні бути першими, як пояснено у відповіді Чада Джонсона.


Так, я фактично бачив вашу публікацію раніше, і це допомогло мені ввести код до мого, srcі buildя побачив, як ви використовуєте цей синтаксис, і я закінчив стерти цю частину, тому що я не був впевнений, чому саме мені це потрібно, має сенс зараз.
Майкл Джозеф Обрі

Ну добре, тож ваш пункт тут просто мене вдарив, хіба що це зробить foobar.js останнім? Чи не повинно бути навпаки. ['./source/js/*.js', './source/js/**/underscore.js', './source/js/**/!(underscore)*.js']
Майкл Джозеф Обрі

Так, це було лише додатковою допомогою. Це найкорисніше, коли вам потрібно або ви хочете, щоб ваш основний код програми вводився після завантаження всього іншого. Немає жодної причини використовувати його ( !(foobar)), якщо ви заздалегідь включили певний файл.
OverZealous

Для програми AngularJS, де визначення мого модуля знаходяться у файлах, у назві яких "немає тире", цей глобульний шаблон Gulp працював; ['src/app/**/!(*-)*.js', 'src/app/**/*.js']
Сем Т

17

Я використовував плагін gulp-order, але він не завжди є успішним, як ви можете бачити за моїм модулем вузла порядку переповнення стека з об'єднаними потоками . Під час перегляду документів Gulp я натрапив на модуль струму, який досить добре попрацював для визначення порядку в моєму випадку конкатенації. https://github.com/gulpjs/gulp/blob/master/docs/recipes/using-multiple-sources-in-one-task.md

Приклад того, як я його використав, наведено нижче

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

Дивіться також потокові серії . Це не вимагає, щоб ви вказували режим об'єкта, і працює з gulp-inject. Дивіться мою відповідь.
кодування

здається, половина плагінів gulp просто не працюють послідовно (як на замовлення, як ви вказали), що є кричущим ганьбою, тому що архітектурна концепція gulp вражаюча, так що дуже багато людей, які реалізують і підтримують свої плагіни погано, я думаю ... Я вважаю, що основні модулі вузлів корисніші, тому дякую за це рішення! Чудово працює!
Джиммі Хоффа

1
streamqueue, event-stream не працював для мене, але merge2 працював як очікувалося npmjs.com/package/merge2
Олександр Шутау

12

За допомогою gulp-useref ви можете об'єднати кожен скрипт, оголошений у вашому індексному файлі, у тому порядку, в якому ви його оголосите.

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

І в HTML ви повинні оголосити ім'я файла збірки, який ви хочете створити, як це:

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

У вашому каталозі збірки ви матимете посилання на main.min.js, який буде містити vendor.js, test.js та main.js


2
Це прекрасно! Я ненавидів відповіді, де мені потрібно визначити порядок! Знаєш, що? Порядок є: у файлі HTML. Ідеальне рішення.
Алі Ок

6

Сортування потік також може бути використаний для забезпечення певного порядку файлів з gulp.src. Приклад коду, який ставить backbone.jsзавжди як останній файл, який обробляється:

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

Я б хотів, щоб цей модуль працював, тому що це здається найпростішою відповіддю для мене, але в моєму випадку, де я пронумерував імена файлів і дуже просто функцію порівняння, це не працює.
Джеремі Джон

5

Я просто додаю числа до початку імені файлу:

0_normalize.scss
1_tikitaka.scss
main.scss

Працює залпом без проблем.


1
Так, я вважаю це трохи простіше, я маю на увазі, якщо ви збираєте всі файли для виробництва, це не має значення, що ви називаєте ваші файли в процесі розробки.
Майкл Джозеф Обрі

2
Щойно я з’ясував, що це працює не правильно. спробуйте використовувати 1_xx, 2_xx, 10_xx, 11_xx. Під Windows принаймні це буде 1_xx, 10_xx, 11_xx, 2_xx
dbinott

17
Особисто я майже повністю не згоден із твердженням, що не має значення, як ви називаєте ваші файли в процесі розробки. Увесь розвиток має бути спершу орієнтованим на людину, а не на комп'ютер. Зміна ваших файлів, щоб вони відповідали вашому інструменту збирання, перемагає призначення інструменту збирання. Змініть свій збір, щоб відповідати вашому проекту, а не навпаки.
Джон Хіб

2
@JonHieb Певним чином, префіксація ваших файлів цифрою також допоможе наступному розробникові дізнатися про залежності кожного файлу, ні? Якщо я відкрию папку і побачу 1_foo.js, 2_bar.js, 3_baz.js, я відкрию ці файли в тому порядку і прочитаю початок читання коду з 1_foo.js
sqram

Я виявив, що gulp.src виконує функцію async, а це означає, що це не працює послідовно у випадках, коли в редакторі є більше файлів для обробки.
Джеремі Джон

5

У мене є сценарії, організовані в різні папки для кожного пакета, який я витягую з шафи, а також власний сценарій для свого додатка. Оскільки ви збираєтеся десь перераховувати порядок цих скриптів, чому б просто не перерахувати їх у своєму файлі gulp? Для нових розробників вашого проекту приємно, що всі кінцеві точки сценарію перераховані тут. Це можна зробити за допомогою 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']);

Примітка: jQuery та Bootstrap додані для демонстраційних цілей замовлення. Можливо, краще використовувати CDN для тих, оскільки вони настільки широко використовуються, і браузери можуть вже кешувати їх з інших сайтів.


3

Спробуйте потокові серії . Він працює як merge-stream / event-stream.merge (), за винятком того, що замість переплетення додається до кінця. Це не вимагає, щоб ви вказували режим об'єкта, як streamqueue , тому ваш код виходить більш чистим.

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 схожий на єдиний на даний момент працюючий та підтримуваний впорядкований інструмент злиття потоку.

Оновлення 2020 року

API завжди змінюються, деякі бібліотеки стають непридатними або містять вразливості, або їх залежності містять уразливості, які не фіксуються роками. Для маніпуляцій текстовими файлами краще використовувати спеціальні сценарії NodeJS та популярні бібліотеки, як globbyі fs-extraпоряд з іншими бібліотеками без обгортки Gulp, Grunt тощо.

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

Альтернативний метод - використовувати плагін Gulp, створений спеціально для цієї проблеми. https://www.npmjs.com/package/gulp-ng-module-sort

Це дозволяє сортувати ваші сценарії, додаючи .pipe(ngModuleSort())такі як:

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

Припустимо, що конвенція про каталог:

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

Сподіваюся, це допомагає!


1

Для мене я мав natualSort () та angularFileSort () у трубі, яка переупорядковувала файли. Я його зняв і тепер він працює добре для мене

$.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

Я просто використовую gulp-angular-filesort

function concatOrder() {

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

ой, я щойно зрозумів, що ви не питаєте про кутовий, вибачте
Maccurt

0

Я перебуваю в модульному середовищі, де всі залежні від ядра, що використовують gulp. Отже, coreмодуль потрібно додати перед іншими.

Що я зробив:

  1. Перемістіть усі сценарії до srcпапки
  2. Просто gulp-renameваш coreкаталог в_core
  3. gulp дотримується порядку вашого gulp.src , мій конмат srcвиглядає так:

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

Очевидно, це буде _перший каталог зі списку (природний сорт?).

Примітка (angularjs): я потім використовую gulp- -extender, щоб динамічно додавати модулі до coreмодуля. Складено це виглядає приблизно так:

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

Де Адміністратор та Продукти - це два модулі.


0

якщо ви хочете замовити залежність від бібліотек сторонніх розробників, спробуйте провідним способом . Цей пакет в основному перевіряє залежність кожного пакета в bower.json, а потім передає їх вам.


0

Я спробував кілька рішень з цієї сторінки, але жодне не спрацювало. У мене була серія пронумерованих файлів, які я просто хотів, щоб вони були упорядковані за алфавітним іменем папки, тому, коли трубопроводи, concat()вони будуть в тому ж порядку. Тобто збережіть порядок вхідних даних. Легко, правда?

Ось мій конкретний код підтвердження концепції ( printлише щоб побачити замовлення, надруковані на кліпі):

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

Причина божевілля gulp.src? Я визначив, що gulp.srcпрацює асинхронізація, коли мені вдалося використати sleep()функцію (використовуючи a.map сну, посилений за індексом), щоб правильно замовити вихід потоку.

Підсумок асинхронізації srcсереднього dirs з більшою кількістю файлів у ньому відбувся після того, як у dirs було менше файлів, оскільки їх обробка займала більше часу.


1
Ви знайшли синхронну (ну, принаймні детерміновану) альтернативу?
ELLIOTTCABLE

0

У моєму налаштуванні gulp я вказую спочатку файли постачальника, а потім вказую (більш загальне) все, друге. І він успішно ставить js постачальника перед іншими спеціальними речами.

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.