Mengembangkan aplikasi JavaScript sederhana dan modern menggunakan Webpack dan teknologi web canggih

Pernahkah Anda berpikir tentang menggunakan set teknologi paling sederhana yang ada saat mengembangkan proyek web Anda berikutnya? Jika demikian, maka materi, terjemahan yang kami terbitkan hari ini, ditulis khusus untuk Anda.

Kerangka kerja JavaScript ada untuk membantu kami membangun aplikasi dengan kemampuan serupa menggunakan pendekatan generik. Namun, banyak aplikasi tidak membutuhkan semua kekuatan yang disediakan kerangka kerja. Menggunakan kerangka kerja dalam proyek kecil atau menengah, yang memiliki persyaratan spesifik tertentu, mungkin merupakan pemborosan waktu dan energi yang tidak perlu.

gambar

Pada artikel ini, kita akan berbicara tentang penggunaan teknologi modern dalam pengembangan aplikasi web yang kapabilitasnya tidak dibatasi oleh kapabilitas kerangka kerja. Omong-omong, jika Anda membutuhkannya, maka Anda, menggunakan teknologi yang dijelaskan di sini, dapat membuat kerangka kerja Anda yang sangat terspesialisasi. JavaScript murni dan teknologi web dasar lainnya memberi pengembang kemampuan untuk melakukan apa yang mereka butuhkan tanpa membatasi diri pada ruang lingkup alat yang mereka gunakan.

Ulasan


Sebelum kita memulai bisnis, mari kita bahas alat yang kita butuhkan.

▍ Arsitektur Aplikasi


Untuk memastikan kecepatan pemuatan aplikasi dan kegunaan yang tinggi, kami akan menggunakan pola desain berikut:

  • Arsitektur Aplikasi Shell.
  • Pola PRPL (Push, Render, Pre-cache, memuat Malas).

▍ Sistem pembangunan proyek


Dalam proyek kami, kami membutuhkan sistem perakitan berkualitas tinggi yang disesuaikan dengan kebutuhan kami. Di sini kita akan menggunakan Webpack, menyajikan persyaratan berikut untuk sistem membangun proyek:

  • Dukungan untuk ES6 dan kemampuan impor sumber daya dinamis.
  • Dukungan untuk SASS dan CSS.
  • Konfigurasi mode pengembangan yang terpisah dan karya nyata aplikasi.
  • Kemampuan untuk mengkonfigurasi pekerja layanan secara otomatis.

▍ Fitur JavaScript Canggih


Kami akan menggunakan set minimum fitur JavaScript modern yang memungkinkan kami untuk mengembangkan apa yang kami butuhkan. Berikut adalah fitur yang dimaksud:

  • Modul
  • Berbagai cara untuk membuat objek (objek literal, kelas).
  • Impor sumber daya yang dinamis.
  • Fungsi panah.
  • Templat literal.

Sekarang kami memiliki gagasan umum tentang apa yang kami butuhkan, kami siap untuk mulai mengembangkan proyek kami.

Arsitektur aplikasi


Munculnya Aplikasi Web Progresif (PWA) telah berkontribusi pada kedatangan solusi arsitektur baru dalam pengembangan web. Ini memungkinkan aplikasi web memuat dan menampilkan lebih cepat. Kombinasi arsitektur App Shell dan pola PRPL dapat menyebabkan aplikasi web menjadi cepat dan responsif, mirip dengan aplikasi biasa.

▍ Apa itu App Shell dan PRPL?


App Shell adalah pola arsitektur yang digunakan untuk mengembangkan PWA, bila digunakan, jumlah minimum sumber daya kritis untuk operasi situs dikirim ke browser pengguna saat situs dimuat. Komposisi bahan-bahan ini biasanya mencakup semua sumber daya yang diperlukan untuk tampilan pertama aplikasi. Sumber daya semacam itu juga dapat di-cache menggunakan pekerja layanan.

