Penulis materi, terjemahan yang kami terbitkan hari ini, seorang pengembang web, mengatakan bahwa ia sedang mencoba untuk secara teratur meninjau set alat yang ia gunakan. Dia melakukan ini untuk memahami apakah dia dapat melakukannya tanpa beberapa dari mereka dengan menyelesaikan tugas-tugasnya yang biasa. Dia baru-baru ini memutuskan untuk melakukan percobaan dan membuat aplikasi front-end yang canggih tanpa menggunakan kerangka JavaScript.
Apa itu framework?
Jika Anda mencoba mendefinisikan kerangka JavaScript tanpa merinci, ternyata ini adalah alat yang dapat digunakan untuk mengembangkan aplikasi web yang kompleks, khususnya aplikasi halaman tunggal (SPA).
Di masa lalu, aplikasi tersebut dibangun berdasarkan kemampuan JavaScript murni dan pustaka jQuery. Tetapi, dengan meningkatnya kompleksitas aplikasi front-end, alat yang sesuai mulai muncul yang membuat hidup lebih mudah bagi programmer. Sebagai contoh, ini adalah React, Angular, dan Vue.
Kerangka kerja yang populer hari ini memiliki beberapa kesamaan. Jadi, sebagian besar kerangka kerja dan perpustakaan front-end, secara relatif, dari Vue hingga React, memberi pengembang kombinasi tertentu dari fitur berikut:
- Sinkronisasi keadaan dan presentasi visual aplikasi.
- Routing
- Sistem template.
- Komponen yang cocok untuk digunakan kembali.
Apakah kerangka kerja diperlukan untuk pengembang modern?
Jawaban atas pertanyaan yang diajukan dalam judul bagian ini tergantung pada bagaimana Anda berhubungan dengan gagasan "keharusan" kerangka kerja. Saya yakin banyak yang bisa mengatakan bahwa kerangka front-end tidak diperlukan dalam perangkat pengembang web, dan tidak pernah diperlukan. Meskipun tidak dapat dibantah bahwa ini adalah alat yang sangat berguna.
Sebenarnya, pertanyaan kita dapat dirumuskan kembali sebagai berikut: "Apakah kerangka kerja sedikit" perpustakaan jQuery modern "? Apakah mungkin untuk memecahkan masalah yang mereka tuju, dengan cara lain, misalnya, masalah yang muncul pada saat pemutusan programmer selama pengembangan API peramban? "
jQuerySebenarnya, pertanyaan ini tidak mudah dijawab, tetapi kita dapat mengatakan bahwa pengembangan JavaScript, teknologi untuk bekerja dengan komponen web dan alat untuk membangun proyek telah membuat pengembangan SPA tanpa menggunakan kerangka kerja lebih mudah dari sebelumnya.
Untuk menjelajahi ide ini, saya mengembangkan aplikasi satu halaman hanya menggunakan JavaScript, komponen web standar dan bundel Parcel. Dalam prosesnya, saya menghadapi beberapa masalah dan kesulitan, melihat di mana Anda secara khusus mulai melihat kekuatan kerangka kerja JS modern.
Pada saat yang sama, segera setelah saya berurusan dengan hambatan awal, saya terkejut betapa mudahnya membuat aplikasi satu halaman dalam JavaScript murni.
Tinjauan Aplikasi Eksperimental
Aplikasi yang dimaksud cukup sederhana. Ini adalah kumpulan resep elektronik dan memungkinkan pengguna untuk membuat, melihat, dan mengedit resep. Pengguna, di samping itu, dapat menandai resep, menunjukkan bahwa ia menyukainya, dan juga dapat memfilter dan menghapus entri.
Beranda aplikasiHalaman Rekam ResepKomponen web
- β . , ,
HTMLElement
(
HTMLParagraphElement
, ) .
, - , ,
connectedCallback
,
disconnectedCallback
,
attributeChangedCallback
.
recipe-item
, .
import template from './recipe.html'
import DATA_SERVICE from '../../utils/data'
export default class Recipe extends HTMLElement {
constructor () {
// DOM, recipe DATA_SERVICE()
super()
this._shadowRoot = this.attachShadow({ mode: 'open' })
this._recipe = null
this.ds = new DATA_SERVICE()
}
connectedCallback () {
// html-
this._shadowRoot.innerHTML = template
// delete
this._shadowRoot
.querySelector('.delete')
.addEventListener('click', () => this._delete())
}
_render (title) {
// ,
this._shadowRoot.querySelector('.recipe-title').innerHTML = title
this._shadowRoot.querySelector('.favorite').innerHTML = this._recipe
.favorite
? 'Unfavorite'
: 'Favorite'
}
_delete () {
//
try {
await this.ds.deleteRecipe(this._recipe.id)
} catch (e) {
console.error(e)
alert(
'Sorry, there was a problem deleting the recipe. Please, try again.'
)
}
}
get recipe () {
//
return this._recipe
}
set recipe (recipe = {}) {
// , render
this._recipe = recipe
this._render(this._recipe.title)
}
}
window.customElements.define('recipe-item', Recipe)
. , , .
, , npm- Vanilla JS Router. ,
API History, , - 100 . , - , (route guard).
import './components/error/error'
import content404 from './components/404/404.html'
import DATA_SERVICE from './utils/data'
const ds = new DATA_SERVICE()
// , SPA
const $el = document.getElementById('app')
//
const home = async () => {
await import('./components/recipe/recipe')
await import('./components/recipe-list/recipe-list')
await import('./components/modal/modal.js')
$el.innerHTML = `<recipe-list></recipe-list>`
}
const create = async () => {
await import('./components/create-recipe/create-recipe')
$el.innerHTML = `<create-recipe></create-recipe>`
}
const edit = async () => {
await import('./components/edit-recipe/edit-recipe')
$el.innerHTML = `<edit-recipe></edit-recipe>`
}
const error404 = async () => {
$el.innerHTML = content404
}
//
// id
const routes = {
'/': home,
'/create': create,
'/error': error404,
'/edit': async function (params) {
const id = params.get('id')
const recipe = await ds.getRecipe(id)
await edit()
$el.querySelector('edit-recipe').recipe = recipe
}
}
// onpopstate URL
// - /error
window.onpopstate = async () => {
const url = new URL(
window.location.pathname + window.location.search,
window.location.origin
)
if (routes[window.location.pathname]) {
await routes[window.location.pathname](url.searchParams)
} else routes['/error']()
}
//
let onNavItemClick = async pathName => {
const url = new URL(pathName, window.location.origin)
const params = url.searchParams
if (routes[url.pathname]) {
window.history.pushState({}, pathName, window.location.origin + pathName)
await routes[url.pathname](params)
} else {
window.history.pushState({}, '404', window.location.origin + '/404')
routes['/error']()
}
}
//
;(async () => {
const url = new URL(
window.location.pathname + window.location.search,
window.location.origin
)
if (routes[window.location.pathname]) {
await routes[window.location.pathname](url.searchParams)
} else routes['/error']()
})()
// onNavItemClick()
const router = {
onNavItemClick,
routes
}
export { router }
, . , , , β .
JS
, , . , JS-.
β
-, , , , . , -
Fronteers Conference 2011. . . , HTML-
, .
β
-. , β
skatejs ssr web-component-tester. . , -, .
β
querySelector()- , , . Angular .
, β . , , , .
β Shadow DOM
Shadow DOM. . β , . , , , , , - . , . , ,
.
β DOM
Angular React , DOM. , .
Angular University: Β«Angular DOM, , HTML- Β».
Angular, , jQuery, DOM. , HTML-, , DOM, . , HTML-. Virtual DOM , , .
JS . .
β
-, JS, ( «») , , . , , , Angular-.
Angular-,β
- CLI, , , . , , -. , , , , , , .
β
, , . . β . , , , , , . , , , , DOM. .
, React Angular, , . . , - React
shouldUpdate()
onPush
Angular.
β
β . , . . , , , . , .
Parcel. , , Webpack, , , ,
, Parcel , .
React, Vue Angular . «». , React «», Vue β Β« Β».
Stencil Polymer? , , , , - , . , . , -.
, SPA - . , , , .
?
, - , , Β« Β». , , , , , , . , , , , .
, β , , . Β« Β» . , , . , , , -.
, , , , , , , . β . , , , . β , -, , jQuery, .
, - . - , . , , - , .
- . , , , .
! -, ?