O autor do material, cuja tradução publicamos hoje, um desenvolvedor web, diz que tenta revisar regularmente o conjunto de ferramentas que usa. Ele faz isso para entender se pode ficar sem alguns deles, resolvendo suas tarefas habituais. Ele recentemente decidiu realizar um experimento e criar um aplicativo front-end sofisticado sem usar estruturas JavaScript.
O que é uma estrutura?
Se você tentar definir uma estrutura JavaScript sem entrar em detalhes, é uma ferramenta que pode ser usada para desenvolver aplicativos da web complexos, em particular aplicativos de página única (SPA).
Antigamente, esses aplicativos eram criados com base nos recursos do JavaScript puro e na biblioteca jQuery. Porém, com a crescente complexidade dos aplicativos front-end, começaram a aparecer as ferramentas correspondentes que facilitam a vida dos programadores. Por exemplo, esses são React, Angular e Vue.
As estruturas que são populares atualmente têm algumas semelhanças em comum. Portanto, a maioria das estruturas e bibliotecas de front-end, relativamente falando, do Vue ao React, oferece ao desenvolvedor uma certa combinação dos seguintes recursos:
- Sincronização do estado e apresentação visual do aplicativo.
- Encaminhamento
- Sistema de modelo.
- Componentes adequados para reutilização.
As estruturas são necessárias para um desenvolvedor moderno?
A resposta para a pergunta colocada no título desta seção depende de como você se relaciona com a idéia da “necessidade” de estruturas. Estou certo de que muitos podem dizer que as estruturas de front-end não são necessárias no kit de ferramentas para desenvolvedores da Web e nunca foram necessárias. Embora seja indiscutível que essas são ferramentas muito úteis.
Na verdade, nossa pergunta pode ser reformulada da seguinte maneira: “Os frameworks são um pouco de uma“ biblioteca jQuery moderna ”? É possível resolver os problemas a que se destinam, por outros meios, por exemplo, aqueles que apareceram à disposição dos programadores durante o desenvolvimento das APIs do navegador? ”
jQueryDe fato, não é fácil responder a essa pergunta, mas podemos dizer que o desenvolvimento de JavaScript, tecnologias para trabalhar com componentes da Web e ferramentas para construção de projetos tornou o desenvolvimento do SPA sem o uso de estruturas mais fácil do que nunca.
Para explorar essa idéia, desenvolvi um aplicativo de uma página usando apenas JavaScript, componentes padrão da Web e o empacotador de pacotes. No processo, encontrei alguns problemas e dificuldades, olhando para os quais você claramente começa a ver os pontos fortes das estruturas JS modernas.
Ao mesmo tempo, assim que lidei com os obstáculos iniciais, fiquei surpreso com a facilidade de criar um aplicativo de uma página em JavaScript puro.
Visão Geral da Aplicação Experimental
A aplicação em questão é bastante simples. É uma coleção eletrônica de receitas e permite ao usuário criar, visualizar e editar receitas. Além disso, o usuário pode marcar receitas, indicando que ele gosta delas, e também pode filtrar e excluir entradas.
Homepage do aplicativoPágina de registro de receitaComponentes da 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, .
, - . - , . , , - , .
- . , , , .
! -, ?