كيفية تكوين Webpack 4 مع Angular 7: دليل كامل

الشعارات الزاوي و webpack

يجعل Angular CLI من السهل إنشاء تطبيق يعمل بالفعل ، مباشرة من خارج الصندوق. إنها أداة رائعة ، لكنك لم تفكر أبدًا: "كيف تعمل؟ كيف يمكنني إنشاء تطبيق بدون CLI؟"

جاءت هذه الأسئلة إلى ذهني عندما تم إصدار Angular 7. بدأت في البحث عن إجابات على الويب وما وجدته لم يكن محدّثًا لغرضي. في الواقع ، حيث أن الزاوي و webpack يتطوران دائمًا ، لذا فإن التبعيات والتكوينات.

في هذه المقالة أنت على وشك أن تتعلم:

  • كيفية إعداد تطبيق Angular 7 الأساسي ، من نقطة الصفر
  • كيفية تكوين Webpack لوضع التطوير (الترجمة الفورية فقط)
  • كيفية تكوين حزمة الويب لوضع الإنتاج (ترجمة Ahead-of-Time)

الزاوي 7: إعداد التطبيق الأساسي

قم بإنشاء ملف package.json جديد وأضف الأسطر التالية لتثبيت Angular وتبعياته.

"تبعيات":
  "@ الزاوي / الرسوم المتحركة": "~ 7.0" ،
  "@ الزاوي / المشترك": "~ 7.0" ،
  "@ angular / compiler": "~ 7.0" ،
  "@ angular / compiler-cli": "~ 7.0" ،
  "@ الزاوي / الأساسية": "~ 7.0" ،
  "@ angular / forms": "~ 7.0" ،
  "@ angular / http": "~ 7.0" ،
  "@ angular / platform-browser": "~ 7.0" ،
  "@ الزاوي / متصفح النظام الأساسي": "~ 7.0" ،
  "@ angular / platform-server": "~ 7.0" ،
  "@ الزاوي / جهاز التوجيه": "~ 7.0" ،
  "@ الزاوي / الترقية": "~ 7.0" ،
  "core-js": "~ 2.5" ،
  "rxjs": "~ 6.3" ،
  "zone.js": "~ 0.8"
}

لقد كافحت لفترة طويلة للعثور على أفضل بنية مجلد يناسب كل مشروع Angular ، خاصةً عندما يزداد حجم التطبيق. لقد علمتني هذه المقالة الكثير عن الموضوع.

قم بإنشاء مجلد src جديد والمجلدات / الملفات التالية بداخله. سيكون كل منطق أعمال التطبيق الزاوي في هذا المجلد.

SRC
| __ التطبيق
    | __ الوحدات
        | __ القائمة
            | __ المكونات
                | __ القائمة
                    | __ menu.component.html
                    | __ menu.component.scss
                    | __ menu.component.ts
            | __ menu.module.ts
            | __ menu-routing.module.ts
| __ مشترك
         | __ المكونات
             | __ المنزل
                 | __ home.component.html
                 | __ home.component.scss
                 | __ home.component.ts
| __ app.component.html
        | __ app.component.scss
        | __ app.component.ts
        | __ app.module.ts
        | __ app-routing.module.ts
| __ index.html
| __ main.ts

يحتوي كل تطبيق على وحدة Angular واحدة على الأقل ، وهي وحدة الجذر التي تقوم بتمهيدها لتشغيل التطبيق. من الاتفاقية ، وعادة ما يطلق عليه AppModule. أقوم بإنشاء وحدة نمطية أخرى ، MenuModule لتوضح لك كيف يمكنك استخدام التحميل الكسول في مشروعك ، خاصةً بالنسبة للإنتاج.

بعض النقاط المهمة:

  • index.html و

إضافة تخبر جهاز التوجيه الزاوي الخاص بنا عن كيفية إنشاء عناوين URL للتنقل. يعني هذا السطر أن التطبيق الخاص بك سيبدأ من المجلد الجذر ، أي أنه محليًا سيضع في الاعتبار المضيف المحلي: 3000 / وعلى الخادم ، سيبحث المجلد الجذر.

  • التطبيق-routing.module.ts

هناك ثلاث خطوات رئيسية لإعداد وحدة ميزة التحميل البطيئة:

  1. إنشاء وحدة الميزة
  2. قم بإنشاء وحدة توجيه وحدة الميزات
  3. تكوين الطرق

