আপনার gruntfile সুপারচার্জিং

কিভাবে আপনার বিল্ড কনফিগারেশন থেকে সবচেয়ে বেশি চেপে ধরবেন

ভূমিকা

গ্রান্ট ওয়ার্ল্ড যদি আপনার কাছে নতুন হয়, তাহলে শুরু করার জন্য একটি আদর্শ জায়গা হল ক্রিস কোয়ারের চমৎকার প্রবন্ধ " Grunt for People Who Think Things Like Grunt is Weird and hard "। ক্রিসের পরিচয়ের পরে, আপনি আপনার নিজস্ব গ্রান্ট প্রজেক্ট সেট আপ করবেন এবং পাওয়ার গ্রান্ট অফারগুলির একটি স্লাইস স্বাদ পেয়েছেন।

এই নিবন্ধে, আমরা অসংখ্য গ্রন্ট প্লাগইনগুলি আপনার প্রকৃত প্রকল্প কোডে কী করে তার উপর ফোকাস করব না, তবে গ্রান্ট বিল্ড প্রক্রিয়ার উপর। আমরা আপনাকে ব্যবহারিক ধারনা দেব:

  • কিভাবে আপনার Gruntfile ঝরঝরে এবং পরিপাটি রাখা,
  • কিভাবে নাটকীয়ভাবে আপনার নির্মাণ সময় উন্নত করতে,
  • এবং একটি বিল্ড ঘটলে কিভাবে বিজ্ঞপ্তি দেওয়া হবে.

একটি দ্রুত দাবিত্যাগের জন্য সময়: গ্রান্ট হল অনেকগুলি টুলের মধ্যে একটি যা আপনি কাজটি সম্পন্ন করতে ব্যবহার করতে পারেন। যদি গুলপ আপনার স্টাইল বেশি হয়, তাহলে দারুণ! যদি সেখানে বিকল্পগুলি জরিপ করার পরে, আপনি এখনও আপনার নিজস্ব টুলচেইন তৈরি করতে চান, এটিও ঠিক আছে! শক্তিশালী ইকোসিস্টেম এবং দীর্ঘস্থায়ী ব্যবহারকারী বেসের কারণে আমরা এই নিবন্ধটির জন্য গ্রান্টের উপর ফোকাস করতে বেছে নিয়েছি।

আপনার Gruntfile সংগঠিত

আপনি প্রচুর Grunt প্লাগইন অন্তর্ভুক্ত করুন বা আপনার Gruntfile-এ অনেকগুলি ম্যানুয়াল কাজ লিখুন, এটি দ্রুত খুব অপ্রীতিকর এবং বজায় রাখা কঠিন হয়ে উঠতে পারে। সৌভাগ্যবশত, বেশ কয়েকটি প্লাগইন রয়েছে যা ঠিক সেই সমস্যাটির উপর ফোকাস করে: আপনার Gruntfileটিকে আবার পরিষ্কার এবং পরিপাটি করা।

গ্রান্টফাইল, অপ্টিমাইজেশনের আগে

আমরা এটিতে কোনো অপ্টিমাইজেশন করার আগে আমাদের গ্রন্টফাইলটি দেখতে কেমন তা এখানে রয়েছে:

module.exports = function(grunt) {

  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    concat: {
      dist: {
        src: ['src/js/jquery.js','src/js/intro.js', 'src/js/main.js', 'src/js/outro.js'],
        dest: 'dist/build.js',
      }
    },
    uglify: {
      dist: {
        files: {
          'dist/build.min.js': ['dist/build.js']
        }
      }
    },
    imagemin: {
      options: {
        cache: false
      },

      dist: {
        files: [{
          expand: true,
          cwd: 'src/',
          src: ['**/*.{png,jpg,gif}'],
          dest: 'dist/'
        }]
      }
    }
  });

  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-imagemin');

  grunt.registerTask('default', ['concat', 'uglify', 'imagemin']);

};

