menu

ابزار های توسعه دهنده ی مدرن وب

Yeoman

شنبه 20 شهریور 1395

تا به اینجای کار، در فصل های قبلی، ما با یه سری از Front-end framework ها آشنا شدیم

در طراحی یه وب سایت خوب، مطمئنا این ابزارها خیلی به کار میاد. اما فک کنید که هر دفعه بخواهید این پروسه ی تکراری و خسته کننده را انجام بدید. برید به سایت های فریم ورک ها، دنبال آخرین نسخه بگردید، دانلود کنید، و بشینید یه سری چیزهای تکراری مثل Title و ایناش را تنظیم کنید. کار خیلی ساده، ولی در عین حال تکراری و طاقت فرسایی هست و همینطور وقت زیادی را از ما میگیره.

اینجاس که فصل بعدی ما شروع میشه و YeoMan به سراغ ما میاد!

به قول گوگل Say Yo to Yeoman !

همونطور که اینجا توضیح داده، Yeoman به طور خلاصه یه ابزاری هست که به ما این اجازه را میده که خیلی سریع، چهارچوب ها و ساختار سایت خودمون را بسازیم و تنظیمش کنیم

قبل از شروع کار با Yeoman، این نکته را هم اضافه کنم که خود سیستم Yeoman، برای انجام کارهاش از دوتا فریم ورک دیگه استفاده میکنه

اولین اون ها یه سیستم build tools هست. این سیستم، کارهای متنوعی را برای ما انجام میده، مثلا تصاویر ما را پردازش میکنه یا فایل های SASS را پردازش میکنه یا ... Yeoman برای این کار از دوتا سیستم Gulp و Grunt استفاده میکنه که شما بسته به دلخواهتون، میتونید تنظیم کنید و انتخاب کنید که از کدوماش استفاده کنه. در فصل های آینده در رابطه با این دو فریم ورک توضیح میدم

سیستم دوم هم Package Manager اون هست. برای سیستم مدیریت بسته هاش هم Yeoman از NPM و Bower استفاده میکنه.

شاید بگید که سیستم های مدیریت بسته به چه دردی میخوره؟

قبل از اون بزارید ساختار اصلی Yeoman را توضیح بدم. Yeoman بر اساس ساختاری که خودش اسمش را Generators گذاشته کار میکنه. هر Generator در واقع یه ساختار و چهار چوب هست. مثلا فرض کنید که ما میخواهید یه وب سایت بر اساس Angular راه اندازی کنیم، و نمیخواهیم که بریم فایل های مورد نیاز را دانلود و کانفیگ کنیم و ... در واقع میخواهیم کارهای اولیه و ضروری و وقت گیر را Yeoman انجام بده. برای این کار فقط کافیه که Generator مربوط به Angular را اجرا کنیم. و البته Yeoman دارای Generator های خیلی زیادی هست. 

از Bootstrap و Foundation بگیر تا HTML5 Boilerplate و wordpress حتی و Backbones و خیلی چیزای دیگه!

و البته خیلی از این Generator ها ممکنه خودشون یه سری Dependencies و اینا داشته باشن که کلا مدیریت اینکه هر generator چه فایل هایی را داره و چی را نصب کنه و چی را نصب نکنه به عهده ی Bower هست

برای شروع کار، اول از هر چیز Yeoman را نصب میکنیم. خود Yeoman را باید از طریق NPM نصب کرد که نصب و راه اندازی NPM را در mini chapter قبل توضیح دادم

برای نصب، کافیه فقط کد زیر را بزنید

npm install -g yo

و با زدن این کد، یه خروجی شبیه به این بهتون میده

بعد از این هم میتونید با زدن دستور زیر، ورژن Yeoman خودتون را چک کنید

yo --version

ما الان Yeoman را نصب کردیم، اما همونطور که گفتیم، Yeoman برای کار کردن نیاز به Bower داره. پس bower را هم نصب میکنیم

npm install -g bower

ولی باز هم یه dependency دیگه هست! bower هم برای کار کردن نیاز به git داره! پس git را هم نصب میکنیم

اگه توی ویندوز هستید، میتونید از اینجا دانلود و نصب کنید

بعد از این کار، اولین دستوری که میخواهیم بزنیم اینه

npm search yeoman-generator