يخبر {path: ’menu’، loadChildren: ’./ modules / menu / menu.module # MenuModule’} Angular أن يحمّل كسل وحدة الميزات لدينا MenuModule بحلول الوقت الذي يزور فيه المستخدم مسار / menu.

تكوين TypeScript

أضف الأسطر التالية إلى ملف package.json الخاص بك:

"devDependencies": {
  "@ types / core-js": "~ 2.5" ،
  "@ types / node": "~ 10.12" ،
  "typescript": "~ 3.1"
}

قم بإنشاء ملف tsconfig.json في مجلد مشروع الجذر الخاص بك:

{
  "compilerOptions": {
    "الهدف": "es5" ،
    "الوحدة النمطية": "commonjs" ،
    "moduleResolution": "node"،
    "sourceMap": صحيح ،
    "emitDecoratorMetadata": صحيح ،
    "الديكور التجريبي": صحيح ،
    "noImplicitAny": صحيح ،
    "suppressImplicitAnyIndexErrors": true،
    "lib": ["es6" ، "dom"] ،
    "typeRoots": ["node_modules / @ types"]
  }،
  "استبعاد": ["node_modules"]
}

هذا ملف تكوين TypeScript أساسي. من الضروري تثبيت تعريف أنواع العقدة و Core-js. بدون ذلك ، لن يكون برنامج TypeScript قادرًا على ترجمة تطبيقنا Angular إلى JavaScript.

تكوين Webpack لوضع التطوير (تجميع في الوقت المناسب)

بادئ ذي بدء ، ماذا يعني التجميع؟ لا يعني تجميع ملفات TypeScript إلى JavaScript ، هذا لا يرتبط بـ Angular. يحتاج الزاوي نفسه إلى تجميع قوالب HTML في جافا سكريبت وهذا يمكن أن يحدث في نقطتين مختلفتين من الوقت:

  • بعد تنزيل التطبيق الخاص بك في المتصفح (JiT)
تجميع JiT
  • مباشرة بعد التطوير ، في وقت البناء ، قبل تنزيل التطبيق الخاص بك في المتصفح (AoT)

ما هو webpack؟

حسب ويكيبيديا:

Webpack عبارة عن حزمة وحدة جافا سكريبت مفتوحة المصدر. الغرض الرئيسي منه هو تجميع ملفات JavaScript لاستخدامها في المستعرض ، ومع ذلك فهي أيضًا قادرة على تحويل أو تجميع أو تعبئة أي مورد أو مادة عرض. Webpack يأخذ الوحدات النمطية مع التبعيات ويولد أصول ثابتة تمثل تلك الوحدات. إنها حزمة مجمعة في المقام الأول لجافا سكريبت ، لكنها يمكن أن تحول الأصول الأمامية مثل HTML ، CSS ، وحتى الصور إذا تم تضمين الإضافات المقابلة.

لإخبار webpack بكيفية تجميع طلبنا ، علينا تكوين ما نسميه المفاهيم الأساسية:

الإدخال - تشير نقطة الإدخال إلى الحزمة التي يجب أن تستخدمها حزمة الويب للبدء في بناء رسم التبعية الداخلي الخاص بها. سوف يقوم Webpack باكتشاف الوحدات والمكتبات الأخرى التي تعتمد عليها نقطة الإدخال (بشكل مباشر وغير مباشر).

الإخراج - تخبر خاصية الإخراج webpack أين تنبعث منها الحزم التي تنشئها وكيفية تسمية هذه الملفات. من المفترض أن ./dist/main.js لملف الإخراج الرئيسي وإلى المجلد. / مجلد لأي ملف تم إنشاؤه.

اللوادر - على مستوى عالٍ ، يكون للوادر خاصيتان في تكوين حزمة الويب:

  • تحدد خاصية الاختبار الملفات أو الملفات التي يجب تحويلها.
  • تشير خاصية الاستخدام إلى المحمل الذي يجب استخدامه لإجراء التحويل.

الإضافات - أثناء استخدام اللوادر لتحويل أنواع معينة من الوحدات ، يمكن الاستفادة من الإضافات لتنفيذ مجموعة واسعة من المهام مثل تحسين الحزمة ، وإدارة الأصول ، وإدخال متغيرات البيئة.

كل هذه يجب إعدادها في ملف تكوين webpack webpack.config.js.

تكوين webpack

في مجلد src ، نحتاج إلى إنشاء ملفين إضافيين:

  • vendor.ts التي تستورد فقط وحدات الطرف الثالث للتطبيق.
  • polyfills.ts نحتاج إلى polyfills لتشغيل تطبيق Angular في معظم المتصفحات كما هو موضح في دليل دعم المتصفح. سيتم تحميل ملف الحزمة أولاً ، لذا يعد هذا مكانًا جيدًا لتهيئة بيئة المتصفح للإنتاج أو التطوير.

قم بإنشاء مجلد تكوين جديد والملفات التالية بداخله:

  • webpack.config.common.js: التكوين الذي سنستخدمه في التطوير والإنتاج.

الدخول - بالنسبة لهذا التطبيق (ولأغلبهم في الواقع) لدينا 3 نقاط دخول مختلفة: vendor.ts polyfills.ts و main.ts.

الإدخال: {
    البائع: './src/vendor.ts' ،
    polyfills: './src/polyfills.ts' ،
    الرئيسية: "./src/main.ts"
}

Loaders - نحن نقوم بتحميل ملفات. html باستخدام html-loader وهو أمر قياسي إلى حد كبير. يعتبر تحميل ملفات .scss أمرًا صعبًا بعض الشيء بالنسبة لتطبيق Angular وقد ناضلت لساعات عديدة لمعرفة كيفية القيام بذلك.

بادئ ذي بدء ، يجب علينا تحميل ملفات sass باستخدام محملين sass-loader و css-loader. إذا كنت تريد أن تجعل تصحيح الأخطاء أمرًا سهلاً ، خاصةً في وضع التطوير ، فمن المهم حقًا إضافة sourceMap: true كخيارات. في تطبيق Angular ، نضيف أنماطًا إلى المكون بتمرير مسار ملف إلى صفيف styleUrls كما يلي: بالنسبة لنا ويلقي الإخراج إلى سلسلة.

{
    اختبار: / \.html$/ ،
    اللودر: 'html-loader'
}،
{
    اختبار: / \ .(scss|sass)$/ ،
    استعمال: [
        "لسلسلة لوادر،
        {
            اللودر: 'css-loader' ،
            خيارات: {
                sourceMap: صحيح
            }
        }،
        {
            اللودر: 'sass-loader' ،
            خيارات: {
                sourceMap: صحيح
            }
        }
    ]،
    تشمل: helpers.root ('src' ، 'app')
}

الإضافات - CleanWebpackPlugin ستقوم بإزالة / تنظيف مجلد (مجلدات) الإنشاء قبل الإنشاء مرة أخرى. سيقوم المكون الإضافي HtmlWebpackPlugin بإنشاء ملف HTML5 لك يتضمن جميع حزم webpack الخاصة بك في النص باستخدام علامات البرامج النصية. يتطلب فقط الطريق إلى القالب.

CleanWebpackPlugin جديد (
    helpers.root ( 'حي')،
    {
        الجذر: helpers.root () ،
        مطول: صحيح
    }
)،
جديد HtmlWebpackPlugin ({
    القالب: 'src / index.html'
})
  • webpack.config.dev.js هو تكوين webpack الذي سنستخدمه لوضع التطوير فقط.
الوضع: "التنمية"

في webpack 4 ، يخبر الوضع المختار webpack باستخدام تحسيناته المدمجة وفقًا لذلك.

devtool: 'cheap-module-eval-source-map'

يتحكم هذا الخيار في كيفية إنشاء الخرائط المصدر. باستخدام الخريطة الرخيصة من وحدة ، eval-source-map ، تتم معالجة خرائط المصدر من اللوادر للحصول على نتائج أفضل. ومع ذلك ، يتم تبسيط خرائط Source loader إلى مناظرة واحدة لكل سطر.

انتاج: {
    المسار: helpers.root ('dist') ،
    publicPath: '/' ،
    اسم الملف: '[الاسم] .bundle.js' ،
    chunkFilename: '[id] .chunk.js'
}

يحتوي مفتاح الإخراج على مجموعة من الخيارات التي تُوجِّه حزمة الويب حول كيفية ومكان إخراج حزمك وأصولك وأي شيء آخر تقوم بجمعه أو تحميله مع حزمة الويب. نحن هنا نقول webpack لإخراج حزمنا إلى مجلد dist.

الاقوي: {
    noEmitOnErrors: صحيح
}

يتخطى مرحلة الانبعاث كلما حدثت أخطاء أثناء الترجمة. هذا يضمن عدم إرسال أي أصول خاطئة. يحتوي مفتاح التحسين على العديد من الخيارات الأخرى التي تم تعيينها افتراضيًا وفقًا لوضع تكوين حزمة الويب (التطوير / الإنتاج). يمكنك قراءة المزيد عنه هنا.

{
    اختبار: / \
    اللودرات: [
        "بابل لوادر،
        {
            اللودر: 'رهيبة - الطباع - اللودر' ،
            خيارات: {
                configFileName: helpers.root ('tsconfig.json')
            }
        }،
        "angular2 قالب لوادر،
        "الزاوي الموجه لوادر"
    ]،
    استبعاد: [/ node_modules /]
}

الزاوي-router-loader هو محمل حزمة الويب الذي يتيح تحميل الوحدة النمطية المستندة إلى السلسلة مع Angular Router.

angular2-template-loader هو سلسلة من اللودرات التي تحمل جميع أتش تي أم أل والأنماط في المكونات الزاوي.

awesome-typescript-loader هو حاليًا webpack TypeScript وهو أسرع. ويستخدم قرار التبعية لبناء وحدات الرسم البياني التبعية. هذا يسرع نسبيا عملية البناء.

بابل محمل يسمح بنقل ملفات جافا سكريبت.

devServer: {
    historyApiFallback: صحيح ،
    الإحصائيات: "الحد الأدنى"
}

عند استخدام HTML5 History API ، من المرجح أن يتم عرض صفحة index.html بدلاً من 404 استجابات. لذلك نحن بحاجة إلى تمكين historyApiFallback.

يتيح لك خيار stats التحكم بدقة في معلومات الحزمة التي يتم عرضها. قد يكون هذا أساسًا متوسطًا جيدًا إذا كنت تريد بعض معلومات الحزمة ، ولكن ليس كل ذلك.

إضافة البرامج النصية

أضف الأسطر التالية إلى ملف package.json الخاص بك:

"نصوص": {
  "build: dev": "webpack-dev-server - inline --hot --progress --port 8080"
}

--hot تمكين webpack Hot Module Replacement (HMR). يقوم بتبديل الوحدات النمطية أو إضافتها أو إزالتها أثناء تشغيل التطبيق ، دون إعادة تحميل كاملة. يمكن أن يسرع هذا التطور بشكل كبير بعدة طرق:

  • الاحتفاظ بحالة التطبيق المفقودة أثناء إعادة التحميل الكامل.
  • وفر وقت التطوير الثمين من خلال تحديث ما تم تغييره فقط.
  • تؤدي التعديلات التي تم إجراؤها على CSS / JS في التعليمات البرمجية المصدر إلى تحديث مستعرض فوري يمكن مقارنته تقريبًا بتغيير الأنماط مباشرة في أدوات تطوير المتصفح.

الآن أنت كل الإعداد! يمكنك تشغيل بناء تشغيل npm: افتح متصفحك وانتقل إلى المضيف المحلي: 8080.

تكوين Webpack لوضع الإنتاج (تجميع Ahead-of-Time)

مزايا تجميع AoT

  • باستخدام AoT ، يقوم المتصفح بتنزيل إصدار تم تجميعه مسبقًا من التطبيق. يقوم المتصفح بتحميل التعليمة البرمجية القابلة للتنفيذ حتى يتمكن من تقديم التطبيق على الفور ، دون انتظار ترجمة التطبيق أولاً.
  • يقوم المحول البرمجي بتضمين قوالب HTML الخارجية وأوراق أنماط CSS داخل تطبيق JavaScript ، مما يلغي طلبات AJAX المنفصلة لتلك الملفات المصدر.
  • ليست هناك حاجة لتنزيل برنامج التحويل البرمجي Angular إذا تم تجميع التطبيق بالفعل. المترجم هو ما يقرب من نصف Angular نفسها ، لذلك حذفه يقلل بشكل كبير من حمولة التطبيق.
  • يقوم برنامج التحويل البرمجي AoT بالكشف عن أخطاء ربط القالب وتقريرها أثناء خطوة الإنشاء قبل أن يتمكن المستخدمون من رؤيتها.
  • تقوم AoT بتجميع قوالب HTML ومكوناتها في ملفات JavaScript قبل وقت طويل من تقديمها للعميل. مع عدم وجود قوالب للقراءة ولا تقييم HTML أو JavaScript من جانب العميل المحفوف بالمخاطر ، هناك فرص أقل لهجمات الحقن.

تكوين webpack

في مجلد التكوين الخاص بك ، أنشئ ملفًا جديدًا webpack.config.prod.js

الوضع: "الإنتاج"

عادةً ما ننتقل إلى تجميع AoT في وضع الإنتاج ، وكما كتبت سابقًا ، في webpack 4 ، يخبر الوضع المختار webpack باستخدام تحسيناته المضمنة وفقًا لذلك.

انتاج: {
    المسار: helpers.root ('dist') ،
    publicPath: '/' ،
    اسم الملف: '[hash] .js' ،
    chunkFilename: '[id]. [hash] .chunk.js'
}

نحن نطلب أيضًا من webpack إخراج حزمنا إلى مجلد dist. نقوم بتضمين تجزئة لأسماء الملفات للاستفادة من ذاكرة التخزين المؤقت على مستوى العميل بكفاءة. بهذه الطريقة ، يعرف webpack ما إذا كان الملف قد تغير أم لا. Webpack يوفر العناصر النائبة لهذا الغرض. تُستخدم هذه السلاسل لإرفاق معلومات محددة بالمخرجات. الأكثر قيمة هي:

  • [id] تقوم بإرجاع معرف القطعة.
  • إرجاع [المسار] مسار الملف.
  • إرجاع [name] اسم الملف.
  • [تحويلة] إرجاع التمديد. [تحويلة] يعمل لمعظم الحقول المتاحة.
  • إرجاع [التجزئة] بناء التجزئة. إذا تغير أي جزء من البنية ، فإن هذا يتغير أيضًا.
  • إرجاع [chunkhash] تجزئة إدخال قطعة خاصة. يتلقى كل إدخال معرف في التكوين علامة تجزئة خاصة به. إذا تغير أي جزء من الإدخال ، فستتغير التجزئة أيضًا. [chunkhash] أكثر حبيبية من [هاش] بحكم التعريف.
  • يعرض [contenthash] علامة تجزئة تم إنشاؤها بناءً على المحتوى.

يُفضل استخدام تجزئة و chunkhash بشكل خاص فقط للإنتاج حيث أن التجزئة ليس ضروريًا أثناء التطوير.

الاقوي: {
    noEmitOnErrors: صحيح ،
    splitChunks: {
        قطع: "الكل"
    }،
    runtimeChunk: "واحد" ،
    مصغر: [
        جديد UglifyJsPlugin ({
            مخبأ: صحيح ،
            بالتوازي: صحيح
        })،
         OptimizeCSSAssetsPlugin الجديد ({
             cssProcessor: cssnano ،
             cssProcessorOptions: {
                 تجاهل:
                     removeAll: صحيح
                 }
             }،
             canPrint: خطأ
         })
    ]
}
  • كما هو الحال في وضع التطوير ، نريد تخطي مرحلة الانبعاث كلما حدثت أخطاء أثناء الترجمة. هذا يضمن عدم إرسال أي أصول خاطئة.
  • القطع: يشير "الكل" إلى القطع التي سيتم اختيارها للتحسين. يمكن أن يكون توفير كل شيء قويًا بشكل خاص ، لأنه يعني أنه يمكن مشاركة القطع حتى بين القطع غير المتزامنة وغير المتزامنة.
  • تتم تهيئة الوحدات النمطية المستوردة لكل قطعة وقت التشغيل بشكل منفصل. كما تقترح webpack ، أثناء العمل في مشروع يحتوي على نقاط إدخال متعددة ، لا ترغب في الحصول على مثيل واحد من وقت التشغيل. لذلك تحتاج إلى ضبطه على "مفرد".
  • يستخدم UglifyJsPlugin uglify-js لتقليل ملفات JavaScript الخاصة بك. لقد قمنا بتعيين ذاكرة التخزين المؤقت والخصائص المتوازية على true لتمكين تخزين الملفات المؤقت واستخدام التشغيل المتوازي متعدد العمليات لتحسين سرعة الإنشاء. هناك المزيد من الخيارات المتاحة وأدعوك لمعرفة المزيد حول هذا البرنامج المساعد.
  • سيبحث OptimizeCSSAssetsPlugin عن أصول CSS أثناء إنشاء حزمة الويب وسيعمل على تحسينها وتقليلها. معالج CSS المستخدم للتحسين هو cssnano. ستتم إزالة جميع التعليقات من CSS المصغّر ولن تتم طباعة أي رسائل على وحدة التحكم.