এখন আপনি যদি বলছেন "আরে! আমি আরও খারাপ আশা করছিলাম! এটা আসলে রক্ষণাবেক্ষণযোগ্য!", আপনি সম্ভবত সঠিক। সরলতার জন্য, আমরা খুব বেশি কাস্টমাইজেশন ছাড়াই শুধুমাত্র তিনটি প্লাগইন অন্তর্ভুক্ত করেছি। একটি প্রকৃত উৎপাদন Gruntfile ব্যবহার করে একটি মাঝারি আকারের প্রকল্প তৈরি করার জন্য এই নিবন্ধে অসীম স্ক্রোলিং প্রয়োজন হবে। তাহলে দেখা যাক আমরা কি করতে পারি!

আপনার গ্রান্ট প্লাগইনগুলি স্বয়ংক্রিয়ভাবে লোড করুন৷

একটি নতুন গ্রান্ট প্লাগইন যোগ করার সময় যা আপনি আপনার প্রকল্পে ব্যবহার করতে চান, আপনাকে এটি উভয়ই আপনার package.json ফাইলে একটি npm নির্ভরতা হিসাবে যোগ করতে হবে এবং তারপর এটি Gruntfile এর মধ্যে লোড করতে হবে। প্লাগইন " grunt-contrib-concat " এর জন্য, এটি নিম্নলিখিত মত দেখতে পারে:

// tell Grunt to load that plugin
grunt.loadNpmTasks('grunt-contrib-concat');

আপনি যদি এখন npm এর মাধ্যমে প্লাগইনটি আনইনস্টল করেন এবং আপনার package.json আপডেট করেন, কিন্তু আপনার Gruntfile আপডেট করতে ভুলে যান, আপনার বিল্ড ভেঙ্গে যাবে। এখানেই নিফটি প্লাগইন লোড-গ্রান্ট-টাস্ক সাহায্য করতে আসে।

এর আগে, আমাদের গ্রান্ট প্লাগইনগুলি ম্যানুয়ালি লোড করতে হয়েছিল, যেমন:

grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-imagemin');

লোড-গ্রান্ট-টাস্কের সাহায্যে, আপনি এটিকে নিচের ওয়ান-লাইনারে ভেঙে দিতে পারেন:

require('load-grunt-tasks')(grunt);

প্লাগইন প্রয়োজন হওয়ার পরে, এটি আপনার package.json ফাইলটি বিশ্লেষণ করবে, কোনটি নির্ভরতা গ্রান্ট প্লাগইন তা নির্ধারণ করবে এবং সেগুলি স্বয়ংক্রিয়ভাবে লোড করবে।

আপনার গ্রান্ট কনফিগারেশনকে বিভিন্ন ফাইলে বিভক্ত করা

load-grunt-tasks আপনার Gruntfileকে কোড এবং জটিলতায় কিছুটা সঙ্কুচিত করে, কিন্তু আপনি একটি বড় অ্যাপ্লিকেশন কনফিগার করার সাথে সাথে এটি একটি খুব বড় ফাইল হয়ে যাবে। এখানেই লোড-গ্রান্ট-কনফিগেশন কাজ করে। load-grunt-config আপনাকে কাজ অনুসারে আপনার Gruntfile কনফিগারেশন ভাঙতে দেয়। তাছাড়া, এটি লোড-গ্রান্ট-টাস্ক এবং এর কার্যকারিতাকে এনক্যাপসুলেট করে!

গুরুত্বপূর্ণ, তবে: আপনার Gruntfile বিভক্ত করা সবসময় প্রতিটি পরিস্থিতিতে কাজ নাও করতে পারে। আপনার যদি আপনার কাজের মধ্যে অনেকগুলি শেয়ার করা কনফিগারেশন থাকে (যেমন প্রচুর গ্রান্ট টেমপ্লেটিং ব্যবহার করুন), আপনার একটু সতর্ক হওয়া উচিত।

load-grunt-config এর সাথে, আপনার Gruntfile.js দেখতে এইরকম হবে:

module.exports = function(grunt) {
  require('load-grunt-config')(grunt);
};

