معرفی فریمورک Express (آموزش نصب فریمورک Express)

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

چند سال پیش من مانند دیگران، بیشتر و بیشتر در مورد Node.js شنیدم. بیش از یک دهه بود که در حال ساختن برنامه‌های سمت سرور در ColdFusion بودم ولی مثل همیشه کنجکاو بودم که ببینم بقیه پلتفرم‌ها چگونه کار می‌کنند. من از جاوااسکریپت سمت کلاینت لذت می‌بردم و استفاده از اون در سمت سرور به نظر جالب می اومد. (گرچه لزوماً چیز جدیدی نبود. به اندازه کافی سن دارم که به یاد بیارم زمانی که Netscape در دهه‌ی 90 SSJS رو منتشر کرد.) تعدادی آموزش خواندم، در چند تا جلسه شرکت کردم ولی تحت تاثیر قرار نگرفتم.

هربار که درباره Node مطالعه می کردم به داستانی مشابه ختم میشد: ساختن یک وب سرور. صادقانه بگم که اصلاً هیجان انگیز نبود. حتی زمانی که من اولین برنامه‌ی تحت وبم را با CGI پرل ساختم اصلاً نگرانی دربارش نداشتم. می توانستم پتانسیل یک ارائه دهنده API کوچک و سبک را در آن ببینم ولی باید به وسیله آن یک سایت ساده ایجاد کنم؟ نه به هیچ وچه!

اما روزی  خوش شانس بودم. تصمیم گرفتم که در یک ارائه Node بیشتر بنشینم (درحقیقت به این دلیل بیشتر ماندم که می دانستم ارائه کننده خوب می باشد) در حین ارائه‌، سخنگو Express را شرح داد. فکری به سرم زد. این فریمورکی بود که من منتظرش بودم! به صورت تئوری شما هنوز وبسرور خودتان را می سازید ولی درگیر شدن با این بخش از برنامه به حداقل می رسد و به جای آن، شما بر روی ساخت منطق سایت و محتوای آن تمرکز می کنید. در این مقاله به شما نحوه نصب Express و طریقه ساخت یک نرم افزار تحت وب با استفاده از این فریمورک را نشان خواهم داد.

به احتمال زیاد شما پیش از این، یک توسعه دهنده Node باشید. در صورتی که تازه کار هستید شاید مانند من از قدرت npm در بهت و حیرت باشید. همانطور که گفتم بیشتر از عمرم را با ColdFusion کار کرده ام. در این پلتفرم یک اکوسیستم غنی، از پروژه های اپن سورس وجود دارد. ولی نصب و یافتن آن ها یک کار دستی می باشد. در ابتدا که از npm استفاده می کردم در ترس و بیم بودم. صادقانه من الان به سختی می تونم تصور کنم که از پلتفرمی استفاده کنم که ابزاری مانند npm را نداشته باشد. بیاید کارمان را با فایل package.json شروع کنیم جایی که وابستگی های Express را اضافه خواهیم کرد.

{
  "name": "demo1",
    "description": "First Express app",
    "version": "0.0.1",
    "dependencies": {
        "express": "3.x"
    }
}

بار دیگر می گویم که این کار باید برای توسعه دهندگان Node کاری استاندارد باشد. به کامند لاین بروید و کد زیر را اجرا نمایید:

npm install

این کد، Express را به همراه متعلقاتش نصب می کند.

در مقابل شما می توانید Express را به عنوان یک ابزار خط فرمان نصب کنید تا بتوانید به سرعت ساختار اصلی برنامه ها را تولید کنید. این کار را می توانید با کد زیر انجام دهید:

npm install -g express

بعد از این که کد بالا را اجرا کردید می توانید با اجرا کردن دستور express در خط فرمان ساختار اصلی برنامه را ایجاد کنید.

بگزارید به برنامه‌ی قبلی که با فایل package.json ایجاد کردیم برگردیم و فایل app.js را به آن اضافه کنیم. برنامه‌ی شما نمونه‌ای از شی Express را ایجاد کرده و شروع به گوش دادن به پورتی خاص می کند. به این صورت:

var express = require('express');
var app = express();
 
app.listen(3000);

شخصاً تمایل دارم زمانی که در حال یاد گرفتن فریمورک جدید هستم همه چیز به آرامی پیش برود، بنابراین شاید این حس به وجود بیاید که به سرعت دستور node app را اجرا کنیم تا مطمئن شوید جایی را اشتباه نکرده ایم.

