:: # دورة النظم المتقدمة في المحاسبة وتحقيق الرقابة المالية وتقييم الأداء#30يونيه 2024م (آخر رد :جهاد سعيد)       :: # دورة إعداد التقارير و المراسلات والأرشفة#2 يونيه 2024م #اسطنبول#metc (آخر رد :جهاد سعيد)       :: خدمات شركة الحمد (آخر رد :soha mag)       :: # دورة الادارة الامنة للشبكات وأنظمة التشغيل#7 يوليو 2024م #القاهرة#metc (آخر رد :جهاد سعيد)       :: # دورة استراتيجيات التخطيط في إدارة الأزمات#23 يونيه 2024م #دبي#metc (آخر رد :جهاد سعيد)       :: خدمات شركة الحمد (آخر رد :soha mag)       :: # دورة إعداد ميزانية برامج الصيانة الإنتاجية#2 يونيه 2024م #القاهرة#metc (آخر رد :جهاد سعيد)       :: # دورة الاستراتيجيات المتقدمة للمشتريات والمخازن وادارة الخدمات اللوجستية#2 يونيه 202 (آخر رد :جهاد سعيد)       :: شركة الحمد وفروعها (آخر رد :soha mag)       :: #دورة الإبتكار في تطبيقات الذكاء الإصطناعي للتميّز المؤسسي #26 مايو 2024م #دبي#metc (آخر رد :جهاد سعيد)      
اختر لونك:
وَقُلِ اعْمَلُوا فَسَيَرَى اللَّهُ عَمَلَكُمْ وَرَسُولُهُ وَالْمُؤْمِنُونَ ۖ وَسَتُرَدُّونَ إِلَىٰ عَالِمِ الْغَيْبِ وَالشَّهَادَةِ فَيُنَبِّئُكُم بِمَا كُنتُمْ تَعْمَلُونَ [ التوبة : ( 105 )] كلمة الإدارة

يرجى إختيار القسم المناسب قبل النشر وسيعاقب المخالف بإنذار أول مرة وسيتم حظره إذا تكرر ذلك كلمة الإدارة

يُمنع كتابة مواضيع السحر والشعوذة والروحانيات والابراج بكافة الأشكال والمخالف سيعاقب بحظر مؤقت وإذا تكرر سيكون حظر دائم تنبيه هام جداً



أضف رد جديد
 
LinkBack أدوات الموضوع انواع عرض الموضوع

قديم 01-04-2019, 06:21 PM   #1
تاريخ التسجيل: Feb 2019
العمر: 38
المشاركات: 1,149
التقييم: 10
تاريخ التسجيل: Feb 2019
العمر: 38
المشاركات: 1,149
التقييم: 10
افتراضي ما هو محزم الوحدات webpack

تحدثنا في مقال سابق عن Webpack من الناحية النظرية، وشرحنا دوره وأهميته في حياة مطوري الويب هذه الأيام.
وكنت قد وعدتكم بأن أقوم بإعداد درس جديد من أجل شرح webpack واكتشافه بطريقة عملية حتى تترسخ في أذهاننا المفاهيم التي رأيناها في الدرس السابق، وها أنا اليوم أفي بوعدي لكم
سنسير في هذا الدرس خطوغ بخطوة لنرى كيفية إعداد ويب باك من الصفر من أجل تكييفه مع احتياجات مشروعنا، وقد يكون هذا الدرس طويلا لأنني لا أريد أن أحرق أي مرحلة مهما كانت بسيطة حتى يكون الشرح في متناول المبتدئين والمتقدمين على السواء.
البداية

لننشئ مجلدا اسمه wepback-project ونقوم بالدخول إليه :
mkdir wepback-project cd wepback-project
1
2

mkdir wepback-project
cd wepback-project



ثم لنقم بتهيئة ملف packages.json عن طريق هذا الأمر :
npm init
1

npm init



بعد إنشاء الملف packages.json سنقوم بتحميل Webpack 4، وهي آخر نسحة من webpack لحدود كتابة هذه الأسطر، مع تحميل حزمة Webpack-cli لتنفيذ بعض أوامر webpack انطلاقا من Terminal.
npm install webpack webpack-cli --save-dev
1