پردازش این کد، ممکنه که کمی طول بکشه

اما با زدن این کد، یه لیست خیلی خیلی طولانی از صدها generator که yeoman داره را در اختیار ما میزاره

همینطور میتونید توی این صفحه هم یه لیست از Generator ها را ببینید

قبلا در رابطه با این که این generator ها توضیح دادم. این که چی هستن و چیکار میکنن. همونطور که توی لیست میبینید، generator های زیادی مثل وجود دارند

یکی از generator هایی که پیش فرض خود Yeoman هست، اسمش Webapp هست. بزارید برای تست، این Generator را نصب کنیم

برای نصب این generator، کافیه کد زیر را بزنید

npm install -g generator-webapp

با زدن این کد، NPM میاد و Generator مربوطه را نصب میکنه. حالا تنها کاری که باید بکنیم اینه که یه پوشه انتخاب کنیم(ایجاد کنیم) و بگیم که فایل های مورد نظر این Generator را توی اون پوشه درست کنه (در واقع با زدن npm، ما generator مورد نظر را دانلود کردیم و با زدن کد زیر، یه new project توی current directory میسازیم)

من ابتدا توی دسکتاپ خودم یه پوشه میسازم به اسم yo و توی اون یه پوشه به اسم webapp و با کد زیر میرم توی اون پوشه

md yo
cd yo
md webapp
cd webapp

حالا کافیه که فقط بگیم توی این پوشه ی فعلی، یه new project بر اساس webapp که قبلا generator اون را نصب کرده ایم بسازه

برای این کار هم کد زیر را میزنم

yo webapp

با زدن این کد، Yeoman از شما میپرسه که برای این پروژه تون چه چیزهایی را نیاز دارید؟

من Bootstrap و Modernizer را انتخاب کردم

بزارید یه نگاهی به فایل های این پروژه ای که generate کردیم بندازیم

البته اگه مشکلی در این پروسه پیدا کردید، دستور های npm را با sudo انجام بدید یا Node Command Prompt را Run as Adminstrator کنید

من پوشه ی webapp را توی Sublime باز میکنم

همونطور که میبینید، یه دستور خیلی ساده، چقدر فایل های زیادی را توی زمان کمی برای ما ایجاد کرد (البته اگه اینترنت شما هم مثل من داغون باشه ممکنه کمی زمانش طولانی بشه!)

بزارید ببینیم چی داریم اینجا

اولین چیزی که توجه منو جلب میکنه، پوشه ی app هست. این پوشه ی اصلی پروژه ی ما هست و تمام فایل های ما توی این پوشه ذخیره میشه. توی این پوشه، ما پوشه های fonts و images را داریم که خالی هستند. همینطور هم فایل main.js را توی scripts داریم که فقط یه کد console توش هست و محل مناسبی برای زدن کدهامونه و البته فایل main.css توی پوشه ی styles. فایل های index و robots هم آماده است.

پوشه ی بعدی هم bower_components هست که توش کتابخونه هایی مثل bootstrap و jquery و modernizr که انتخاب کرده بودیم توش هست

پوشه ی بعدی node_modules هست که توش یه سری از module های node هست و البته این که از کدوم یک از این ماژول ها توی پروژه ی ما استفاده بشه، توی فایل package.json هست که تعیین میشه.

بریم یه سری به فایل بعدی، یعنی فایل .bowerrc بزنیم. این فایل هم تعیین میکنه که دایرکتوری bower_component (دقیق ترش کتابخونه هایی که توی این پروژه استفاده شده اند) در کجا ذخیره بشند. شما میتونید این آدرس را تغییر بدید و فایل های bower_component را به پوشه ی دیگه ای ببرید و با پاک کردن cache های bower و re build کردن پروژه، اون را تغییر بدید

فایل های بعدی هم به ترتیب .editorconfig و .gitignore و .gitattributes هستند که قبلا توضیح داده ام که چی هستند

همونطور که میبینید، یکی دیگه از فایل های ما gulpfile.js هست. یعنی که برای پردازش، از موتور gulp استفاده میکنه (نه grunt)

پس اول میریم سراغ نصب gulp

npm install -g gulp

حالا توی ویرایشگر، فایل gulpfile.js را باز میکنیم

شاید در اول کار به نظرتون خیلی درهم برهم بیاد، ولی نگران نباشید. در فصل های آتی وقتی به grunt و gulp رسیدیم، اینا را هم توضیح میدیم

ولی توجه شما را به یه قسمتش جلب میکنم

این قسمت، میاد و واسه ی ما روی پورت 9000، یه local server machine میسازه. و برای اجرای این local server، کافیه فقط توی دایرکتوری مورد نظر(جایی که gulpfile.js وجود داره) دستور زیر را بزنید

gulp serve

و البته اگه توی ویندوز هستید، به فایل nodejs دسترسی داده و اگه توی لینوکس هستید با sudo بزنید بهتره

و میبینید که خیلی راحت، توی مرورگر، توی localhost، پروژه ی ما Run شد!

خیلی راحت و آسوده خاطر، Yeoman حتی یه Localhost هم در اختیار ما قرار میده (پ.ن: اگه پورت 9000 خودتون اشغال هست، فقط توی فایل gulpfile.js عدد port را عوض کنید)

خیلی ساده، و خیلی راحت یه پروژه ی bootstrap و modernizr و البته بر اساس HTML5 Boilerplate را راه اندازی کردیم، که اگه میخواستیم بریم از توی سایت های اصلیشون فایل ها را دانلود کنیم و...، مطمئنا خیلی وقت گیر تر بود (البته بدی نیس یه سری هم به localhost:3001 بزنید، ولی کار باهاش به عهده ی خودتون!)

و در نهایت، کافیه که برای پروژه ی خودتون، هر تغییری را که میخواهید توی فایل های پوشه ی app بدهید

بهتره از این حالت localhost با زدن ctrl + C خارج بشیم. نکته ی بعدی که میخواستم در رابطه با gulp اضافه کنم، موقعی هست که ما پروژه امون پایان یافته و میخواهیم که این پروژه را online کنیم

برای این کار، کافیه که فقط دستور زیر را بزنیم

gulp

در این حالت، gulp میاد تمام فایل ها را build میکنه، css ها را minify میکنه، فایل ها را gzip میکنه، cache ها را clean میکنه و پروژه ی ما را واسه آنلاین شدن محیا میکنه

و در نهایت، یه پوشه ی dist در اختیار ما میزاره که این پوشه را میتونیم به سرورمون انتقال بدیم

همونطور که میبینید فایل های این پوشه minify شده و gzip شده هستند.

خب تا اینجا کار با generator-webapp ما تموم شد.

اما یه سوال پیش میاد، این generator-webapp تنها به ما bootstrap و modernizr و html5 boilerplate میده. بقیه ی generator ها هم چهار چوب خاص خودشون را دارن. چی میشه اگه بخواهیم که یه generator خاص داشته باشیم؟ یه generator اختصاصی؟

خوشبختانه Yeoman این قابلیت را نیز داره. شخصی سازی و ایجاد یه generator خاص

برای این کار، باید با استفاده از npm اول generator-generator را نصب کرد! یعنی یه generator که خودش یه generator میسازه!

npm install -g generator-generator

توی generator قبلی، ما از یه generator به اسم webapp استفاده کردیم. حالا میخواهیم خودمون یه generator بسازیم. من که دوست دارم اسمش را بزارم noisy

پس اول از همه، یه folder به اسم generator-noisy میسازم

mkdir generator-noisy
cd generator noisy

حالا تنها کافیست که بگیم میخواهیم این folder را به یه generator تبدیل کنیم

با دستور زیر

yo generator

با زدن دستور زیر، ابتدا از ما نام generator را میپرسه که میتونیم همین نام فعلی را براش انتخاب کنیم یا اسم اون را عوض کنیم؛ و بعد از اون از ما توضیحات، صفحه ی خانه ی مربوط به پروژه، اسم نویسنده، ایمیل نویسنده، صفحه ی خانه ی نویسنده، کلمات کلیدی، یوزرنیم گیت هاب و یه سری سوال دیگه را میپرسه

بعد از تموم شدن این پروسه، بزارید پوشه ی generator-noisy را توی sublime باز کنم

اول از همه، یه پوشه ی hidden به اسم .git وجود داره git repository خالی هست، که از اونجایی که قرار نیست ما زیاد وارد بحث git بشیم، کاری به این پوشه نداریم