بیایید چند مسیر ساده به برنامه اضافه کنیم. برنامه های Express می توانند به متدهای متفاوت HTTP به عنوان API پاسخ بدهند. به عنوان مثال:

//Regular HTTP get
app.get(some url, do something);
 
//Some other page
app.get(some other url, do something else);
 
//I can respond to a form post
app.post(some url, do more stuff);

حالا بیایید یک مثال واقعی از مسیردهی ها ایجاد کنیم و یک صفحه خانگی به برنامه اضافه کنیم:

app.get('/', function(request, response) {
    response.send("This would be some HTML");
});

توجه داشته باشید که Express متد send() را به شی response اضافه می کند. این مفهوم باعث میشود که دیگر نیازی به استفاده از یک سری کدهای تکراری برای کار با درخواست ها را نداشته باشیم. اگر همه چیز را درست انجام داده باشید شما می توانید برنامه خود را ری‌استارت کرده و آن را در مرورگر بر روی پورت 3000 باز نمایید.

همچنین متد request.send() به طور هوشمند انواع مختلف دیتاهای ارسالی را پردازش می کند. تصور کنید که شما می خواهید یک API به سایتتان اضافه کنید که نوع داده‌ای که با آن سروکار دارد JSON باشد. به راحتی شما می توانید یک شی به جای رشته برگردانید، Express نتیجه را به JSON تبدیل می کند و همچنین هدرهای http مناسب را نیز تنظیم می کند.

app.get('/api', function(request, response) {
    response.send({name:"Raymond",age:40});
});

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

به عنوان اولین سایتمان، یک وبلاگ خواهیم ساخت. چیز جدید و هیجان انگیزی نیست ولی این چیزی است که همه به صورت مفهومی آن را درک می کنند. شما می توانید سورس کامل کدهای این برنامه را در فایل ضمیمه در فولدر blog1 پیدا کنید. از فایل package.json به جز تغییر اسم پروژه نیاز به تغییر خاصی ندارد. و به جای آن بیایید نگاهی به app.js بیاندازیم.

var express = require('express');
var app = express();
 
app.get('/', function(req, res) {
    res.sendfile('./views/index.html');
});
 
app.get('/about', function(req, res) {
    res.sendfile('./views/about.html');
});
 
app.get('/article', function(req, res) {
    res.sendfile('./views/article.html');
});
 
app.listen(3000);

اولین چیزی که شما متوجه آن شدید این است که ما به جای استفاده از متد send از متد sendfile استفاده کردیم. در حالی که می توانستیم کدهای HTML را در فایل app.js را اضافه کنیم که باعث می شود کد ما به هم ریخته شود. ما سه مسیر (route) برای این برنامه داریم. یکی برای صفحه خانگی، یکی برای صفحه درباره ما و دیگری برای مقاله. معمولاً صفحه مقاله باید ارائه کننده محتوای وبلاگ باشد ولی فعلاً سعی می کنیم که همه چیز را ساده در نظر بگیریم.

کد HTML صفحات ما نسبتاً ساده می باشد. در زیر کد HTML صفحه خانگی را مشاهده می کنید:

<html>
<head>
    <title>Home Page</title>
</head>
 
<body>
<h1>Blog!</h1>
 
<footer>
<p>
    <a href="/">Home</a> ~ <a href="/about">About Me</a> ~ <a href="/article">Some Article</a>
</p>
</footer>
 
</body>
</html>

توجه داشته باشید که چیز خاصی در اینجا وجود ندارد. کد بالا یک سری دستورات HTML استاتیک می باشد که توسط برنامه Express بازگردانده می شود. هر دو صفحه درباره ما و مقاله کد یکسانی دارند فقط باید تغییراتی در عنوان و h1 اعمال کنیم.

یک بار دیگر برنامه را در خط فرمان اجرا کنید و مرورگر را باز نمایید. (یکی از اشتباهاتی که من در اوایل یادگیری Node مرتکب می شدم این بود که فراموش می کردم که برنامه قبلی را از بین ببرم. اگر هنوز برنامه قبلی درحال اجرا باشد پورت 3000 را در اختیار دارد. و شما باید برنامه قبلی را متوقف کنید و یا از پورتی دیگر استفاده نمایید.) شما می توانید تمام قسمت های برنامه را با چند کلیک در مروگر مشاهده نمایید.

و حالا بیایید که از حالت استاتیک به داینامیک حرکت کنیم.