npm install webpack webpack-cli --save-dev



الآن، عند تنفيذ الأمر webpack من نافذة Terminal فإنه ستظهر لنا رسالة الخطأ هذه :
محزم الوحدات webpack
الرسالة باللون الأصفر هي فقط رسالة تحذيرية تعلمنا بأن webpack يفترض مسبقا بأننا في وضع الإنتاج (Production) إذا لم نقل له العكس، وبالتالي فإنه قد يقوم بتنفيذ بعض المهام الخاصة بهذا الوضع مثل ضغط ملفات CSS و JS إلخ…
أما الرسالة الثانية باللون الأحمر فهي رسالة خطأ تقول لنا بأن webpack يبحث عن مجلد اسمه src في مشروعنا ولكن لم يجده. فانطلاقا من النسخة الرابعة، أصبح webpack يعتمد مقاربة zero configuration التي تمكننا من القيام بعدد من المهام الأساسية من دون إنشاء ملف الإعدادات webpack.config.js. لهذا يفترض هذا المحزم بأن هناك مجلد اسمه src وبداخله ملف index.js، ويمكننا طبعا تغيير هذه الإعدادات الإفتراضية عبر ملف webpack.config.js كما سنرى لاحقا، أو حتى من دونه إنطلاقا من الأوامر السطرية فقط :
webpack ./src/index.js --output ./dist/main.js
1

webpack ./src/index.js --output ./dist/main.js



وضع التطوير

لنقم بإنشاء المجلد src وملف index.js بداخله.
وبما أننا في مرحلة التطوير، فسنطلب من webpack أن يقوم بعمله بناء على هذا الوضع، والطريقة هي عبر إضافة العلم mode– لأوامر ويب باك :
webpack --mode development
1

webpack --mode development



محزم الوحدات webpack
بعد تنفيذ هذا الأمر، ستتم عملية التحزيم بنجاح لأن ويب باك وجد كل الظروف التي افترضها مسبقا. وستلاحظون بأنه قام بإنشاء مجلد جديد اسمه dist بداخله ملف جافاسكريبت main.js وبداخله كود الجافاسكريبت المحزم، غير مضغوط لأننا طلبنا من webpack أن يعمل وفق إعدادات وضع التطوير Development.
ولجعل بيئة عملنا أكثر احترافية وعملية، سنقوم بتنفيذ أوامر webpack من داخل سكريبتات npm التي نقوم بإضافتها داخل الملف package.json في منطقة scripts. إليكم الطريقة :
"scripts": { "dev": "webpack --mode development" }
1
2
3

"scripts": {
"dev": "webpack --mode development"
}



لإعادة تنفيذ الأمر السابق webpack --mode development ، يكفي تنفيذ هذا الأمر :
npm run dev
1

npm run dev



بهذه الطريقة يمكننا تنفيذ أوامر npm مهما كانت معقدة، ومهما أظفنا أعلاما وخصائص جديدة لأوامر webpack فإن أمر npm الذي نقوم بتنفيذه في نافذة Terminal يبقى كما هو. وحتى إذا قدر لمطور آخر أن يعمل على مشروعنا، فسيمكنه معرفة الأوامر التي يجب تنفيذها على المشروع فقط بفتح الملف package.json ومعاينة الأوامر داخل الخاصية {} scripts .
لإضافة وضع بناء جديد خاص بمرحلة الإنتاج، فيمكننا إنشاء سكريبت جديد اسمه مثلا build بنفس الكيفية التي أضفنا بها السكريبت dev.
"scripts": { "dev": "webpack --mode development", "build": "webpack --mode production" }
1
2
3
4

"scripts": {
"dev": "webpack --mode development",
"build": "webpack --mode production"
}



npm run build
1

npm run build



لكي لا نضطر لإعادة تنفيذ هذه الأوامر بعد كل عملية تعديل على الملف index.js، سنقوم بإضافة علم جديد (flag) اسمه watch– لأوامر webpack بهذه الكيفية :
"scripts": { "dev": "webpack --mode development --watch", "build": "webpack --mode production --watch" }
1
2
3
4

"scripts": {
"dev": "webpack --mode development --watch",
"build": "webpack --mode production --watch"
}



لنبدأ العمل في الأمور الجادة

أحدث طريقة لكتابة أكواد الجافاسكريبت معروفة باسم ES6، ولكن مع الأسف لا تدعمها حتى الآن بشكل كامل كل المتصفحات الكبيرة، لذلك علينا تحويل أكواد جافاسكريبت ES6 إلى أكواد جافاسكريبت ES5 مدعومة من كافة المتصفحات. هذه العملية معروفة باسم Transpiling، ويعتبر Babel هو أشهر Transpiler لأكواد الجافاسكريبت في الوقت الحالي.
لنكتشف معا كيفية استخدام Babel مع webpack
تحميل وإعداد بابل Babel

أولا علينا تحميل بابل من مستودع npm مع ملحقاته التي سوف نحتاجها.
npm install babel-core babel-loader babel-preset-env --save-dev
1

npm install babel-core babel-loader babel-preset-env --save-dev



قمنا هنا بتحميل 3 حزم :
  1. babel-core : الحزمة التي تحتوي على الشفرة المصدرية لنواة بابل.
  2. babel-preset-env : الحزمة التي تمكن نواة بابل من تحويل أكواد جافاسكريبت ES6 إلى أكواد جافاسكريبت ES5.
  3. babel-loader : هذه الحزمة تمثل ال loader الذي يستخدمه webpack لكي يعمل بتوافقية كاملة مع Babel. يعني أن webpack يستعين ببابل في عملية Transpiling قبل أن يقوم بعملية التجميع أو التحزيم ( Bundling ).
كما شرحنا في المقال السابق، فإن webpack يعتمد على ما يعرف ب Loaders لكي يتمكن من تحزيم ومعالجة مختلف أنواع الملفات، وليس فقط ملفات جافاسكريبت (صور، CSS، خطوط، JSX ،TypeScript إلخ …).
الآن بعد أن قمنا بتحميل الحزم الثلاث، سنقوم بإنشاء ملف اسمه babelrc. لكي نطلب من بابل أن يستخدم الإضافة babel-preset-env ( تعرف هذه الإضافات في بيئة “بابل” ب Presets ) أثناء عملية Transpiling. ونكتب بداخله ما يلي :
{ "presets": [ "env" ] }
1
2
3
4
5

{
"presets": [
"env"
]
}



جاء الوقت الآن لنطلب من “ويب باك” أن يستعين ب Babel، سنفعل ذلك عن طريق ملف webpack.config.js الذي ذكرناه أكثر من مرة.
إعداد “ويب باك”

نحن الآن مطالبين بالإستعانة بالملف webpack.config.js من أجل إضافة عدد من الإعدادات المتقدمة ل Webpack.
لنشئ هذا الملف الآن، ولنضع فيه المحتوى التالي :
const path = require('path'); module.exports = { entry: { main: './src/index.js' }, output: { path: path.resolve(__dirname, 'dist'), filename: 'main.js' } };
1
2
3
4
5
6
7
8
9

const path = require('path');

module.exports = {
entry: { main: './src/index.js' },
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'main.js'
}
};



هذا هو أبسط صورة يمكن أن يكون عليها الملف webpack.config.js، وهذا الكود بسيط حيث يطلب من ويب باك فقط أن يبدأ التحزيم من ملف index.js (يسمى Entry point) على أن يجمع الكود النهائي في ملف main.js (يسمى Output file) وهي كما رأينا سابقا الإعدادات الإفتراضية التي يمكن تغييرها كما شئنا.
لنطلب الآن من webpack أن يستخدم الحزمة babel-loader لكي نتمكن من كتابة أكواد جافاسكريبت ES6 :
const path = require('path'); module.exports = { entry: { main: './src/index.js' }, output: { path: path.resolve(__dirname, 'dist'), filename: 'main.js' }, module: { rules: [ { test: /\.js$/, exclude: /node_modules/, use: { loader: "babel-loader" } } ] } };
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

const path = require('path');

module.exports = {
entry: { main: './src/index.js' },
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'main.js'
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
}
]
}
};