وحدة: {
    قواعد: [
        {
            اختبار: /(؟:\.ngfactory\.js|\.ngstyle\.js|\.ts)$/ ،
            لودر: '@ ngtools / webpack'
        }
    ]
}
الإضافات: [
    new ngw.AngularCompilerPlugin ({
        tsConfigPath: helpers.root ('tsconfig.aot.json') ،
        entryModule: helpers.root ('src' ، و 'app' ، و 'modules' ، و 'app' ، و 'app.module # AppModule')
    })
]

@ ngtools / webpack هو البرنامج المساعد الرسمي الذي يقوم AoT بتجميع المكونات والوحدات الزاوي الخاص بك. يعمل المُحمل مع البرنامج المساعد webpack لتجميع TypeScript الخاص بك. من المهم تضمين كليهما وعدم تضمين أي برنامج تحميل مترجم TypeScript آخر.

إضافة ملف main.aot.ts

في مجلد src ، أضف ملف main.aot.ts:

استيراد {enableProdMode} من '@ angular / core' ؛
استيراد {platformBrowser} من '@ angular / platform-browser' ؛
استيراد {AppModuleNgFactory} من './app/app.module.ngfactory' ؛
enableProdMode ()؛
. platformBrowser () bootstrapModuleFactory (AppModuleNgFactory)؛

