همهی ما کمابیش با Git آشنا هستیم، همچنین از ماهیت و کاربرد ابزارهایی مانند Grunt و Gulp آگاهیم. Grunt و Gulp هر دو تقریباً برای یک کاربرد ساخته شدهاند، اما Gulp سرعت بیشتری داره و علاوه بر این، پلاگینهای زیادی هم برای استفاده داره. برای مطالعه بیشتر درمورد Gulp و راهاندازی اون میتونید به «شروع استفاده از Gulp»سر بزنید.
در این مطلب، قصد دارم پلاگینی برای کنترل و برقراری ارتباط با مخازن Git معرفی کنم، نام اون احتمالاً قابلحدسه: gulp-git
شما با استفاده از gulp-git میتونید با هر مخزن Git مثل GitHub و یا Bitbucket ارتباط برقرار کنید و از همون دستورهای معمول گیت استفاده کنید. در ادامه، با هم یک پروسس برای گالپ مینویسیم که CSSهای مخزن رو دریافت، سپس آنها را Minify و جمع کند و نتیجه رو به مخزن Commit کند.
چنین پروسسی قطعاً برای کارهای تیمی که مرتباً روی Git قرار میگیرند، بسیار مفید خواهد بود. با استفاده از Trigger حتی میتوانید پس از هر کامیت، پراسس رو به صورت اتوماتیک اجرا کنید.
راهاندازی پروژه
ابتدا مطمئن شوید که NodeJS و Gulp را به خوبی نصب و پیکربندی کردهاید. برای پروژهای که مدنظر داریم، به gulp-git، gulp-concat و gulp-minify-css و gulp-uglify نیاز داریم. کار رو با نصب این پلاگینها با استفاده از npm شروع میکنیم.
npm install -g gulp-git gulp-concat gulp-uglify gulp-minify-css
-دقت کنید که شاید به sudo نیاز داشته باشید.
حالا که پلاگینها نصب شدهاند، میتوانیم نوشتن Tasks رو آغاز کنیم.
پیشنهاد میکنم که در یک دایرکتوری جدا، فایل gulpfile.js خود را ایجاد کنید.
شروع اسکریپتنویسی
مراحل کار اسکریپت ما به این صورت است:
- Clone یا Pull از مخزن موردنظر (اگر با این مفاهیم آشنا نیستید، مقالات راجعبه Gitرا مطالعه کنید)
- Build فایلهای CSS و JavaScript پروژه و Concat آنها
- کامیت به مخزن
کار رو با فراخوانی Dependencies و پلاگینها شروع میکنیم:
// gulpfile.js var gulp = require( 'gulp' ); var git = require( 'gulp-git' ); var minifyCss = require( 'gulp-minify-css' ); var uglify = require( 'gulp-uglify' ); var concat = require( 'gulp-concat' ); var fs = require( 'fs' );
حالا که Dependencyها فراخوانی شدند، نیاز به آدرس مخزن داریم، بهتر است آدرس را به صورت عمومی در یک ثابت تعریف کنیم. همچنین نام مخزن را در یک ثابت جداگانه ذخیره کنید، زیرا بعداً به آن نیاز خواهیم داشت.
const repo = "https://ehsaan:pass@github.com/ehsaan/test-repo.git"; const repo_name = "test-repo";
اگر به آدرس مخزن دقت کنید، میبینید که من هم نامکاربری و هم رمزعبور رو در آدرس تعریف کردهام، شما هم میتوانید این کار را انجام بدهید و رمزعبور خود را همینجا قرار بدهید، ولی اگر حذف کنید هم مشکلی پیش نمیآید، اما ممکن است در هنگام کار، چندبار رمزعبور از شما پرسیده شود.
همانطور که مراحل کار رو با هم مرور کردیم، برای سادگی و خوانایی بیشتر کد، هر کدوم از مراحل رو در یک Task جدا تعریف میکنیم.
مرحله اول: دانلود
در مرحله اول، ما مخزن را دانلود میکنیم، برای دانلود از گیت، ما باید مخزن را اصطلاحاً Clone کنیم، اما اگر مخزن قبلاً دانلود شده باشد، باید فایلهای جدید را Pull کنیم. به همین دلیل ابتدا چک میکنیم که آیا مخزن قبلاً کلون شده یا نه؟
ابتدا، Task مربوط را میسازیم، من اسم Task را download میگذارم.
// gulpfile.js //... gulp.task( 'download', function() { if ( fs.existsSync( repo_name ) ) { // That means repository already cloned, we just need to pull. } else { // All right, we need to clone } } );
همانطور در کد میبینید، ابتدا چک میکنیم که آیا مخزن قبلاً کلون شده یا خیر؟ اما این کار چگونه میسر است؟ وقتی یک مخزن را کلون میکنید، Git به صورت خودکار، محتویات مخزن را در دایرکتوری با نام همان مخزن میریزد، بنابراین اگر قبلاً کلون شده باشد، قطعاً باید دایرکتوری با نام مخزن موردنظر قبلاً وجود داشته باشد. بنابراین یک شرط تعریف میکنیم که اگر دایرکتوری با نام مخزن موجود بود، نیاز به Pull و در صورتی که نبود، باید مخزن را کلون کرد.
ابتدا از Clone مخزن شروع میکنیم، برای بلوک else کدهای زیر را مینویسم:
// gulpfile.js // ... else { git.clone( repo, function( err ) { if ( err ) throw err; } ); }
میتوانیم کارکرد کد را تست کنیم، اول فایل را ذخیره کنید و سپس در ترمینال، به دایرکتوری که gulpfile.js وجود دارد تغییر مسیر بدهید. حالا با اجرای دستور gulp download میتوانید از کارکرد آن اطمینان حاصل کنید. البته فراموش نکنید که به ثابتهای repo و repo_name مقادیر صحیح و معتبر بدهید.
در صورتی که فرآیند کلون به خوبی انجام شده باشد، در دایرکتوری کار ما، باید یک دایرکتوری با نام مقدار repo_name ایجاد شده باشد و حاوی محتوای مخزن باشد.
همانطور که در اسکرینشات مشاهده میکنید، اسکریپت به خوبی در محیط Koding اجرا شد.
حالا در صورتی که مجدداً اسکریپت را اجرا کنید، Task بسیار سریع اجرا میشود، زیرا در شرطی که تعریف کردیم، هنوز دستوری برای برقراربودن شرط تعریف نکردهایم. دستور موردنظر برای اجرا، Pull خواهد بود، زیرا قصد داریم که صرفاً فایلهای جدید را دانلود کنیم.
//gulpfile.js //.... if ( fs.existsSync( repo_name ) ) { git.pull( 'origin', 'master', { cwd: './' + repo_name + '/' }, function( err ) { if ( err ) throw err; } ); } else { //....
اگر با گیت آشنا باشید، میدانید که Git برای کار با مخزنهای ریموت، از چندین مخزن پشتیبانی میکند، یعنی شما میتوانید چندین مخزن آنلاین همزمان داشته باشید و بین هر کدام سوییچ کنید. اما مخزن آنلاین پیشفرض origin نام دارد، در واقع در کد ما تعریف میکنیم که مخزن پیشفرض را آپدیت کند. پارامتر بعدی Branch موردنظر است که پیشفرض آن master است.
در پارامتر بعدی، شما میتوانید تعدادی پارامتر دلخواه برای هر دستور تعریف کنید (اطلاعات بیشتر درمورد دستورات)، از جمله این پارامترها cwd است که تعیین میکند که دستور موردنظر در کدام دایرکتوری اجرا شود.
در Callback فانکشن هم چک میکنیم که اگر مشکلی پیش آمد، جزییات مشکل را Throw کند.
بدین ترتیب تا به اینجا کد مربوط به دانلود را نوشتیم و اگر مراحل را درست طی کرده باشید، باید مخزن را Clone کند و اگر Cloneشده بود، آن را Pull کند.
کد کامل مربوط به Task download رو نوشتم:
// gulpfile.js // ... gulp.task( 'download', function() { if ( fs.existsSync( repo_name ) ) { git.pull( 'origin', 'master', { cwd: './' + repo_name + '/' }, function( err ) { if ( err ) throw err; } ); } else { git.clone( repo, function( err ) { if ( err ) throw err; } ); } } );
مرحله دوم: Build
برای Build از سه پلاگین Minify CSS، Uglify و Concat استفاده میکنیم. ابتدا یک Task برای CSS ایجاد میکنیم.
// gulpfile.js // ... gulp.task( 'build-css', [ 'download' ], function() { // CSS Build process goes here... } );
همانطور که مشاهده میکنید، یک Task جدید با نام build-css ساخته شد. همچنین یک Dependency برای این Task نیز تعریف کردیم، به این معنی که این Task برای اجراشدن نیاز دارد که یک Task پیش از آن، اجرا شود. برای build-css همانطور که تعریف کردیم، نیاز است تا ابتدا وظیفه download اجرا شود.
حالا کدهای مربوط به build-css را مینویسیم.
// gulpfile.js // ... gulp.task( 'build-css', [ 'download' ], function() { return gulp.src( repo_name + '/css/*.css' ) .pipe( minifyCss() ) .pipe( concat( 'package.css' ) ) .pipe( gulp.dest( repo_name + '/dist/' ) ); } );
همانطور که در کد مشخص است، ابتدا فایلهای CSS را از دایرکتوری css در مخزن میخوانیم، آنها را minify و سپس در فایل package.css جمع میکنیم و در دایرکتوری dist در مخزن میریزیم. به همین راحتی 😉
مشابه همین Task را برای Javascript با نام build-js مینویسم، با آن تفاوت که به جای minifyCSS از uglify استفاده میکنم.
// gulpfile.js // ... gulp.task( 'build-js', [ 'download' ], function() { return gulp.src( repo_name + '/js/*.js' ) .pipe( uglify() ) .pipe( concat( 'build.js' ) ) .pipe( gulp.dest( repo_name + '/dist/' ) ); } );
حالا اگر build-css و build-js را اجرا کنید، میبینید که خیلی روان کار میکند!
مرحله آخر: آپلود
و میرسیم به مرحله آخر که آپلود فایلهای Buildشده به مخزن گیت است. همانطور که میدانید آپلود به مخزن Git به طور معمول نیازمند سه عمل است.
- Addکردن فایلهای جدید
- Commit
- Push
اسکریپت ما هم از این قاعده مستثنی نیست. بنابراین نیازمند ایجاد سه Task جدا برای هرکدام هستیم.
// gulpfile.js // ... gulp.task( 'add', [ 'build-css', 'build-js' ], function() { } ); gulp.task( 'commit', [ 'add' ], function() { } ); gulp.task( 'push', [ 'commit' ], function() { } );
خب، Taskهای ما آماده هستن برای پذیرفتن کد! همونطور که در کد میبینید، add نیاز داره که اول build-css و build-js اجرا بشن. commit به اجرای کامل add نیاز داره و push هم به اجرای commit. بنابراین وقتی شما gulp push را اجرا کنید، تمامی Taskها باید به ترتیب مدنظرمون اجرا بشن.
ابتدا از add شروع میکنیم، به لطف Pipe در nodeJS فقط میتوانیم فایلهای موردنظرمان، آن هم به راحتی Add کنیم.
// gulpfile.js // ... gulp.task( 'add', [ 'build-css', 'build-js' ], function() { return gulp.src( './' + repo_name + '/dist/**/*.*' ) .pipe( git.add( { cwd: './' + repo_name + '/' } ) ); } );
در Task ابتدا در دایرکتوری مخزن سپس dist و همه فایلها و فولدرها میگردیم و همه فایلها را به کامیت جدید اضافه میکنیم. دقت کنید که برای دستور git.add نیاز به cwd هستیم که علت آن را پیشتر توضیح دادهام.
حالا برای commit به همین صورت عمل میکنیم.
// gulpfile.js // ... gulp.task( 'commit', [ 'add' ], function() { return gulp.src( './' + repo_name + '/dist/**/*.*' ) .pipe( git.commit( 'Automated Build by Gulp', { cwd: './' + repo_name + '/' } ) ); } );
git.commit یک پارامتر اجباری به نام message دارد که همان پیام برای کامیت است و متنی که من نوشتم Automated Build by Gulp است که مشخص شود که Gulp این تغییرات را انجام داده است.
و مرحله آخر! کافیست که فقط دستور git.push را در دایرکتوری موردنظر انجام دهیم!
// gulpfile.js // ... gulp.task( 'push', [ 'commit' ], function() { git.push( 'origin', 'master', { cwd: './' + repo_name + '/', args: ' -u' }, function( err ) { if ( err ) throw err; } ); } );
درمورد origin و master قبلاً توضیح دادهام. دقت کنید که اگر در Clone و Pull، مقدار مربوط به Branch را تغییر دادهاید، حتماً همینجا هم تغییر بدهید. همچنین چون با یک مخزن ریموت (از راه دور) کار میکنیم، آرگومنت -u را هم تعریف کردم.
حالا نوبت جمعبندی این Taskهاست! کافیست که یک Task به نام default تعریف کنیم تا Gulp آن را به صورت خودکار بشناسد. ولی نام Task، default باشد، با اجرای دستور gulp ، کدهای مربوط به default اجرا میشود.
// gulpfile.js // ... // Now, default task to run all them in arrange gulp.task( 'default', function() { gulp.start( 'download', 'build-css', 'build-js', 'add', 'commit', 'push' ); // and Done! } );
همهچیز آماده است تا فقط ما دستور gulp را در دایرکتوری که gulpfile.js قرار دارد، اجرا کنیم!
جمعبندی
اگر با Gulp هم آشنا نبودهاید، شاید با مطالعه این آموزش به آن علاقهمند شده باشید؛ Gulp میتواند در یک پروژه متوسط، یار شما باشد و بسیاری از کارها را برای شما آسانتر کند.
کد کامل مربوط به این Receipt را در Gist به اشتراک گذاشتهام. ممنون میشوم نظرات خودتون، پیشنهاد و اشکالاتی که مشاهده کردید رو از طریق بخش دیدگاهها اطلاع بدید 🙂
آموزش بسیار با ارزش و ارزنده ای را ارائه فرمودید
با سلام
خیلی عالی بود
ممنون