لاحظوا بأننا أضفنا المنطقة {} module، هناك سيتم إضافة وإعداد جميع ال Loaders التي نحتاجها مع webpack في مشروعنا. بداخل المصفوفة rules نضع هذه ال loaders على شكل كائنات من نوع JSON، وكل كائن يضم مجموعة من الخصائص أهمها :
  • test : هذه الخاصية عبارة عن RegEx وتحدد ل webpack أي نوع من الملفات سيقوم بإجراء هذا loader عليها.
  • exclude : الملفات التي نريد استبعادها رغم أنها تحقق ال RegEx المحدد في الخاصية test.
  • use : هذه الخاصية تخبر webpack بال loaders التي عليه إجراؤها وتطبيقها على هذه الملفات. (babel-loader في حالتنا).
سنفتح الآن الملف index.js ونكتب فيه بعضا من كود جافاسكريبت ES6 :
// src/index.js const fn = () => "Arrow functions're Working!"; alert(fn());
1
2
3
4
5

// src/index.js

const fn = () => "Arrow functions're Working!";

alert(fn());



بعد تنفيذ الأمر npm run dev سنلاحظ بأن webpack قام بعملية التجميع في الملف main.js مع تحويل الدالة السهمية (Arrow function) أعلاه إلى دالة تقليدية بطريقة جافاسكريبت ES5.
// dist/main.js "use strict"; var fn = function fn() { return "Arrow functions're Working!"; }; alert(fn());
1
2
3
4
5
6
7
8
9

// dist/main.js

"use strict";

var fn = function fn() {
return "Arrow functions're Working!";
};

alert(fn());



إذن أصبح بإمكاننا الآن كتابة أكواد جافاسكريبت الحديثة في مشروعنا، و webpack بفضل ال babel-loader سيتولى مهمة تجميعها وتحويلها لأكواد جافاسكريبت ES5 المدعومة من معظم المتصفحات.
ماذا عن ملفات HTML ؟

نحن الآن لدينا ملف dist/main.js المحزم والجاهز للإستدعاء في صفحة الويب، ولكن أين هي هذه الصفحة ؟ لا تقلق، صديقي، سنقوم بإضافتها حالا.
لنقم بإنشاء ملف اسمه index.html داخل المجلد src ونضع فيه المحتوى التالي :
// dist/index.html <html> <head> </head> <body> <h1>مرحبا بكم في توتومينا :)</h1> </body> </html>
1
2
3
4
5
6
7
8
9
10
11
12

// dist/index.html

<html>

<head>
</head>

<body>
<h1>مرحبا بكم في توتومينا :)</h1>
</body>

</html>



هناك مشكلة صغيرة تواجهنا الآن عندما نقوم بتنفيذ الأمر npm run dev فإنه لا يتم إنشاء أي ملف HTML داخل المجلد dist، رغم أننا قمنا بإنشاء الملف index.html في المجلد src. من الواضح إذن بأن webpack لا يستطيع لوحده القيام بهذه المهمة. سنقوم بمساعدته بواسطة إضافة جديدة ( Plugin ) اسمها HTML webpack Plugin.
تلاحظون كذلك أننا لم نقم باستدعاء أي ملف جافاسكريبت في الصفحة src/index.html سنترك هذه المهمة أيضا للإضافة HTML webpack Plugin التي سنقوم بتثبيها في مشروعنا حالا ؛)
npm i --save-dev html-webpack-plugin
1

npm i --save-dev html-webpack-plugin



بعد تثبيت إضافتنا الجديدة، سنقوم بإعداد webpack لكي يقوم باستخدامها. هيا بنا إلى الملف webpack.config.js
... const HtmlWebpackPlugin = require('html-webpack-plugin') module.exports = { entry: { ... }, output: { ... }, module: { rules: [ ... ] }, plugins: [ new HtmlWebpackPlugin({ hash: true, template: './src/index.html', filename: 'index.html' }) ] };
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

...

const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
entry: {
...
},
output: {
...
},
module: {
rules: [
...
]
},
plugins: [
new HtmlWebpackPlugin({
hash: true,
template: './src/index.html',
filename: 'index.html'
})
]
};



في البداية قمنا بإنشاء متغير (كلاس) جديد HtmlWebpackPlugin انطلاقا من الحزمة html-webpack-plugin، ثم قمنا بإنشاء نموذج (Instance) من هذا الكلاس داخل المصفوفة plugins، وبعد ذلك قمنا بتمرير 3 معاملات :
  • hash : قمنا بتمرير true لهذا المعامل حتى يتم إضافة سلسلة حروف وأرقام عشوائية إلى نهاية اسم ملف الجافاسكريبت المحزم ( مثال: main.js?3cbc8ec659d08ad396e1 ) عند استدعائه في الصفحة. يستخدم هذا ال Hash لأغراض تتعلق بالكاش Cache الخاص بالصفحة.
  • template : هذا المعامل يمثل مسار القالب الذي سيبنى عليه ملف HTML المُخرَج.
  • filename : اسم ملف HTMLالمُخرَج.
وهناك مجموعة من المعاملات الأخرى يمكنكم الإطلاع عليها في صفحة الإضافة على Github.
الآن، بعض تنفيذ npm run dev مرة أخرى سنرى بأن webpack قام بإنشاء ملف index.html داخل المجلد dist مع استدعاء الملف main.js المحزم (Bundled).
// dist/index.html <html> <head> </head> <body> <h1>مرحبا بكم في توتومينا :)</h1> <script type="text/javascript" src="main.js?3cbc8ec659d08ad396e1"></script></body> </html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14

// dist/index.html

<html>

<head>
</head>

<body>

<h1>مرحبا بكم في توتومينا :)</h1>

<script type="text/javascript" src="main.js?3cbc8ec659d08ad396e1"></script></body>

</html>



لم ننتهي بعد! أين هو CSS ؟

لا يوجد تطبيق ويب من دون CSS، لنقم بإنشاء ملف style.css في المجلد src.
ثم لنقم باستدعائه من ملف index.js، نعم من الجافاسكريبت
// src/index.js import './style.css'; const fn = () => "Arrow functions're Working!"; alert(fn());
1
2
3
4
5
6

// src/index.js

import './style.css';

const fn = () => "Arrow functions're Working!";
alert(fn());



webpack لا يستطيع التعامل مع ملفات CSS، فهو دائما ينتظر ملفات JavaScript. لهذا عند تشغيله سيظهر لنا هذا الخطأ الجميل والذي يخبرنا بأنه علينا مساعدة webpack في إيجاد حل للتعامل مع ملفات CSS وذلك بتثبيت ال Loader المناسب لهذه الحالة.
محزم الوحدات webpack
ال Loader الذي نحتاجه هنا موجود واسمه css-loader، لنقم بتثبيته الآن :
npm install --save-dev css-loader
1

npm install --save-dev css-loader



هذا loader يمكن webpack من استيراد أكواد CSS باستخدام import أو require، وهذه حدود دور css-loader، هذا الدور ضروري ولكنه غير كافي.
نحن الآن لدينا ال CSS المستورد بفضل css-loader، ولكن كيف نقوم باستدعاء هذا CSS في الصفحة ؟
لحسن الحظ هناك إضافة (Plugin) أخرى اسمها mini-css-extract-plugin وتمكن من استخلاص ال CSS المستورد ووضعه في ملف (أو ملفات) CSS منفصل.
لنقم بتثبيت هذه الإضافة :
npm install --save-dev mini-css-extract-plugin
1

npm install --save-dev mini-css-extract-plugin



بعد التثبيت، سنقوم بإعداد webpack لكي يستعين بهذه الإضافة الجديدة :
// webpack.config.js ... const MiniCssExtractPlugin = require("mini-css-extract-plugin"); module.exports = { entry: { ... }, output: { ... }, module: { rules: [ ... ,{ test: /\.css$/, use: [ MiniCssExtractPlugin.loader, "css-loader" ] } ] }, plugins: [ ..., new MiniCssExtractPlugin({ filename: "bundle.css" }) ] };
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

// webpack.config.js

...

const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
entry: { ... },
output: {
...
},
module: {
rules: [
...
,{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader"
]
}
]
},
plugins: [
...,
new MiniCssExtractPlugin({
filename: "bundle.css"
})
]
};



مثلما فعلنا مع إضافة HtmlWebpackPlugin، قمنا بإنشاء نموذج من الكلاس MiniCssExtractPlugin وأضفناه في المصفوعة plugins، ثم طلبنا منه أن يكون اسم ملف ال CSS المخرج bundle.css. ولا ننسى كذلك أننا أعطينا تعليمات لِ webpack من داخل المصفوفة rules لكي يقوم بإجراء css-loader و MiniCssExtractPlugin.loader (هذا الأخير يمكن تعويضه ب style-loader بعد تثبيته) على جميع الملفات من نوع css.
ومن الآن، بعد تشغيل webpack سيتم استخلاص ال css المستورد من داخل الجافاسكريبت ويضاف إلى ملف جديد اسمه bundle.css في المجلد dist، ثم يتم استدعائه تلقائيا في الملف dist/index.html إليكم الحالة النهائية لهذا الملف :
// dist/index.html <html> <head> <link href="bundle.css?a583e8290b8c96b0a276" rel="stylesheet"> </head> <body> <h1>مرحبا بكم في توتومينا :)</h1> <script type="text/javascript" src="main.js?a583e8290b8c96b0a276"></script> </body> </html>
1
2
3
4
5
6
7
8
9
10
11
12
13

// dist/index.html
<html>

<head>
<link href="bundle.css?a583e8290b8c96b0a276" rel="stylesheet">
</head>

<body>
<h1>مرحبا بكم في توتومينا :)</h1>
<script type="text/javascript" src="main.js?a583e8290b8c96b0a276"></script>
</body>

</html>



وفي الصورة التالية، تجدون البنية النهائية لمشروعنا :
محزم الوحدات webpack
النهاية

هكذا تعلمنا اليوم كيفية إضافة Webpack إلى مشاريعنا والإستعانة بالمزايا العديدة التي يوفرها بفضل العدد الكبير من Loaders و Plugins التي تزخر بها هذه البيئة.
المهام التي أنجزناها في هذا الدرس تعتبر بسيطة مقارنة بكل ما يمكن القيام به، حتى الإضافات و Loaders التي تطرقنا إليها اليوم لم نرى من إمكانياتها سوى القليل، فأدعوكم لزيارة صفحات كل واحدة منها على Github لإكتشاف جميع المزايا التي تقدمها.

raheel غير متواجد حالياً   اقتباس
أضف رد جديد


الذين يشاهدون محتوى الموضوع الآن : 1 ( الأعضاء 0 والزوار 1)
 

تعليمات المشاركة
لا تستطيع إضافة مواضيع جديدة
لا تستطيع الرد على المواضيع
لا تستطيع إرفاق ملفات
لا تستطيع تعديل مشاركاتك

BB code is متاحة
كود [IMG] متاحة
كود HTML معطلة
Trackbacks are متاحة
Pingbacks are متاحة
Refbacks are متاحة


المواضيع المتشابهه
الموضوع كاتب الموضوع المنتدى مشاركات آخر مشاركة
إدارة القسائم (Coupons)، الودجات (Widgets)، والشيفرات المختصرة (Shortcodes) في متجرك مهرة النجدية قسم تطوير المواقع ومحركات البحث والسيو Seo والووردبريس WordPress 1 22-07-2019 06:51 PM
دليلك الشامل حول النظام البيئي لِ “جافاسكريبت” raheel قسم تطوير المواقع ومحركات البحث والسيو Seo والووردبريس WordPress 0 01-04-2019 06:50 PM
كيفية استيراد وتصدير الوحدات على طريقة es5 raheel قسم تطوير المواقع ومحركات البحث والسيو Seo والووردبريس WordPress 0 01-04-2019 06:37 PM
مميزات Webpack التي تفوق بها على المنافسين raheel قسم تطوير المواقع ومحركات البحث والسيو Seo والووردبريس WordPress 0 01-04-2019 06:24 PM
كيفية إعداد مشروع React.js باستخدام Webpack 4 و Babel raheel قسم تطوير المواقع ومحركات البحث والسيو Seo والووردبريس WordPress 0 01-04-2019 06:04 PM


الساعة الآن 07:58 AM

 


Content Relevant URLs by vBSEO ©2010, Crawlability, Inc.