Express از موتورهای قالب و یا همان templating engine های متنوعی پشتیبانی می کند. خط فرمان Express از تمپلت انجینهایِی مانند Jade، EJS، JSHTML و Hogan پشتیبانی میکند. طبق اسناد Express هر تمپلت انجینی که مطابق با امضای خاصی باشد می تواند با Express کار کند. همچنین پیشنهاد می کنند که کتابخانه consolidate.js را برای مشاهده لیست تمپلت انجین های که ساپورت می کند را برسی نماییم.

شخصاً علاقه بسیاری به Handlebars دارم (handlebarsjs.com). من از این تمپلت انجین در بسیاری از برنامه های سمت کاربر استفاده کرده ام برای همین برای استفاده در سمت سرور نیز برای من مناسب می باشد. برای استفاده از Handlebars نیاز دارید که کتابخانه hbs را نصب نمایید. بیایید تا این را به برنامه اضافه کنیم.

{
    "name": "blog2",
    "description": "Blog app",
    "version": "0.0.1",
    "dependencies": {
        "express": "3.x",
        "hbs":"*"
    }
}

حالا بیایید فایل app.js را برای استفاده از این تمپلت اینجین بروزرسانی کنیم:

var express = require('express');
var app = express();
 
var hbs = require('hbs');
 
app.set('view engine', 'html');
app.engine('html', hbs.__express);
 
app.get('/', function(req, res) {
    res.render('index');
});
 
app.get('/about', function(req, res) {
    res.render('about');
});
 
app.get('/article', function(req, res) {
    res.render('article');
});
 
app.listen(3000);

ما یک سری کارهای مهم را اینجا انجام دادیم. برای استفاده از Handlebars با استفاده از دستور require آن را لود کردیم. سپس احتیاج داریم که به Express اعلام کنیم که از این تمپلت انجین استفاده کند. به طور پیشفرض Handlebars با فایلهایی کار می کند که دارای فرمتی خاص باشند برای ما این فرمت something.hbs می باشد. ولی ما می توانیم به Express بگوییم که با فایل های HTML به عنوان فایل های داینامیک رفتار کند همانطور که در بالا مشاهده می کنید این کار را می توانیم با دستور "view engine" انجام دهیم. این کار الزامی نیست ولی من ترجیح می دهم که برای کار با فایل های HTML از آن استفاده کنم. با این کار ادیتور من می تواند در حدس کد و … به من کمک کند. لود کردن موتور قالب با استفاده از دستور app.engine صورت می پذیرد.

