تطوير تطبيقات JavaScript بسيطة وحديثة باستخدام Webpack وتقنيات الويب المتقدمة

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

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

صورة

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

نظرة عامة


قبل أن نبدأ العمل ، دعونا نناقش الأدوات التي نحتاجها.

▍ تطبيق العمارة


من أجل ضمان سرعة عالية لتحميل التطبيق وسهولة الاستخدام ، سوف نستخدم أنماط التصميم التالية:

  • العمارة التطبيقات شل.
  • نمط PRPL (الدفع ، العرض ، التخزين المؤقت ، التحميل الكسول).

build نظام بناء المشروع


في مشروعنا ، نحتاج إلى نظام تجميع عالي الجودة مخصص لاحتياجاتنا. هنا سنستخدم Webpack لتقديم المتطلبات التالية لنظام بناء المشروع:

  • دعم ES6 وقدرات استيراد الموارد الحيوية.
  • دعم SASS و CSS.
  • تكوين منفصل من وسائط التنمية والعمل الحقيقي للتطبيق.
  • القدرة على تكوين عمال الخدمة تلقائيا.

JavaScript ميزات جافا سكريبت المتقدمة


سنستخدم مجموعة الحد الأدنى من ميزات JavaScript الحديثة التي تسمح لنا بتطوير ما نحتاج إليه. وهنا الميزات في السؤال:

  • وحدات.
  • طرق مختلفة لإنشاء كائنات (حرفية الكائن ، والطبقات).
  • استيراد ديناميكي للموارد.
  • وظائف السهم.
  • حرفية القالب.

الآن وقد أصبح لدينا فكرة عامة عما نحتاج إليه ، فنحن على استعداد للبدء في تطوير مشروعنا.

بنية التطبيق


ساهم ظهور تطبيق الويب التدريجي (PWA) في وصول حلول معمارية جديدة في تطوير الويب. سمح هذا لتطبيقات الويب بالتحميل والعرض بشكل أسرع. قد يؤدي الجمع بين بنية App Shell ونمط PRPL إلى أن يكون تطبيق الويب سريعًا وسريع الاستجابة ، على غرار التطبيق العادي.

▍ ما هو التطبيق شل و PRPL؟


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

يتم فك تشفير الاختصار PRPL على النحو التالي:

  • دفع - إرسال الموارد الهامة إلى العميل للمسار المصدر (على وجه الخصوص ، باستخدام HTTP / 2).
  • تقديم - عرض المسار الأصلي.
  • قبل التخزين المؤقت - التخزين المؤقت للطرق المتبقية أو الموارد مقدما.
  • تحميل كسول - أجزاء التحميل "كسول" من التطبيق كلما أصبحت ضرورية (على وجه الخصوص ، بناء على طلب المستخدم).

▍ تنفيذ التطبيق شل و PRPL في التعليمات البرمجية


تتم مشاركة أنماط التطبيق Shepp و PRPL. يتيح لك ذلك تنفيذ الأساليب المتقدمة لتطوير مشاريع الويب. إليك ما يبدو عليه نمط تطبيق Shell في التعليمات البرمجية:

<!DOCTYPE html> <html lang="en"> <head>    <meta charset="utf-8" />    <meta name="viewport" content="width=device-width, initial-scale=1.0" />    <meta http-equiv="X-UA-Compatible" content="ie=edge" />    <!-- Critical Styles -->    <!--   №1 -->    <style>        html {            box-sizing: border-box;        }        *,        *:after,        *:before {            box-sizing: inherit;        }        body {            margin: 0;            padding: 0;            font: 18px 'Oxygen', Helvetica;            background: #ececec;        }        header {            height: 60px;            background: #512DA8;            color: #fff;            display: flex;            align-items: center;            padding: 0 40px;            box-shadow: 1px 2px 6px 0px #777;        }        h1 {            margin: 0;        }        .banner {            text-decoration: none;            color: #fff;            cursor: pointer;        }        main {            display: flex;            justify-content: center;            height: calc(100vh - 140px);            padding: 20px 40px;            overflow-y: auto;        }        button {            background: #512DA8;            border: 2px solid #512DA8;            cursor: pointer;            box-shadow: 1px 1px 3px 0px #777;            color: #fff;            padding: 10px 15px;            border-radius: 20px;        }        .button {            display: flex;            justify-content: center;        }        button:hover {            box-shadow: none;        }        footer {            height: 40px;            background: #2d3850;            color: #fff;            display: flex;            align-items: center;            padding: 40px;        }    </style>    <!--   №1 -->    <title>Vanilla Todos PWA</title> </head> <body>    <body>        <!-- Main Application Section -->        <!--   №2 -->        <header>            <h3><font color="#3AC1EF"><a class="banner"> Vanilla Todos PWA </a></font></h3>        </header>        <main id="app"></main>        <footer>            <span>© 2019 Anurag Majumdar - Vanilla Todos SPA</span>        </footer>        <!--   №2 -->             <!-- Critical Scripts -->        <!--   №3 -->        <script async src="<%= htmlWebpackPlugin.files.chunks.main.entry %>"></script>        <!--   №3 -->        <noscript>            This site uses JavaScript. Please enable JavaScript in your browser.        </noscript>    </body> </body> </html> 

بعد دراسة هذا الرمز ، يمكنك أن تفهم أن قالب التطبيق Shell يوفر إنشاء "shell" لأحد التطبيقات ، وهو "هيكلها العظمي" الذي يحتوي على الحد الأدنى من العلامات. دعنا نحلل هذا الرمز (يشار إليه فيما يلي ، شظايا الكود التي سنشير إليها أثناء التحليل يتم تمييزها بتعليقات ، مثل <!-- №1 --> ).

  • الجزء رقم 1. يتم تضمين الأنماط الأكثر أهمية في الترميز ، ولا يتم تقديمها كملفات منفصلة. يتم ذلك بحيث تتم معالجة رمز CSS مباشرةً عند تحميل صفحة HTML.
  • الجزء رقم 2. هنا هو "قذيفة" من التطبيق. سيتم التحكم في هذه المناطق في وقت لاحق بواسطة كود JavaScript. ينطبق هذا بشكل خاص على ما سيكون في العلامة main مع app المعرف ( <main id="app"></main> ).
  • الجزء رقم 3. البرامج النصية تأتي هنا في اللعب. تسمح لك السمة async بعدم حظر المحلل اللغوي أثناء تحميل البرنامج النصي.

يقوم "الهيكل العظمي" أعلاه للتطبيق بتنفيذ خطوات Push and Render الخاصة بنمط PRPL. يحدث هذا عندما يوزع المستعرض رمز HTML لتكوين تمثيل مرئي للصفحة. في الوقت نفسه ، يعثر المستعرض بسرعة على الموارد المهمة لإخراج الصفحة. بالإضافة إلى ذلك ، يتم تقديم البرامج النصية هنا (الجزء رقم 3) ، المسؤولة عن عرض المسار الأصلي من خلال معالجة DOM (في خطوة Render).

ومع ذلك ، إذا لم نستخدم عامل الخدمة للتخزين المؤقت لـ "shell" للتطبيق ، فلن نحقق مكاسب في الأداء ، على سبيل المثال ، عند إعادة تحميل الصفحة.

يُظهر الرمز أدناه عامل خدمة يقوم بالتخزين المؤقت للهيكل العظمي وجميع الموارد الثابتة للتطبيق.

 var staticAssetsCacheName = 'todo-assets-v3'; var dynamicCacheName = 'todo-dynamic-v3'; //   №1 self.addEventListener('install', function (event) {   self.skipWaiting();   event.waitUntil(     caches.open(staticAssetsCacheName).then(function (cache) {       cache.addAll([           '/',           "chunks/todo.d41d8cd98f00b204e980.js","index.html","main.d41d8cd98f00b204e980.js"       ]       );     }).catch((error) => {       console.log('Error caching static assets:', error);     })   ); }); //   №1 //   №2 self.addEventListener('activate', function (event) {   if (self.clients && clients.claim) {     clients.claim();   }   event.waitUntil(     caches.keys().then(function (cacheNames) {       return Promise.all(         cacheNames.filter(function (cacheName) {           return (cacheName.startsWith('todo-')) && cacheName !== staticAssetsCacheName;         })         .map(function (cacheName) {           return caches.delete(cacheName);         })       ).catch((error) => {           console.log('Some error occurred while removing existing cache:', error);       });     }).catch((error) => {       console.log('Some error occurred while removing existing cache:', error);   })); }); //   №2 //   №3 self.addEventListener('fetch', (event) => {   event.respondWith(     caches.match(event.request).then((response) => {       return response || fetch(event.request)         .then((fetchResponse) => {             return cacheDynamicRequestData(dynamicCacheName, event.request.url, fetchResponse.clone());         }).catch((error) => {           console.log(error);         });     }).catch((error) => {       console.log(error);     })   ); }); //   №3 function cacheDynamicRequestData(dynamicCacheName, url, fetchResponse) {   return caches.open(dynamicCacheName)     .then((cache) => {       cache.put(url, fetchResponse.clone());       return fetchResponse;     }).catch((error) => {       console.log(error);     }); } 

دعنا نحلل هذا الرمز.

  • الجزء رقم 1. تساعد معالجة حدث install الخاص بعامل الخدمة في تخزين موارد ثابتة في ذاكرة التخزين المؤقت. هنا يمكنك تخزين موارد "الهيكل العظمي" للتطبيق (CSS ، JavaScript ، الصور ، إلخ) للمسار الأول (وفقًا لمحتوى "الهيكل العظمي"). بالإضافة إلى ذلك ، يمكنك تنزيل موارد التطبيق الأخرى ، مما يجعلها تعمل من دون اتصال بالإنترنت. يتوافق التخزين المؤقت للموارد ، بالإضافة إلى التخزين المؤقت للهيكل العظمي ، مع خطوة Pre-cache لنموذج PRPL.
  • الجزء رقم 2. تؤدي معالجة حدث activate ذاكرة التخزين المؤقت غير المستخدمة.
  • الجزء رقم 3. تحميل سطور التعليمات البرمجية هذه الموارد من ذاكرة التخزين المؤقت إذا كانت هناك. خلاف ذلك ، يتم إجراء طلبات الشبكة. بالإضافة إلى ذلك ، إذا تم تقديم طلب شبكة لاستلام مورد ، فهذا يعني أن هذا المورد لم يتم تخزينه مؤقتًا بعد. يتم وضع مثل هذا المورد في ذاكرة تخزين مؤقت منفصلة جديدة. يساعد هذا البرنامج النصي ذاكرة التخزين المؤقت بيانات التطبيق الديناميكي.

حتى الآن ، ناقشنا معظم الحلول المعمارية التي سيتم استخدامها في تطبيقنا. الشيء الوحيد الذي لم نتحدث عنه حتى الآن هو خطوة التحميل كسلان من نمط PRPL. سنعود إليه لاحقًا ، لكن الآن سنتعامل مع نظام تجميع المشروع.

نظام بناء المشروع


بنية جيدة بمفردها ، بدون نظام بناء مشروع لائق ، لا تكفي لإنشاء تطبيق جيد. هذا هو المكان الذي يأتي Webpack في متناول يدي. هناك أدوات أخرى لبناء المشاريع (المجمعين) ، على سبيل المثال - الطرود والتراكم. لكن ما سننفذه استنادًا إلى Webpack يمكن أن يتم أيضًا باستخدام وسائل أخرى.

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

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

ES دعم ES6 وقدرات استيراد الموارد الديناميكية


لتنفيذ هذه الميزات ، نحتاج إلى Babel ، وهي شركة نقل شائعة تسمح لك بتحويل الشفرة المكتوبة باستخدام ميزات ES6 إلى رمز يمكن تشغيله في بيئات ES5. من أجل جعل Babel يعمل مع Webpack ، يمكننا استخدام الحزم التالية:

  • @babel/core
  • @babel/plugin-syntax-dynamic-import
  • @babel/preset-env
  • babel-core
  • babel-loader
  • babel-preset-env

فيما يلي مثال لملف .babelrc للاستخدام مع Webpack:

 {   "presets": ["@babel/preset-env"],   "plugins": ["@babel/plugin-syntax-dynamic-import"] } 

عند تكوين Babel ، يتم استخدام سطر presets لهذا الملف لتكوين Babel لتجميع ES6 إلى ES5 ، وسطر plugins بحيث يمكن استخدام الاستيراد الحيوي في Webpack.

هكذا يتم استخدام Babel مع Webpack (هنا مقتطف من ملف إعدادات webpack.config.js - webpack.config.js ):

 module.exports = {   entry: {       //     },   output: {       //     },   module: {       rules: [           {               test: /\.js$/,               exclude: /node_modules/,               use: {                   loader: 'babel-loader'               }           }       ]   },   plugins: [       //    ] }; 

يصف قسم rules في هذا الملف كيفية استخدام babel-loader لتخصيص عملية النقل. تم حذف بقية هذا الملف من أجل الإيجاز.

ASSSASS و CSS الدعم


لتوفير الدعم لنظام التجميع لمشروع SASS و CSS الخاص بنا ، نحتاج إلى الإضافات التالية:

  • sass-loader
  • css-loader
  • style-loader
  • MiniCssExtractPlugin

إليك ما يبدو عليه ملف إعدادات Webpack والذي يتم فيه إدخال بيانات حول هذه المكونات الإضافية:

 module.exports = {   entry: {       //     },   output: {       //     },   module: {       rules: [           {               test: /\.js$/,               exclude: /node_modules/,               use: {                   loader: 'babel-loader'               }           },           {               test: /\.scss$/,               use: [                   'style-loader',                   MiniCssExtractPlugin.loader,                   'css-loader',                   'sass-loader'               ]           }       ]   },   plugins: [       new MiniCssExtractPlugin({           filename: '[name].css'       }),   ] }; 

يتم تسجيل اللوادر في قسم rules . بما أننا نستخدم المكوّن الإضافي لاستخراج أنماط CSS ، يتم إدخال الإدخال المقابل في قسم plugins .

setting إعداد منفصل من وسائط التنمية والعمل الحقيقي للتطبيق


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

  • clean-webpack-plugin : لتنظيف محتويات المجلد dist .
  • compression-webpack-plugin : لضغط محتويات المجلد dist .
  • copy-webpack-plugin : لنسخ الموارد الثابتة ، على سبيل المثال ، الملفات ، من المجلدات التي تحتوي على بيانات مصدر التطبيق إلى مجلد dist .
  • html-webpack-plugin : لإنشاء ملف index.html في المجلد dist .
  • webpack-md5-hash : webpack-md5-hash ملفات التطبيق في مجلد dist .
  • webpack-dev-server : لبدء تشغيل الخادم المحلي المستخدم أثناء التطوير.

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

 const path = require('path'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const WebpackMd5Hash = require('webpack-md5-hash'); const CleanWebpackPlugin = require('clean-webpack-plugin'); const CopyWebpackPlugin = require('copy-webpack-plugin'); const CompressionPlugin = require('compression-webpack-plugin'); module.exports = (env, argv) => ({   entry: {       main: './src/main.js'   },   devtool: argv.mode === 'production' ? false : 'source-map',   output: {       path: path.resolve(__dirname, 'dist'),       chunkFilename:           argv.mode === 'production'               ? 'chunks/[name].[chunkhash].js'               : 'chunks/[name].js',       filename:           argv.mode === 'production' ? '[name].[chunkhash].js' : '[name].js'   },   module: {       rules: [           {               test: /\.js$/,               exclude: /node_modules/,               use: {                   loader: 'babel-loader'               }           },           {               test: /\.scss$/,               use: [                   'style-loader',                   MiniCssExtractPlugin.loader,                   'css-loader',                   'sass-loader'               ]           }       ]   },   plugins: [       new CleanWebpackPlugin('dist', {}),       new MiniCssExtractPlugin({           filename:               argv.mode === 'production'                   ? '[name].[contenthash].css'                   : '[name].css'       }),       new HtmlWebpackPlugin({           inject: false,           hash: true,           template: './index.html',           filename: 'index.html'       }),       new WebpackMd5Hash(),       new CopyWebpackPlugin([           // {           // from: './src/assets',           // to: './assets'           // },           // {           // from: 'manifest.json',           // to: 'manifest.json'           // }       ]),       new CompressionPlugin({           algorithm: 'gzip'       })   ],   devServer: {       contentBase: 'dist',       watchContentBase: true,       port: 1000   } }); 

يتم تقديم تكوين Webpack بأكمله كدالة تتطلب وسيطين. يتم استخدام وسيطة argv هنا ، والتي تمثل الوسائط التي تم تمريرها إلى هذه الوظيفة عند تنفيذ webpack أو webpack-dev-server . إليك كيفية ظهور وصف هذه الأوامر في ملف مشروع package.json :

 "scripts": {   "build": "webpack --mode production && node build-sw",   "serve": "webpack-dev-server --mode=development --hot", }, 

نتيجة لذلك ، إذا قمنا بتنفيذ الأمر npm run build ، npm run build نسخة الإنتاج من التطبيق. إذا قمت بتشغيل الأمر npm run serve ، npm run serve خادم التطوير ، ويدعم العمل في التطبيق.

devServer plugins و devServer الملف أعلاه كيفية تكوين المكونات الإضافية وخادم التطوير.

في القسم الذي يبدأ new CopyWebpackPlugin ، يمكنك تحديد الموارد التي تريد نسخها من مواد مصدر التطبيق.

a إعداد عامل خدمة


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

 const glob = require('glob'); const fs = require('fs'); const dest = 'dist/sw.js'; const staticAssetsCacheName = 'todo-assets-v1'; const dynamicCacheName = 'todo-dynamic-v1'; //   №1 let staticAssetsCacheFiles = glob   .sync('dist/**/*')   .map((path) => {       return path.slice(5);   })   .filter((file) => {       if (/\.gz$/.test(file)) return false;       if (/sw\.js$/.test(file)) return false;       if (!/\.+/.test(file)) return false;       return true;   }); //   №1 const stringFileCachesArray = JSON.stringify(staticAssetsCacheFiles); //   №2 const serviceWorkerScript = `var staticAssetsCacheName = '${staticAssetsCacheName}'; var dynamicCacheName = '${dynamicCacheName}'; self.addEventListener('install', function (event) {   self.skipWaiting();   event.waitUntil(     caches.open(staticAssetsCacheName).then(function (cache) {       cache.addAll([           '/',           ${stringFileCachesArray.slice(1, stringFileCachesArray.length - 1)}       ]       );     }).catch((error) => {       console.log('Error caching static assets:', error);     })   ); }); self.addEventListener('activate', function (event) {   if (self.clients && clients.claim) {     clients.claim();   }   event.waitUntil(     caches.keys().then(function (cacheNames) {       return Promise.all(         cacheNames.filter(function (cacheName) {           return (cacheName.startsWith('todo-')) && cacheName !== staticAssetsCacheName;         })         .map(function (cacheName) {           return caches.delete(cacheName);         })       ).catch((error) => {           console.log('Some error occurred while removing existing cache:', error);       });     }).catch((error) => {       console.log('Some error occurred while removing existing cache:', error);   })); }); self.addEventListener('fetch', (event) => {   event.respondWith(     caches.match(event.request).then((response) => {       return response || fetch(event.request)         .then((fetchResponse) => {             return cacheDynamicRequestData(dynamicCacheName, event.request.url, fetchResponse.clone());         }).catch((error) => {           console.log(error);         });     }).catch((error) => {       console.log(error);     })   ); }); function cacheDynamicRequestData(dynamicCacheName, url, fetchResponse) {   return caches.open(dynamicCacheName)     .then((cache) => {       cache.put(url, fetchResponse.clone());       return fetchResponse;     }).catch((error) => {       console.log(error);     }); } `; //   №2 //   №3 fs.writeFile(dest, serviceWorkerScript, function(error) {   if (error) return;   console.log('Service Worker Write success'); }); //   №3 

دعنا نحلل هذا الرمز.

  • الجزء رقم 1. هنا يتم وضع قائمة الملفات من المجلد dist في صفيف staticAssetsCacheFiles .
  • الجزء رقم 2. هذا هو قالب عامل الخدمة الذي تحدثنا عنه. عند إنشاء الكود النهائي ، يتم استخدام المتغيرات. هذا يجعل القالب عالميًا ، مما يسمح لك باستخدامه في المستقبل أثناء تطوير المشروع. نحتاج أيضًا إلى قالب لأننا نضيف معلومات حول محتويات مجلد dist إليه ، والتي قد تتغير بمرور الوقت. لهذا ، stringFileCachesArray ثابت.
  • الجزء رقم 3. هنا ، تتم كتابة رمز عامل الخدمة الذي تم إنشاؤه حديثًا والمخزن في ثابت dist/sw.js إلى الملف الموجود في dist/sw.js

لتشغيل هذا البرنامج النصي ، استخدم الأمر node build-sw . يجب تنفيذها بعد webpack --mode production الأمر webpack --mode production الأمر.

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

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

▍ نظرة عامة على الحزم المستخدمة في المشروع


فيما يلي ملف package.json الخاص package.json ، حيث يمكنك العثور على معلومات حول الحزم المستخدمة في هذا المشروع:

 { "name": "vanilla-todos-pwa", "version": "1.0.0", "description": "A simple todo application using ES6 and Webpack", "main": "src/main.js", "scripts": {   "build": "webpack --mode production && node build-sw",   "serve": "webpack-dev-server --mode=development --hot" }, "keywords": [], "author": "Anurag Majumdar", "license": "MIT", "devDependencies": {   "@babel/core": "^7.2.2",   "@babel/plugin-syntax-dynamic-import": "^7.2.0",   "@babel/preset-env": "^7.2.3",   "autoprefixer": "^9.4.5",   "babel-core": "^6.26.3",   "babel-loader": "^8.0.4",   "babel-preset-env": "^1.7.0",   "clean-webpack-plugin": "^1.0.0",   "compression-webpack-plugin": "^2.0.0",   "copy-webpack-plugin": "^4.6.0",   "css-loader": "^2.1.0",   "html-webpack-plugin": "^3.2.0",   "mini-css-extract-plugin": "^0.5.0",   "node-sass": "^4.11.0",   "sass-loader": "^7.1.0",   "style-loader": "^0.23.1",   "terser": "^3.14.1",   "webpack": "^4.28.4",   "webpack-cli": "^3.2.1",   "webpack-dev-server": "^3.1.14",   "webpack-md5-hash": "0.0.6" } } 

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

ميزات جافا سكريبت الحديثة


أثناء تطوير تطبيق ويب ، يكون للمبرمج خيار - سواء لكتابة تطبيقاته الخاصة لمزايا مثل اكتشاف التغيير أو التوجيه أو تخزين البيانات أو استخدام الحزم الموجودة.

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

. وحدات


سنستخدم قدرات ES6 لاستيراد وتصدير الوحدات ، مع الأخذ بعين الاعتبار كل ملف كوحدة نمطية ES6. غالبًا ما توجد هذه الميزة في الأطر الشائعة مثل Angular و React ، وهي ملائمة جدًا لاستخدامها. بفضل تكوين Webpack لدينا ، يمكننا استخدام التعبير عن موارد الاستيراد والتصدير. إليك ما يبدو في ملف app.js :

 import { appTemplate } from './app.template'; import { AppModel } from './app.model'; export const AppComponent = { //   App... }; 

ar طرق مختلفة لإنشاء الكائنات


يعد إنشاء المكونات جزءًا مهمًا من عملية تطوير التطبيق لدينا. من الممكن تمامًا استخدام بعض الأدوات الحديثة ، مثل مكونات الويب ، ولكن من أجل عدم تعقيد المشروع ، سنستخدم كائنات JavaScript العادية ، والتي يمكن إنشاؤها إما باستخدام حرفية الكائن أو باستخدام بناء جملة الفصل الذي ظهر في معيار ES6 .

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

 import { appTemplate } from './app.template'; import { AppModel } from './app.model'; export const AppComponent = {   init() {       this.appElement = document.querySelector('#app');       this.initEvents();       this.render();   },   initEvents() {       this.appElement.addEventListener('click', event => {           if (event.target.className === 'btn-todo') {               import( /* webpackChunkName: "todo" */ './todo/todo.module')                   .then(lazyModule => {                       lazyModule.TodoModule.init();                   })                   .catch(error => 'An error occurred while loading Module');           }       });       document.querySelector('.banner').addEventListener('click', event => {           event.preventDefault();           this.render();       });   },   render() {       this.appElement.innerHTML = appTemplate(AppModel);   } }; 

هنا نقوم بتكوين وتصدير مكون AppComponent ، والذي يمكنك استخدامه على الفور في أجزاء أخرى من التطبيق.

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

yn استيراد ديناميكي للموارد


تذكر أنه ، عند الحديث عن نمط PRPL ، فإننا لم نفهم بعد الجزء الذي يمثله الحرف L (تحميل كسول)؟ الاستيراد الديناميكي للموارد هو ما يساعدنا في تنظيم التحميل البطيء للمكونات أو الوحدات النمطية. نظرًا لأننا نستخدم بنية التطبيق Shell ونمط PRPL للتخزين المؤقت لـ "الهيكل العظمي" للتطبيق وموارده ، أثناء الاستيراد الديناميكي ، يتم تنزيل الموارد من ذاكرة التخزين المؤقت وليس من الشبكة.

يرجى ملاحظة أنه إذا استخدمنا بنية التطبيق Shell فقط ، فلن يتم تخزين موارد التطبيق المتبقية ، أي محتويات مجلد chunks .

يمكن رؤية مثال لاستيراد المورد الديناميكي في جزء التعليمات البرمجية أعلاه لمكون AppComponent ، على وجه الخصوص ، حيث تم تكوين حدث النقر للزر (نحن نتحدث عن طريقة كائن initEvents() ). وهي ، إذا نقر مستخدم التطبيق على زر btn-todo ، فسيتم تحميل وحدة btn-todo . هذه الوحدة هي ملف JavaScript عادي يحتوي على مجموعة من المكونات الممثلة ككائنات.

functions وظائف السهم والقوالب الحرفية


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

 export const appTemplate = model => `   <section class="app">       <h3><font color="#3AC1EF">▍ ${model.title} </font></h3>       <section class="button">           <button class="btn-todo"> Todo Module </button>       </section>   </section> `; 

تأخذ دالة دالة appTemplate نموذجًا (معلمة model ) وتقوم بإرجاع سلسلة HTML تحتوي على بيانات مأخوذة من النموذج. . , - .

, , . reduce() HTML-:

 const WorkModel = [   {       id: 1,       src: '',       alt: '',       designation: '',       period: '',       description: ''   },   {       id: 2,       src: '',       alt: '',       designation: '',       period: '',       description: ''   },   //... ]; const workCardTemplate = (cardModel) => ` <section id="${cardModel.id}" class="work-card">   <section class="work__image">       <img class="work__image-content" type="image/svg+xml" src="${           cardModel.src       }" alt="${cardModel.alt}" />   </section>   <section class="work__designation">${cardModel.designation}</section>   <section class="work__period">${cardModel.period}</section>   <section class="work__content">       <section class="work__content-text">           ${cardModel.description}       </section>   </section> </section> `; export const workTemplate = (model) => ` <section class="work__section">   <section class="work-text">       <header class="header-text">           <span class="work-text__header"> Work </span>       </header>       <section class="work-text__content content-text">           <p class="work-text__content-para">               This area signifies work experience           </p>       </section>   </section>   <section class="work-cards">       ${model.reduce((html, card) => html + workCardTemplate(card), '')}   </section> </section> `; 

, . . , , .

:

  • model . — , reduce() , .
  • model.reduce , HTML-, , . , , , — .

. , , — .


Todo-, . .




. . , , , .

-


-, , -, . , , . , JavaScript -, .

, .


-

. Lighthouse.




النتائج


, , JavaScript, . , , , .

أعزائي القراء! -, ?

Source: https://habr.com/ru/post/ar444342/


All Articles