হ্যাঁ, সত্যিই এটা, পুরো ফাইল! এখন আমাদের টাস্ক কনফিগারেশন কোথায় থাকে?

আপনার Gruntfile এর ডিরেক্টরিতে grunt/ নামে একটি ফোল্ডার তৈরি করুন। ডিফল্টরূপে, প্লাগইনটি সেই ফোল্ডারের মধ্যে ফাইলগুলিকে অন্তর্ভুক্ত করে যা আপনি যে টাস্কটি ব্যবহার করতে চান তার নামের সাথে মেলে। আমাদের ডিরেক্টরি গঠন এই মত হওয়া উচিত:

- myproject/
-- Gruntfile.js
-- grunt/
--- concat.js
--- uglify.js
--- imagemin.js

আসুন এখন আমাদের প্রতিটি কাজের টাস্ক কনফিগারেশন সরাসরি সংশ্লিষ্ট ফাইলগুলিতে রাখি (আপনি দেখতে পাবেন যে এগুলি বেশিরভাগই আসল গ্রন্টফাইল থেকে একটি নতুন কাঠামোতে অনুলিপি করে পেস্ট করে):

grunt/concat.js

module.exports = {
  dist: {
    src: ['src/js/jquery.js', 'src/js/intro.js', 'src/js/main.js', 'src/js/outro.js'],
    dest: 'dist/build.js',
  }
};

grunt/uglify.js

module.exports = {
  dist: {
    files: {
      'dist/build.min.js': ['dist/build.js']
    }
  }
};

grunt/imagemin.js

module.exports = {
  options: {
    cache: false
  },

  dist: {
    files: [{
      expand: true,
      cwd: 'src/',
      src: ['**/*.{png,jpg,gif}'],
      dest: 'dist/'
    }]
  }
};

যদি জাভাস্ক্রিপ্ট কনফিগারেশন ব্লকগুলি সত্যিই আপনার জিনিস না হয়, তাহলে লোড-গ্রান্ট-টাস্কগুলি আপনাকে এর পরিবর্তে YAML বা CoffeeScript সিনট্যাক্স ব্যবহার করার অনুমতি দেয়। চলুন আমাদের চূড়ান্ত প্রয়োজনীয় ফাইলটি YAML-এ লিখি - " aliases " ফাইল। এটি একটি বিশেষ ফাইল যা টাস্ক উপনাম নিবন্ধন করে, যা registerTask ফাংশনের মাধ্যমে আগে গ্রন্টফাইলের অংশ হিসাবে আমাদের করতে হয়েছিল। এখানে আমাদের:

grunt/aliases.yaml

default:
  - 'concat'
  - 'uglify'
  - 'imagemin'

এবং এটাই! আপনার টার্মিনালে নিম্নলিখিত কমান্ডটি চালান:

$ grunt

যদি সবকিছু কাজ করে, তাহলে এটি এখন "ডিফল্ট" টাস্ক দেখবে এবং সবকিছু ক্রমানুসারে চালাবে। এখন যেহেতু আমরা আমাদের মূল গ্রন্টফাইলটি কোডের তিনটি লাইনে নামিয়ে দিয়েছি আমাদের কখনই প্রতিটি টাস্ক কনফিগারেশনকে স্পর্শ করার এবং বাহ্যিক করার দরকার নেই, আমরা এখানে সম্পন্ন করেছি। কিন্তু মানুষ, সবকিছু তৈরি করা এখনও বেশ ধীর। এর উন্নতি করতে আমরা কী করতে পারি তা দেখা যাক।

আপনার বিল্ড সময় মিনিমাইজিং

যদিও আপনার ওয়েব অ্যাপের রানটাইম এবং লোড টাইম পারফরম্যান্স একটি বিল্ড চালানোর জন্য প্রয়োজনীয় সময়ের চেয়ে অনেক বেশি ব্যবসায়িক গুরুত্বপূর্ণ, একটি ধীর বিল্ড এখনও সমস্যাযুক্ত। এটি গ্রান্ট-কন্ট্রিব-ওয়াচের মতো প্লাগইনগুলির সাথে স্বয়ংক্রিয় বিল্ডগুলি সম্পাদন করা কঠিন করে তুলবে বা গিট যথেষ্ট দ্রুত কমিট করার পরে এবং বিল্ডটি চালানোর জন্য একটি "জরিমানা" প্রবর্তন করে – যত দ্রুত বিল্ড সময় হবে, আপনার কর্মপ্রবাহ তত বেশি চটপটে হবে। যদি আপনার প্রোডাকশন বিল্ডটি চালানোর জন্য 10 মিনিটের বেশি সময় নেয়, তাহলে আপনি বিল্ডটি তখনই চালাবেন যখন আপনাকে একেবারেই করতে হবে এবং এটি চলার সময় আপনি কফি পেতে ঘুরে বেড়াবেন। যে একটি উত্পাদনশীলতা হত্যাকারী. আমরা গতি বাড়াতে জিনিস আছে.

শুধুমাত্র এমন ফাইল তৈরি করুন যা আসলে পরিবর্তিত হয়েছে: grunt-newer

আপনার সাইটের একটি প্রাথমিক বিল্ড করার পরে, আপনি যখন আবার বিল্ডিং করতে যাবেন তখন সম্ভবত আপনি প্রজেক্টের কয়েকটি ফাইল স্পর্শ করবেন। ধরা যাক যে আমাদের উদাহরণে, আপনি src/img/ ডিরেক্টরিতে একটি চিত্র পরিবর্তন করেছেন – চিত্রগুলিকে পুনরায় অপ্টিমাইজ করার জন্য ইমেজমিন চালানো অর্থপূর্ণ হবে, তবে শুধুমাত্র সেই একক চিত্রের জন্য – এবং অবশ্যই, কনক্যাট এবং অগ্লিফাই পুনরায় চালু করা কেবল নষ্ট হচ্ছে মূল্যবান CPU চক্র।

অবশ্যই, আপনি সর্বদা আপনার টার্মিনাল থেকে $ $ grunt এর পরিবর্তে $ grunt imagemin চালাতে পারেন শুধুমাত্র বেছে বেছে হাতে একটি কাজ সম্পাদন করতে, কিন্তু একটি বুদ্ধিমান উপায় আছে। এটাকে বলা হয় গ্রান্ট-নতুন

Grunt-newer-এর একটি স্থানীয় ক্যাশে রয়েছে যেখানে এটি আসলে কী ফাইলগুলি পরিবর্তিত হয়েছে সে সম্পর্কে তথ্য সঞ্চয় করে এবং শুধুমাত্র সেই ফাইলগুলির জন্য আপনার কার্য সম্পাদন করে যা প্রকৃতপক্ষে পরিবর্তন করেছে৷ চলুন দেখে নেই কিভাবে এটি সক্রিয় করবেন।

আমাদের aliases.yaml ফাইল মনে আছে? এটি থেকে এটি পরিবর্তন করুন:

default:
  - 'concat'
  - 'uglify'
  - 'imagemin'

এর প্রতি:

default:
  - 'newer:concat'
  - 'newer:uglify'
  - 'newer:imagemin'

আপনার যেকোন টাস্কের জন্য শুধু "নতুন:" আগে থেকে শুরু করে প্রথমে গ্রান্ট-নতুন প্লাগইনের মাধ্যমে আপনার সোর্স এবং গন্তব্য ফাইলগুলিকে পাইপ করে, যা তারপরে নির্ধারণ করে কোন ফাইলের জন্য, যদি থাকে, টাস্কটি চালানো উচিত

সমান্তরালে একাধিক কাজ চালান: grunt-concurrent

grunt-concurrent হল একটি প্লাগইন যা সত্যিই উপযোগী হয়ে ওঠে যখন আপনার প্রচুর কাজ থাকে যা একে অপরের থেকে স্বাধীন এবং অনেক সময় ব্যয় করে। এটি আপনার ডিভাইসে CPU-এর সংখ্যা ব্যবহার করে এবং সমান্তরালভাবে একাধিক কাজ সম্পাদন করে।

সর্বোপরি, এর কনফিগারেশনটি অত্যন্ত সহজ। ধরে নিচ্ছি আপনি load-grunt-config ব্যবহার করছেন, নিম্নলিখিত নতুন ফাইল তৈরি করুন:

grunt/concurrent.js

module.exports = {
  first: ['concat'],
  second: ['uglify', 'imagemin']
};

আমরা শুধু “ প্রথম ” এবং “ দ্বিতীয় ” নামের সমান্তরাল এক্সিকিউশন ট্র্যাক সেটআপ করি। কনক্যাট টাস্কটি প্রথমে চালানো দরকার এবং আমাদের উদাহরণে এর মধ্যে চালানোর জন্য আর কিছুই নেই। আমাদের দ্বিতীয় ট্র্যাকে, আমরা uglify এবং imagemin উভয়ই রাখি, যেহেতু এই দুটি একে অপরের থেকে স্বাধীন, এবং উভয়ই যথেষ্ট সময় নেয়।

এটি নিজে থেকে এখনও কিছু করে না। আমাদের ডিফল্ট টাস্কের উপনাম পরিবর্তন করতে হবে সরাসরি কাজের পরিবর্তে সমসাময়িক কাজের দিকে নির্দেশ করতে। এখানে grunt/aliases.yaml এর নতুন বিষয়বস্তু রয়েছে:

default:
  - 'concurrent:first'
  - 'concurrent:second'

আপনি যদি এখন আপনার গ্রান্ট বিল্ড পুনরায় চালু করেন, তাহলে সমবর্তী প্লাগইনটি প্রথমে কনক্যাট টাস্কটি চালাবে এবং তারপরে দুটি ভিন্ন CPU কোরে দুটি থ্রেড তৈরি করবে যাতে ইমেজমিন এবং অগ্লিফাই উভয়ই সমান্তরালে চালানো যায়। হ্যাঁ!

যদিও উপদেশের একটি শব্দ: সম্ভাবনা হল আমাদের মৌলিক উদাহরণে, গ্রান্ট-কনকারেন্ট আপনার বিল্ডকে উল্লেখযোগ্যভাবে দ্রুততর করবে না। এর কারণ হল ওভারহেড বিভিন্ন থ্রেডে গ্রান্টের বিভিন্ন উদাহরণ তৈরি করে তৈরি করা হয়েছে: আমার ক্ষেত্রে, কমপক্ষে +300ms প্রো স্পন।

কত সময় লেগেছে? সময়

এখন যেহেতু আমরা আমাদের প্রতিটি কাজকে অপ্টিমাইজ করছি, প্রতিটি কাজ সম্পাদন করতে কত সময় লাগবে তা বোঝা সত্যিই সহায়ক হবে। সৌভাগ্যবশত, এর জন্য একটি প্লাগইনও রয়েছে: time-grunt

time-grunt একটি ধ্রুপদী গ্রান্ট প্লাগইন নয় যা আপনি npm টাস্ক হিসাবে লোড করেন, বরং একটি প্লাগইন যা আপনি সরাসরি অন্তর্ভুক্ত করেন, load-grunt-config এর মতো। আমরা আমাদের Gruntfile-এ টাইম-গ্রান্টের জন্য একটি প্রয়োজন যোগ করব, ঠিক যেমন আমরা load-grunt-config দিয়ে করেছি। আমাদের Gruntfile এখন এই মত হওয়া উচিত:

module.exports = function(grunt) {

  // measures the time each task takes
  require('time-grunt')(grunt);

  // load grunt config
  require('load-grunt-config')(grunt);

};

এবং আমি হতাশ হওয়ার জন্য দুঃখিত, কিন্তু এটাই হল - আপনার টার্মিনাল থেকে Grunt পুনরায় চালু করার চেষ্টা করুন এবং প্রতিটি কাজের জন্য (এবং অতিরিক্ত মোট বিল্ড), আপনি সম্পাদনের সময় একটি সুন্দর ফর্ম্যাট করা তথ্য প্যানেল দেখতে পাবেন:

গর্জন সময়

স্বয়ংক্রিয় সিস্টেম বিজ্ঞপ্তি

এখন আপনার কাছে একটি ভারী অপ্টিমাইজ করা গ্রান্ট বিল্ড রয়েছে যা দ্রুত কার্যকর হয় এবং আপনাকে এটিকে কোনোভাবে স্বয়ংক্রিয়ভাবে তৈরি করে দেয় (অর্থাৎ গ্রান্ট-কন্ট্রিবি-ওয়াচ সহ ফাইলগুলি দেখে, বা কমিট করার পরে), এটি কি দুর্দান্ত হবে না যদি আপনার সিস্টেমটি করতে পারে? আপনার নতুন বিল্ড কখন ব্যবহার করার জন্য প্রস্তুত, বা যখন খারাপ কিছু ঘটেছিল তখন আপনাকে অবহিত করবেন? গ্রান্ট-বিজ্ঞপ্তির সাথে দেখা করুন।

ডিফল্টরূপে, গ্রান্ট-নোটিফাই আপনার OS-এ উপলব্ধ যে কোনও নোটিফিকেশন সিস্টেম ব্যবহার করে সমস্ত গ্রান্ট ত্রুটি এবং সতর্কতার জন্য স্বয়ংক্রিয় বিজ্ঞপ্তি সরবরাহ করে: OS X বা Windows, Mountain Lion's and Mavericks' Notification Center, এবং Notify-send. আশ্চর্যজনকভাবে, এই কার্যকারিতা পাওয়ার জন্য আপনার যা দরকার তা হল npm থেকে প্লাগইনটি ইনস্টল করা এবং এটিকে আপনার Gruntfile এ লোড করা (মনে রাখবেন, আপনি যদি উপরে grunt-load-config ব্যবহার করছেন, এই ধাপটি স্বয়ংক্রিয়!)

আপনার অপারেটিং সিস্টেমের উপর নির্ভর করে এটি দেখতে কেমন হবে তা এখানে:

অবহিত

ত্রুটি এবং সতর্কতা ছাড়াও, আসুন এটিকে কনফিগার করি যাতে এটি আমাদের শেষ কাজটি কার্যকর করার পরে চলে। ধরে নিচ্ছি যে আপনি ফাইল জুড়ে কাজগুলিকে বিভক্ত করতে grunt-load-config ব্যবহার করছেন, এই ফাইলটি আমাদের প্রয়োজন হবে:

grunt/notify.js

module.exports = {
  imagemin: {
    options: {
      title: 'Build complete',  // optional
        message: '<%= pkg.name %> build finished successfully.' //required
      }
    }
  }
}

আমাদের কনফিগার অবজেক্টের প্রথম স্তরে, কীটিকে আমরা যে টাস্কের সাথে সংযোগ করতে চাই তার নামের সাথে মিলতে হবে। এই উদাহরণটি ইমেজমিন টাস্কটি কার্যকর করার পরেই বার্তাটি প্রদর্শিত হবে, যা আমাদের বিল্ড চেইনের শেষটি।

সব গুটিয়ে নিচ্ছে

আপনি যদি উপরে থেকে অনুসরণ করে থাকেন, তাহলে আপনি এখন এমন একটি বিল্ড প্রক্রিয়ার গর্বিত মালিক যা অত্যন্ত পরিপাটি এবং সংগঠিত, সমান্তরালকরণ এবং নির্বাচনী প্রক্রিয়াকরণের কারণে উজ্জ্বলভাবে দ্রুত এবং কিছু ভুল হলে আপনাকে অবহিত করে।

আপনি যদি অন্য একটি রত্ন আবিষ্কার করেন যা গ্রান্ট এবং এর প্লাগইনগুলিকে আরও উন্নত করে, দয়া করে আমাদের জানান! ততক্ষণ পর্যন্ত, খুশির গর্জন!

আপডেট (2/14/2014): সম্পূর্ণ, কাজের উদাহরণ গ্রান্ট প্রকল্পের একটি অনুলিপি পেতে, এখানে ক্লিক করুন