در نهایت در تمامی مسیرها از متد render استفاده می کنیم. Express به طور پیش فرض از فولدر views استفاده میکند در نتیجه فقط وارد کردن نام view کفایت می کند همچنین به دلیل اینکه Express از فرمت فایل هایی که از قبل تعیین کردیم آگاه است احتیاجی به وارد فرمت فایل ها نیز نمی باشد. اساساً ('res.render('something مانند این است که به Express بگوییم که به دنبال فایلی در views/something.html باش، آن را بر اساس قوانین تمپلت انجین ما پردازش کن و به مروگر بازگردان.

شما می توانید این مثال را در فولدر blog2 در ضمیمه سورس کد پیدا نمایید. همانطور که قبلاً هم گفتم مایلم که آهسته پیش بروم اگرچه ما هنوز به معنای واقعی کار داینامیکی نکرده ایم ولی من توصیه می کنم که یک بار دیگر برنامه را اجرا کنیم تا مطمئن شویم سایت بدون نقض اجرا می شود.

با توجه به اینکه برنامه ما از تمپلت های داینامیک پشتیبانی می کند بیاید تا به صورت واقعی آن را داینامیک کنیم. از آن جایی که ما در حال ایجاد یک وبلاگ هستیم باید لیست نوشته های وبلاگ به همراه لینک به هر کدام از آنها را در صفحه خانگی نمایش دهیم. در حالیکه ما می توانیم به دیتابیس هایی مانند MySQL و یا Mongo  متصل شویم ولی از یک سری دیتای استاتیک به عنوان یک کتابخانه استفاده خواهیم کرد. کتابخانه ما نام blog.js یک سری امکانات برای دریافت تمام محتوای وبلاگ و یا دریافت فقط یکی از آن ها را فراهم می کند.

var entries = [
{"id":1, "title":"Hello World!", "body":"This is the body of my blog entry. Sooo exciting.", "published":"6/2/2013"},
{"id":2, "title":"Eggs for Breakfast", "body":"Today I had eggs for breakfast. Sooo exciting.", "published":"6/3/2013"},
{"id":3, "title":"Beer is Good", "body":"News Flash! Beer is awesome!", "published":"6/4/2013"},
{"id":4, "title":"Mean People Suck", "body":"People who are mean aren't nice or fun to hang around.", "published":"6/5/2013"},
{"id":5, "title":"I'm Leaving Technology X and You Care", "body":"Let me write some link bait about why I'm not using a particular technology anymore.", "published":"6/10/2013"},
{"id":6, "title":"Help My Kickstarter", "body":"I want a new XBox One. Please fund my Kickstarter.", "published":"6/12/2013"}];
 
 
exports.getBlogEntries = function() {
    return entries;
}
 
exports.getBlogEntry = function(id) {
    for(var i=0; i < entries.length; i++) {
        if(entries[i].id == id) return entries[i];
    }
}

اساساً ما باید متدهایی برای اضافه کردن، حذف و ویرایش محتوا داشته باشیم اما در حال حاضر نیازی به اینها نداریم. حالا بیایید نگاهی به فایل app.js بیاندازیم.

var express = require('express');
var app = express();
 
var hbs = require('hbs');
 
var blogEngine = require('./blog');
 
app.set('view engine', 'html');
app.engine('html', hbs.__express);
app.use(express.bodyParser());
 
app.get('/', function(req, res) {
    res.render('index',{title:"My Blog", entries:blogEngine.getBlogEntries()});
});
 
app.get('/about', function(req, res) {
    res.render('about', {title:"About Me"});
});
 
app.get('/article/:id', function(req, res) {
    var entry = blogEngine.getBlogEntry(req.params.id);
    res.render('article',{title:entry.title, blog:entry});
});
 
app.listen(3000);

حالا یکی یکی آنها را بروزرسانی کنیم. (این نسخه از برنامه را در فولدر blog3 می توانید پیدا کنید.) ابتدا ما فایل blog.js را به برنامه با استفاده از دستور require اضافه می کنیم. این کار به ما این اجازه را می دهد تا محتواهای وبلاگ را فراخوانی کنیم. شاید متوجه بخشی از کد bodyParser شده باشید ولی فعلاً کاری با این قسمت نداشته باشید.

در روتر مرتبط با صفحه خانگی، آرگومان دیگری را به متد render ارسال کرده ایم. این آرگومان یک شی با دو کلید title و entries می باشد. مقدار title یک رشته می باشد و مقدار entries را برابر با فراخوانی متد blogEngine قرار می دهیم. این جا جایست که قضیه جالب می شود. هر دیتایی که ما ارسال میکنیم در تمپلت ما قابل دسترسی می باشد. بسته به زبان تمپلت ما، نحوه استفاده از این دیتاها ممکن است تغییر کند. بیاید تا نگاهی به صفحه خانگی بیاندازیم.

<h1>Blog!</h1>
 
{{#each entries}}
    <p>
        <a href="/article/{{id}}">{{title}}</a><br/>
        Published: {{published}}
    </p>
{{/each}}

اگر شما تا پیش از این از Handlebars استفاده نکرده باشید احتمالاٌ میتوانید کاربرد این کدها را حدس بزنید. دستور each# بر روی عناصر یک آرایه چرخش می کند. در داخل بلاک، من از توکن های Handlebars استفاده کرده ام این توکن ها به دیتای نوشته های وبلاگ من اشاره دارند و با کمک اینها می توان لیست نوشته های وبلاگ را به صورت HTML تولید کرد. برای کسانی که بک گراند ColdFusion دارند این موارد بسیار آشنا می باشد.

من شرط می بندم که شما متعجب شده اید که بقیه کدهای HTML کجا رفته اند. زمانی که از تمپلت انجین ها در Express استفاده می کنید به طور اتوماتیک از layout ها پشتیانی می شود. بدین معناست که ما می توانیم یک layout عمومی برای ظاهر سایت ایجاد کنیم و سپس Express به خروجی هر صفحه این layout را تزریق می کند. به طور قرار دادی، layout به صورت layout.something نام گزاری می شود که “something” فرمتی است که شما در حال استفاده از آن هستید که در این جا، layout.html می باشد.

<html>
 
<head>
    <title>{{title}}</title>
</head>
 
<body>
 
    {{{body}}}
 
    <footer>
        <p>
            <a href="/">Home</a> ~ <a href="/about">About Me</a>
        </p>
    </footer>
     
</body>
</html>

صفحه ی درباره ما چیز خاصی ندارد پس ما از آن عبور می کنیم ولی روتر article را یک بار دیگر برسی کنید. url این روتر دارای یک توکن به نام :id می باشد. Express این اجازه را به ما می دهد تا  url های داینامیک ایجاد کنیم و بتوانیم آرگومان های موجود در آدرسها را استخراج کنیم. شاید متوجه شده باشید که ما در صفحه خانگی، لینک ها را به صورت /article/{{id}} ایجاد کردیم.

به صورت تئوری ما می توانیم برای هر نوشته وبلاگ یک روتر اضافه کنیم ولی بهتر است که یک روتر کلی ایجاد کنیم و هر درخواستی که با فرمی خاص و تعیین شده می باشد را مسیردهی کند. برای انجام این کار، ما به bodyParser که چند سطر قبل آن تعریف کردیم نیاز داریم. (این ویژگی از فریمورک Connect وارد Express شده است که به شما کمک می کند تا بتوانید با query string ها و فرم ها کار کنید. تقریباً تمام برنامه هایی که با Express نوشته می شوند به این ویژگی نیاز دارند.)

از آن جایی که ما به مقدار انتهایی URL دسترسی پیدا کرده ایم، می توانیم به سادگی شماره ی هر نوشته‌ی وبلاگ را به شی blogEngine ارسال کنیم و نتیجه آن را به عنوان آرگومان به view ارسال کنیم.

فایل article.html

<h1>{{blog.title}}</h1>
Published: {{blog.published}}
 
<p/>
 
{{blog.body}}

حالا سایت ما داینامیک می باشد ولی ظاهر زیبایی ندارد. صفحه خانگی برنامه ما:

و این هم یکی از نوشته های وبلاگ:

بیایید کمی استایل برای زیباتر شدن به برنامه اضافه کنیم. Express روشی ساده برای دسترسی به فایل های استاتیک مانند تصاویر، فایل های جاوااسکریپت و استایل ها فراهم کرده است. به سادگی با تعریف کردن فولدر فایل های استاتیک، هر ریکوئست برای این فایل ها، مستقیماً در داخل این فولدر برسی می شود. در این جا ورژن نهایی وبلاگ را می توانید مشاهده کنید (این نسخه در فولدر blog4 قرار گرفته است):

app.use(express.static('public'));

در این مرحله اگر شما ریکوستی برای آدرس /foo.css ارسال نمایید و فایل foo.css در فولدر public وجود داشته باشد، آنگاه این فایل به شما برگردانده خواهد شد. از آن جایی که توانایی طراحی من مانند سایر توسعه دهندگان خوب می باشد راه آسان را انتخاب کردم و یک کپی از Bootstrap ایجاد کردم (http://twitter.github.io/bootstrap/). من بوت استرپ و یک کپی از jQuery را در فولدر public قرار دادم.

و در فایل layout.html می توانم این دو فایل را اضافه کنم. در زیر نمونه ای از اضافه کردن فایل bootstrap.css به layout را مشاهده می نمایید.

<link href="/bootstrap/css/bootstrap.css" rel="stylesheet">

حالا Express به طور خودکار این فایل را در فولدر public جستجو می نماید. شما می توانید چندین فولدر استاتیک داشته باشید. نتیجه خیره کننده است. (در مقایسه با ورژن اولیه یک پیشرفت چشمگیر می باشد!)

صفحه خانگی:

یکی از نوشته ها:

مایلید بیشتر یاد بگیرید؟ تعدادی لینک برای شما فراهم کرده ام امیدوارم که مفید باشه.

  • بدیهی است که اولین ایستگاه شما Express homepage می باشد.
  • شما می توانید برای صحبت کردن با سایر توسعه دهندگان عضو گروه های گوگل شوید.
  • کانال IRC : برای اتصال به کانال IRC از هشتگ #express استفاده کنید.
  • در نهایت می توانید نگاهی به مثال های موجود در گیت هاب بیاندازید.
نویسنده مطلب
علی پامناری

دیدگاه کاربران

  • AZFX41
    7 سال, 2 ماه پیش
    سلام تشکر خیلی خوب کار کردید

این وب سایت متعلق است به آذین وب (طراحی سایت در اصفهان) و تمامی حقوق آن محفوظ است.

طـبق ماده 12 فصل سوم قانون جرائم رایانه ای هرگونه کپی برداری از قالب پیگرد قانونی دارد.