Singkatan PRPL diuraikan sebagai berikut:

  • Push - mengirim sumber daya penting ke klien untuk rute sumber (khususnya, menggunakan HTTP / 2).
  • Render - menampilkan rute asli.
  • Pra-cache - cache dari rute atau sumber daya yang tersisa sebelumnya.
  • Lazy load - "lazy" memuat bagian-bagian aplikasi yang diperlukan (khususnya, atas permintaan pengguna).

▍ Implementasi App Shell dan PRPL dalam kode


Pola App Shepp dan PRPL dibagikan. Ini memungkinkan Anda untuk menerapkan pendekatan lanjutan dalam pengembangan proyek web. Begini pola aplikasi Shell dalam kode:

<!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> 

Setelah mempelajari kode ini, Anda dapat memahami bahwa template App Shell menyediakan untuk pembuatan "shell" aplikasi, yang merupakan "kerangka" yang berisi minimal markup. Mari kita analisis kode ini (selanjutnya, fragmen kode yang akan kita rujuk selama analisis ditandai dengan komentar, seperti <!-- β„–1 --> ).

  • Fragmen No. 1. Gaya paling penting dibangun ke dalam markup, dan tidak disajikan sebagai file terpisah. Ini dilakukan agar kode CSS akan diproses langsung saat memuat halaman HTML.
  • Fragmen No. 2. Ini adalah "shell" dari aplikasi tersebut. Area-area ini nantinya akan dikendalikan oleh kode JavaScript. Ini terutama berlaku untuk apa yang akan ada di tag main dengan app pengenal ( <main id="app"></main> ).
  • Fragmen No. 3. Di sini skrip ikut bermain. Atribut async memungkinkan Anda untuk tidak memblokir parser selama pemuatan skrip.

"Kerangka" aplikasi di atas mengimplementasikan langkah-langkah Push dan Render dari pola PRPL. Ini terjadi ketika browser mem-parsing kode HTML untuk membentuk representasi visual dari halaman. Pada saat yang sama, browser dengan cepat menemukan sumber daya yang penting untuk output halaman. Selain itu, skrip disajikan di sini (fragmen No. 3), yang bertanggung jawab untuk menampilkan rute asli dengan memanipulasi DOM (pada langkah Render).

Namun, jika kami tidak menggunakan pekerja layanan untuk menembolok "shell" dari aplikasi, maka kami tidak akan mendapatkan peningkatan kinerja, misalnya, saat memuat ulang halaman.

Kode di bawah ini menunjukkan pekerja layanan caching kerangka dan semua sumber daya statis aplikasi.

 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);     }); } 

Mari kita menganalisis kode ini.

  • Fragmen No. 1. Menangani acara install pekerja layanan membantu cache sumber daya statis. Di sini Anda dapat menyimpan sumber daya "kerangka" aplikasi (CSS, JavaScript, gambar, dan sebagainya) untuk rute pertama (sesuai dengan konten "kerangka"). Selain itu, Anda dapat mengunduh sumber daya aplikasi lain, membuatnya dapat berfungsi tanpa koneksi Internet. Caching sumber daya, selain caching kerangka, sesuai dengan langkah Pra-cache dari pola PRPL.
  • Fragmen No. 2. Memproses acara activate cache yang tidak digunakan.
  • Fragmen No. 3. Baris sumber kode ini memuat dari cache jika ada di sana. Jika tidak, permintaan jaringan dibuat. Selain itu, jika permintaan jaringan dibuat untuk menerima sumber daya, ini berarti bahwa sumber daya ini belum di-cache. Sumber daya semacam itu ditempatkan dalam cache terpisah yang baru. Script ini membantu cache data aplikasi dinamis.

Sampai saat ini, kami telah membahas sebagian besar solusi arsitektur yang akan digunakan dalam aplikasi kami. Satu-satunya hal yang belum kita bicarakan adalah langkah memuat Malas dari pola PRPL. Kami akan kembali lagi nanti, tetapi untuk saat ini kami akan berurusan dengan sistem perakitan proyek.

Sistem pembangunan proyek


Arsitektur yang baik saja, tanpa sistem pembangunan proyek yang layak, tidak cukup untuk membuat aplikasi yang berkualitas. Di sinilah Webpack sangat berguna. Ada alat lain untuk membangun proyek (bundler), misalnya - Parcel dan Rollup. Tetapi apa yang akan kami terapkan berdasarkan Webpack juga bisa dilakukan dengan menggunakan cara lain.

Di sini kita berbicara tentang bagaimana fitur yang kami minati terkait dengan plugin untuk Webpack. Ini akan memungkinkan Anda untuk dengan cepat memahami esensi sistem build kami. Pemilihan plug-in untuk bundler dan konfigurasi yang tepat adalah langkah paling penting menuju sistem pembangunan proyek berkualitas tinggi. Setelah menguasai prinsip-prinsip ini, Anda akan dapat menggunakannya di masa depan saat mengerjakan aplikasi Anda sendiri.

Tidak mudah untuk menyempurnakan alat seperti Webpack dari awal. Dalam kasus seperti itu, sangat membantu untuk mendapatkan bantuan yang baik. Panduan ini, dengan mana bagian yang sesuai dari bahan ini ditulis, adalah artikel ini . Jika Anda memiliki masalah dengan Webpack - hubungi dia. Sekarang mari kita ingat dan terapkan persyaratan untuk sistem perakitan proyek yang telah kita bicarakan sejak awal.

▍Mendukung ES6 dan kemampuan impor sumber daya dinamis


Untuk mengimplementasikan fitur-fitur ini, kami membutuhkan Babel, transporter populer yang memungkinkan Anda untuk mengubah kode yang ditulis menggunakan fitur ES6 menjadi kode yang dapat dijalankan di lingkungan ES5. Untuk membuat Babel bekerja dengan Webpack, kita dapat menggunakan paket-paket berikut:

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

Berikut ini contoh file .babelrc untuk digunakan dengan Webpack:

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

Saat mengkonfigurasi Babel, baris presets dari file ini digunakan untuk mengkonfigurasi Babel untuk mengkompilasi ES6 ke ES5, dan baris plugins sehingga impor dinamis dapat digunakan di Webpack.

Ini adalah bagaimana Babel digunakan dengan Webpack (di sini adalah potongan dari file pengaturan Webpack - webpack.config.js ):

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

Bagian rules file ini menjelaskan cara menggunakan babel-loader untuk menyesuaikan proses transpilation. Sisa dari file ini dihilangkan demi singkatnya.

▍SASS dan dukungan CSS


Untuk memberikan dukungan untuk sistem perakitan proyek SASS dan CSS kami, kami membutuhkan plugin berikut:

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

Berikut tampilan file pengaturan Webpack di mana data tentang plugin ini dimasukkan:

 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'       }),   ] }; 

Loader terdaftar di bagian rules . Karena kami menggunakan plugin untuk mengekstrak gaya CSS, entri yang sesuai dimasukkan di bagian plugins .

▍ Pengaturan terpisah mode pengembangan dan kerja nyata aplikasi


Ini adalah bagian yang sangat penting dari proses pembuatan aplikasi. Semua orang tahu bahwa ketika membuat aplikasi, beberapa pengaturan digunakan untuk membangun versi yang digunakan selama pengembangan, sementara yang lain digunakan untuk versi produksinya. Berikut adalah daftar paket yang berguna di sini:

  • clean-webpack-plugin : untuk membersihkan isi folder dist .
  • compression-webpack-plugin : untuk mengompresi isi folder dist .
  • copy-webpack-plugin : untuk menyalin sumber daya statis, misalnya, file, dari folder dengan data sumber aplikasi ke folder dist .
  • html-webpack-plugin : untuk membuat file index.html di folder dist .
  • webpack-md5-hash : untuk hashing file aplikasi dalam folder dist .
  • webpack-dev-server : untuk memulai server lokal yang digunakan selama pengembangan.

Beginilah webpack.config.js file webpack.config.js dihasilkan:

 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   } }); 

Seluruh konfigurasi Webpack disajikan sebagai fungsi yang mengambil dua argumen. Argumen argv digunakan di sini, yang mewakili argumen yang diteruskan ke fungsi ini ketika perintah webpack atau webpack-dev-server webpack . Berikut ini uraian perintah-perintah ini dalam file proyek package.json :

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

Akibatnya, jika kita menjalankan perintah npm run build , versi produksi aplikasi akan dibuat. Jika Anda menjalankan perintah npm run serve , server pengembangan akan mulai, mendukung proses pengerjaan aplikasi.

Bagian plugins dan devServer file di atas menunjukkan cara mengkonfigurasi plugins dan server pengembangan.

Di bagian yang dimulai dengan new CopyWebpackPlugin , Anda menentukan sumber daya yang ingin Anda salin dari bahan sumber aplikasi.

Etting Mengatur pekerja layanan


Kita semua tahu bahwa kompilasi daftar file secara manual, misalnya, yang dimaksudkan untuk caching, adalah tugas yang agak membosankan. Oleh karena itu, di sini kita akan menggunakan skrip perakitan pekerja layanan khusus yang menemukan file dalam folder dist dan menambahkannya sebagai konten cache dalam templat pekerja layanan. Setelah itu, file pekerja layanan akan ditulis ke folder dist . Konsep-konsep yang kita bicarakan ketika melamar pekerja layanan tidak berubah. Berikut ini adalah kode skrip 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 

Mari kita menganalisis kode ini.

  • Fragmen No. 1. Di sini daftar file dari folder dist ditempatkan di array staticAssetsCacheFiles .
  • Fragmen No. 2. Ini adalah templat pekerja layanan yang kita bicarakan. Saat membuat kode selesai, variabel digunakan. Ini membuat templat menjadi universal, memungkinkan Anda untuk menggunakannya di masa mendatang, selama pengembangan proyek. Kami juga memerlukan templat karena kami menambahkan informasi tentang isi folder dist ke dalamnya, yang dapat berubah seiring waktu. Untuk ini, stringFileCachesArray konstan stringFileCachesArray .
  • Fragmen No. 3. Di sini, kode pekerja layanan yang baru dibuat disimpan dalam konstanta serviceWorkerScript ditulis ke file yang terletak di dist/sw.js

Untuk menjalankan skrip ini, gunakan perintah node build-sw . Itu perlu dieksekusi setelah perintah webpack --mode production .

Script untuk membangun pekerja layanan yang disajikan di sini sangat menyederhanakan tugas mengatur file caching. Perlu dicatat bahwa skrip ini telah menemukan aplikasi dalam proyek nyata.

Jika Anda ingin menggunakan perpustakaan khusus yang dirancang untuk memecahkan masalah bekerja aplikasi web progresif offline, lihat Workbox . Ini memiliki fitur yang dapat disesuaikan sangat menarik.

▍ Gambaran umum paket yang digunakan dalam proyek


Ini adalah file package.json dari proyek kami, di mana Anda dapat menemukan informasi tentang paket-paket yang digunakan dalam proyek ini:

 { "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" } } 

Jika kita berbicara tentang dukungan proyek-proyek seperti itu, perlu dicatat bahwa alat dalam ekosistem Webpack sering diperbarui. Sering terjadi bahwa plugin yang ada diganti dengan yang baru. Oleh karena itu, penting, ketika memutuskan apakah akan menggunakan yang baru dan bukan beberapa paket, untuk fokus bukan pada paket itu sendiri, tetapi pada fitur yang harus mereka terapkan. Sebenarnya, itulah sebabnya kami berbicara di atas tentang peran yang dimainkan paket ini atau itu.

JavaScript fitur modern


Selama pengembangan aplikasi web, programmer memiliki pilihan - apakah akan menulis implementasi sendiri dari fitur-fitur seperti deteksi perubahan, perutean, penyimpanan data, atau menggunakan paket yang ada.

Sekarang kita akan berbicara tentang set minimum teknologi yang diperlukan untuk memastikan operasi proyek kami. Jika perlu, rangkaian teknologi ini dapat diperluas menggunakan kerangka kerja atau paket yang ada.

▍ Modul


Kami akan menggunakan kemampuan ES6 untuk mengimpor dan mengekspor modul, mengingat setiap file sebagai modul ES6. Fitur ini sering ditemukan dalam kerangka kerja populer seperti Angular dan React, sangat nyaman untuk menggunakannya. Berkat konfigurasi Webpack yang kami miliki, kami dapat menggunakan ekspresi sumber daya impor dan ekspor. Berikut tampilannya di file app.js :

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

▍Berbagai cara untuk membuat objek


Pembuatan komponen adalah bagian penting dari proses pengembangan aplikasi kami. Di sini sangat mungkin untuk menggunakan beberapa alat modern, seperti komponen web, tetapi agar tidak menyulitkan proyek, kami akan menggunakan objek JavaScript biasa, yang dapat dibuat baik menggunakan objek literal atau menggunakan sintaks kelas yang muncul dalam standar ES6 .

Keunikan menggunakan kelas untuk membuat objek adalah bahwa setelah deskripsi kelas, Anda perlu membuat instance objek berdasarkan, dan kemudian mengekspor objek ini. Untuk menyederhanakan banyak hal bahkan lebih kuat, kita akan menggunakan di sini objek biasa yang dibuat menggunakan objek literal. Berikut adalah kode untuk file app.js mana Anda dapat melihat aplikasi mereka.

 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);   } }; 

Di sini kita membentuk dan mengekspor komponen AppComponent , yang dapat langsung Anda gunakan di bagian lain aplikasi.

Anda bisa menggunakan kelas ES6 atau komponen web dengan sangat baik dalam situasi seperti itu, mengembangkan proyek dengan gaya yang lebih dekat dengan deklaratif daripada yang digunakan di sini. Di sini, agar tidak menyulitkan proyek pelatihan, pendekatan imperatif digunakan.

Import Impor sumber daya dinamis


Ingat bahwa, berbicara tentang pola PRPL, kita belum menemukan bagian yang diwakili oleh huruf L (pemuatan Malas)? Impor sumber daya yang dinamis adalah hal yang membantu kami mengatur pemuatan komponen atau modul yang malas. Karena kami menggunakan arsitektur App Shell dan pola PRPL untuk menyimpan "kerangka" aplikasi dan sumber dayanya, proses impor dinamis memuat sumber daya dari cache, bukan dari jaringan.

Harap perhatikan bahwa jika kami hanya menggunakan arsitektur App Shell, maka sumber daya aplikasi yang tersisa, yaitu isi folder chunks , tidak akan di-cache.

Contoh impor sumber daya dinamis dapat dilihat pada fragmen kode di atas komponen AppComponent , khususnya, di mana peristiwa klik tombol dikonfigurasikan (kita berbicara tentang metode objek initEvents() ). Yaitu, jika pengguna aplikasi mengklik tombol btn-todo , modul btn-todo akan dimuat. Modul ini adalah file JavaScript biasa yang berisi sekumpulan komponen yang direpresentasikan sebagai objek.

▍ Fungsi panah dan templat literal


Fungsi panah sangat berguna ketika Anda membutuhkan this dalam fungsi tersebut untuk menunjukkan konteks di mana fungsi tersebut dinyatakan. Selain itu, fungsi panah memungkinkan Anda menulis kode yang lebih ringkas daripada menggunakan fungsi konvensional. Berikut ini contoh fungsi tersebut:

 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> `; 

Fungsi appTemplate mengambil model (parameter model ) dan mengembalikan string HTML yang berisi data yang diambil dari model. . , - .

, , . 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.




Ringkasan


, , JavaScript, . , , , .

Pembaca yang budiman! -, ?

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


All Articles