قبل از اینکه به بررسی بقیه ی فایل های generator-noisy برسیم، بهتره که یه باز ازش استفاده کنیم و یه new project باهاش بسازیم

پس ابتدا، برای اینکه بتونیم از این generator توی جاهای دیگه ی سیستممون استفاده کنیم، اون را link میکنیم. یعنی داخل پوشه ی generator-noisy کد زیر را میزنیم

npm link

بعد توی دایرکتوری yo یه پوشه ی خالی میسازیم

mkdir noisy
cd noisy

و یه new project توی اون میسازیم

yo noisy

حالا اگه به پوشه ی noisy برید میبینید تقریبا هیچ چی توش نیس!

البته تقریبا!

الان موقع اونه که ما generator خودمون را کانفیگ کنیم. مثلا پیام خوش آمد گویی اون را که نوشته "Welcome to the groovy generator-noisy generator!" را عوض کنیم یا به جای Whould You like to enable this option  از یه سوال پر معناتر و واقعی تر استفاده کنیم

برای این کار برمیگردیم به generator-noisy

اول از همه بد نیس یه نگاهی به فایل README بندازیم. میبینیم که توی اونجا، همون اطلاعاتی که وارد کردیم اعم از نویسنده، لایسنس و صفحه ی خانه ی ما درج شده

یه سری هم به package.json میزنیم

توی این فایل، مشخصات Generator ما موجوده. از موتور پردازشش گرفته (gulp) تا اطلاعات نویسنده و dependencies و ...

فایل بعدی هم LICENSE هست که از اونجایی که من Apache  را انتخاب کرده بودم، برای من یه نسخه از لایسنس Apache را آورده

فایل بعدی، یکی از مهم ترین فایل هاست. gulpfile.js که قبلا توضیح دادم چی هست.

از اینها بگذریم، بریم سراغ فایل هایی که برای ما، ساختار generator را میسازند. به generators/app میریم و فایل index.js را باز میکنیم

لطفا گیج نشوید! این ها تنها کدهایی ساده بر اساس JS هستند که با مراجعه به Document های Yeoman میتونید متوجه بشید چی هستند، ولی این فایل، به طور کلی ساختار generator مارا مشخص میکنه. مثلا قسمت

this.log(yosay(
	'Welcome to the groovy ' + chalk.red('generator-noisy') + ' generator!'
));

پیام خوش آمد گویی مارا تعیین میکنه. بیاین کمی تغییرش بدیم

this.log(yosay(
	'Welcome to the ' + chalk.red('noisy') + ' generator!'
));

یا مثلا کد

var prompts = [{
	type: 'confirm',
    name: 'someAnswer',
    message: 'Would you like to enable this option?',
    default: true
}];

از ما یه سوال میپرسه. بیاید یکم شخصی سازیش کنیم. مثلا ازش بپرسیم که میخواد فایل موسیقی داشته باشه یا نه

var prompts = [{
	type: 'confirm',
    name: 'music',
    message: 'Would you like to include some music?',
    default: true
}];

و میتونیم یه شرط بزاریم که یه فایل برامون کپی کنه

قسمت بعدی هم برامون یه فایل کپی میکنه

writing: function () {
    this.fs.copy(
        this.templatePath('dummyfile.txt'),
        this.destinationPath('dummyfile.txt')
    );
}

که شما میتونید این فایل را تغییر بدید. مثلا من فایل توی پوشه ی templates را rename میکنم به index.html و یکم هم محتوا توش میزارم

writing: function () {
    this.fs.copy(
        this.templatePath('index.html'),
        this.destinationPath('index.html')
    );
}

یا مثلا توی همون تابع، با زدن دستور

this.mkdir('app')

میتونم کاری کنم که موقع ساختن new project، یه پوشه ی app هم ساخته بشه

یا خیلی کارهای دیگه

اگه یادتون باشه، چند خط بالاتر، ما یه سوال پرسیدیم که آیا میخواد موسیقی هم داشته باشه؟

توی همین تابع مربوط به writing، میتونیم شرط بزاریم و بگیم که اگه جواب کاربر مثبت بود، یه فایل موسیقی هم براش بسازه!

کدی که ما زدیم این بود

var prompts = [{
    type: 'confirm',
    name: 'music',
    message: 'Would you like to include some music?',
    default: true
}];

دقت کنید که مقدار name برابر music هست.

حالا کافیه قسمت writing را به شکل زیر تغییر بدیم

writing: function () {
    this.mkdir('app');
    if(this.props.music){
        this.copy('../music.txt', 'app/music.txt');
    }
    this.fs.copy(
        this.templatePath('dummyfile.txt'),
        this.destinationPath('dummyfile.txt')
    );
},

و البته یه فایل music.txt هم میسازیم توی قسمت generator-noisy/generators/app

حالا وقتی به پوشه noisy بریم و دستور yo noisy را بزنیم داریم

و به همین ترتیب میتونیم generator خودمون را با پرسیدن سوالات مختلف و شخصی سازی های خیلی زیاد، تبدیل به یه generator خیلی مفید بکنیم (البته الان در رابطه با هرچی که فکرش را بکنید، توی yeoman وجود داره و لازم به ساختن یه generator جدید به نظرم نیست)

میریم سراغ پویایی بیشتر!

شما توی generator های خودتون، میتونید از آرگومان ها هم استفاده کنید!

یعنی چی؟

یعنی شما مثلا به جای زدن 

yo noisy

هنگام ساختن یه پروژه ی جدید میتونید بزنید

yo noisy "My new Website"

و در این حالت، مقداری که بعد از noisy وارد کردیم، به عنوان یه متغیر و یه آرگومان در نظر گرفته میشه و میتونیم توی generator خودمون ازش استفاده کنیم. مثلا میتونیم کاری کنیم که کاربر همون موقع با زدن yo، بتونه اسم وب سایتش را هم به عنوان یه آرگومان وارد کنه، و این اسم به عنوان Title اعمال بشه!

چقد cool !

مثلا شما برای استفاده از آرگومان ها باید این کار را بکنید

اول فایل های مورد نظر را generator خودمون وارد میکنیم

var _ = require('lodash');

بعد یه تابع constructor مینویسیم که بگیم کاربر حتما یه آرگومان وارد کنه

constructor: function () {
	yeoman.Base.apply(this, arguments);

    // This makes `appname` a required argument.
    this.argument('username', { type: String, required: true });
    // And you can then access it later on this way; e.g. CamelCased
    this.username = _.camelCase(this.username);
},

و در نهایت، از این متغیر توی پیام خوش آمدید استفاده میکنم

this.log(yosay(
	'Welcome ' + this.username + ' to the ' + chalk.red('noisy') + ' generator!'
));

یعنی در نهایت کدهای من این شکلیه

'use strict';
var yeoman = require('yeoman-generator');
var chalk = require('chalk');
var yosay = require('yosay');
var _ = require('lodash');

module.exports = yeoman.Base.extend({
  constructor: function () {
    yeoman.Base.apply(this, arguments);

    // This makes `appname` a required argument.
    this.argument('username', { type: String, required: true });
    // And you can then access it later on this way; e.g. CamelCased
    this.username = _.camelCase(this.username);
  },
  prompting: function () {
    // Have Yeoman greet the user.
    this.log(yosay(
      'Welcome ' + this.username + ' to the ' + chalk.red('noisy') + ' generator!'
    ));

    var prompts = [{
      type: 'confirm',
      name: 'music',
      message: 'Would you like to include some music?',
      default: true
    }];
    return this.prompt(prompts).then(function (props) {
      // To access props later use this.props.someAnswer;
      this.props = props;
    }.bind(this));
  },

  writing: function () {
    this.mkdir('app');
    if(this.props.music){
      this.copy('../music.txt', 'app/music.txt');
    }
    this.fs.copy(
      this.templatePath('dummyfile.txt'),
      this.destinationPath('dummyfile.txt')
    );
  },

  install: function () {
    this.installDependencies();
  }
});

و نتیجه اش این میشه

و شما برای پویا کردن هر چه بیشتر generator خودتون میتونید از آرگومان ها، متغیرها، prompt ها و خیلی چیزای دیگه استفاده کنید

البته من قرار نیست به طور کامل درباره ی ساختن یه generator صحبت کنم، و فقط قرار بود کار با Yeoman را نشون بدم و Yeoman را معرفی کنم. پس اگه میخواهید واقعا یه generator بسازید به اینجا مراجعه کنید