يختلف الإدخال الرئيسي الخاص بك قليلاً في وضع الإنتاج وتجميع AoT:

  • قم باستيراد enableProdMode لتعطيل وضع تطوير Angular ، مما يؤدي إلى إيقاف تشغيل التأكيدات وغيرها من عمليات الفحص داخل الإطار.
  • قم باستيراد platformBrowser AND NOT platformBrowserDynamic لأنه في تجميع AoT ، يتم شحن التطبيق الخاص بك إلى المستعرض الذي تم تجميعه بالفعل بينما يحدث في JiT compilation على مستوى المستعرض.
  • بدلاً من استيراد AppModule ، تحتاج إلى استيراد AppModuleFactory وهو تطبيق مترجم تم إنشاؤه بواسطة برنامج التحويل البرمجي Angular الخاص بنا.

إضافة البرامج النصية

أضف البرامج النصية التالية إلى ملف package.json الخاص بك:

"webpack-prod": "cross-env NODE_ENV = production webpack - إنتاج وضع"
"build: prod": "build npm run: clean && ngc && npm run webpack-prod && npm run build: clean"
"build: clean": "del-cli 'src / ** / *. js' 'src / ** / *. js.map' 'src / ** / *. ngsummary.json' 'src / ** / * .metadata.json '' src / ** / ** / *. ngfactory.ts '' src / ** / *. ngstyle.ts 'src / ** / *. shim.ts' "
"خدمة": "خادم لايت"
  • build: clean: يقوم برنامج التحويل البرمجي Angular بإنشاء العديد من الملفات من أجل ترجمة التطبيق الخاص بك. لتبقى نظيفة في مشروعنا ، نحذف كل هذه الملفات قبل التجميع وبعد إنشاء حزم.
  • build: prod: قم بتشغيل برنامج التحويل البرمجي Angular باستخدام الأمر ngc ثم قم بتشغيل webpack في وضع الإنتاج لإنشاء حزمك.
  • تخدم: أنا استخدم خادم لايت لخدمة تطبيقنا ومعرفة ما يبدو عليه. بالطبع ، لن تحتاجه في مشروع حقيقي لأن تطبيقك سيتم تشغيله بواسطة السحابة.

الآن ، يمكنك تشغيل بناء npm run: prod لتجميع تطبيق Angular الخاص بك وإنشاء حزمك. ثم ، تشغيل npm run يخدم تطبيقك على المتصفح.

هيو جاكمان تتمتع هذه المادة

آمل أن يحظى هذا المقال بإعجابكم! إذا كان لديك أي أسئلة / اقتراحات ، فأخبرني في التعليقات أدناه.

ملفات المشروع موجودة على GitHub: