客户端框架介绍

翻译正在进行中。

在本章节我们开始大致了解框架, 简要回顾JavaScript和框架的历史,为什么框架会存在以及它们提供了什么, 如何开始考虑选择一个框架并学习, 以及对于客户端框架还有什么替代方案.

先决条件: 熟悉 HTML, CSS, 以及 JavaScript 语言的核心.
目标: 了解客户端JavaScript框架是如何存在的,它们能解决什么问题,还有哪些替代方案,以及如何选择一个框架.

简史

当JavaScript在1996被发布后, 它给网络增加了少许的交互性和乐趣, 直到那时, 网页仍由静态文档组成. 网络应该不仅仅是阅读,更是创造的地方. 随着JavaScript的流行. 使用JavaScript的开发者们创造工具来解决他们遇到的问题, 并且将其打包成称为的可复用组件, 这样就能和他人共享解决方案. 这种共享库的体系帮助塑造了网络的增长.

现在, JavaScript是网络的基本部分, used on 95% of all websites, 而且网络又是现代生活的基本部分. 用户在网络上写文章, 管理预算, 听音乐, 看电影,  以及和相隔万里的人通过文字, 音频, 视频聊天来瞬时交流. 网络让我们能够做到那些过去只能在电脑上安装本地应用程序才能做到的事. 这些现代的, 复杂的, 具有交互性的网站通常被称为 网络应用程序.

现代JavaScript框架的到来加快了打造高度动态化和交互性强的应用程序的速度.  框架 就是提供该如何构建应用程序的意见的库。这些意见能使应用具有可预测性和同质性。可预测性让软件能在扩展到很大规模的同时仍保持可维护性。可预测性和可维护性对于一个软件的长久健康运行是十分重要的。

在现代网络中,JavaScript框架为众多令人印象深刻的软件提供支持——包括许多你可能每天都使用的网站。你正在阅读的这个MDN Web 文档页面, 就是使用React / ReactDOM框架为其前端提供动力。

有哪些框架?

有很多框架可供你选择,但以下主要介绍目前公认的“四大框架”。

Ember

Ember于2011年12月发布,最初作为SproutCore项目的延续而开始。比其新式的替代品(例如React和Vue),作为老框架它的用户人数要少得多。但因其稳定性、社区支持以及一些明智的编程原则,它仍然享有很高的知名度。

Angular

Angular 是一个开源 Web 应用程序框架,正式发布于2016年9月14日。它由构建 AngularJS 的团队完全重写,并由 Google 的 Angular 团队以及个人和公司社区共同领导。

Angular 是一种基于组件的框架,使用声明式的HTML模板。在应用构建时,框架的编译器将 HTML 模板转换为优化好的 JavaScript 指令,这一过程对开发者是透明的。Angular 使用 TypeScript,它是 JavaScript 的超集,我们将在下一章中对其进行更多介绍。

Vue

Evan You first released Vue in 2014, after working on and learning from the original AngularJS project. Vue is the youngest of the big four, but has enjoyed a recent uptick in popularity.

Vue, like AngularJS, extends HTML with some of its own code. Apart from that, it mainly relies on modern, standard JavaScript.

React

Facebook 在 2013 发布了 React。 在当时 React 已经被Facebook内部用来解决许多问题。 严格来说 React 本身并不是框架,而是一个用来渲染UI 组件的库。 React is used in combination with other libraries to make applications — React and React Native enable developers to make mobile applications; React and ReactDOM enables them to make web applications, etc.

Because React and ReactDOM are so often used together, React is colloquially understood as a JavaScript framework. As you read through this module, we will be working with that colloquial understanding.

React extends JavaScript with HTML-like syntax, known as JSX.

框架为何会存在?

我们已经讨论了因为什么契机而创造了框架,但我们仍不知道为什么开发者认为有必要创造它。要知道这个问题的答案,我们首先需要检查软件开发中的各种挑战。

设想一个很常见的软件:一个To-Do清单创建器,在接下来的章节中我们会使用各种框架来实现它。这个应用应让用户可以完成诸如呈现任务列表、添加和删除任务等操作,且在完成这些操作的同时能可靠地跟踪和更新应用程序的底层数据。在软件开发中,这种底层数据被称为状态。

上述每个目标理论上都很简单。我们可以遍历数据来列出清单,添加一个对象来创建新任务,使用标识符来查找、编辑和删除任务。需要注意的是,用户都是在浏览器中使用应用的这些功能,然而这就引出了一些问题: 每当我们修改应用的数据时,我们都需要更新用户界面以使其匹配。 

我们可以通过To-Do应用的一个功能来检验这个问题的难点:呈现任务清单。

冗长的DOM操作

Building HTML elements and rendering them in the browser at the appropriate time takes a surprising amount of code. Let's say that our state is an array of objects structured like this:

const state = [
  {
    id: 'todo-0',
    name: 'Learn some frameworks!'
  }
]

How do we show one of those tasks to our user? We want to represent each task as a list item – an HTML <li> element inside of an unordered list element (a <ul>). How do we make it? That could look something like this:

function buildTodoItemEl(id, name) {
  const item = document.createElement('li');
  const span = document.createElement('span');
  const textContent = document.createTextNode(name);
 
  span.appendChild(textContent)
 
  item.id = id;
  item.appendChild(span);
  item.appendChild(buildDeleteButtonEl(id));

  return item;
}

Here, we use the document.createElement() method to make our <li>, and several more lines of code to create the properties and children it needs.

The tenth line of this snippet references another build function: buildDeleteButtonEl(). It follows a similar pattern to the one we used to build a list item element:

function buildDeleteButtonEl(id) {
  const button = document.createElement('button');
  const textContent = document.createTextNode('Delete');

  button.setAttribute('type', 'button');
  button.appendChild(textContent);

  return button;
}

This button doesn't do anything yet, but it will later once we decide to implement our delete feature. The code that will render our items on the page might read something like this:

function renderTodoList() {
  const frag = document.createDocumentFragment();
  state.tasks.forEach(task => {
    const item = buildTodoItemEl(task.id, task.name);
    frag.appendChild(item);
  });

  while (todoListEl.firstChild) {
    todoListEl.removeChild(todoListEl.firstChild);
  }
  todoListEl.appendChild(frag);
}

We've now got well over thirty lines of code dedicated just to the UI – just to the step of rendering something in the DOM – and at no point do we add classes that we could use later to style our list-items!

Working directly with the DOM, as in this example, requires understanding many things about how the DOM works: how to make elements; how to change their properties; how to put elements inside of each other; how to get them on the page. None of this code actually handles user interactions, or addresses adding or deleting a task. If we add those features, we have to remember to update our UI in the right time and in the right way.

JavaScript frameworks were created to make this kind of work a little easier — they exist to provide a better developer experience. They don't bring brand-new powers to JavaScript; they give you easier access to JavaScript's powers so you can build for today's web.

If you want to see code samples from this section in action, you can check out a working version of the app on CodePen, which also allows users to add and delete new tasks.

Read more about the JavaScript used in this section:

另一种打造UIs的方式

Every JavaScript framework offers a way to write user interfaces more declaratively. That is, they allow you to write code that describes how your UI should look, and the framework makes it happen in the DOM behind the scenes.

The vanilla JavaScript approach to building out new DOM elements in repetition was difficult to understand at a glance.  By contrast, the following block of code illustrates the way you might use Vue to describe our list of tasks:

<ul>
  <li v-for="task in tasks" v-bind:key="task.id">
    <span>{{task.name}}</span>
    <button type="button">Delete</button>
  </li>
</ul>

That's it. This snippet reduces approximately thirty-two lines of code down to six lines. If the curly braces and v- attributes here are unfamiliar to you, that's okay; you’ll learn about Vue-specific syntax later on in the module. The thing to take away here is that this code looks like the UI it represents, whereas the vanilla JavaScript code does not.

Thanks to Vue, we didn't have to write our own functions for building the UI; the framework will handle that for us in an optimized, efficient way. Our only role here was to describe to Vue what each item should look like. Developers who are familiar with Vue can join our project and quickly work out what is going on. Vue is not alone in this: using a framework improves team as well as individual efficiency.

It's possible to do things similar to this in vanilla JavaScript. Template literal strings make it easy to write strings of HTML that represent what the final element would look like. That might be a useful idea for something as simple as our to-do list application, but it's not maintainable for large applications that manage thousands of records of data, and could render just as many unique elements in a user interface.

框架提供给我们的其他功能

Let's look at some of the other advantages conferred upon us by frameworks. As we've alluded to before, the advantages of frameworks are achievable in vanilla JavaScript, but using a framework takes away all of the cognitive load of having to solve these problems yourself.

Tooling

Because each of the frameworks in this module have a large, active community, each framework's ecosystem provides tooling that Improves the developer experience. These tools make it easy to add things like testing (to ensure that your application behaves as it should) or linting (to ensure that your code is error-free and stylistically consistent).

Note: If you want to find out more details about web tooling concepts, have a read of our Client-side tooling overview.

Compartmentalization

Most major frameworks encourage developers to abstract the different parts of their user interfaces into components — maintainable, reusable chunks of code that can communicate with one another. All the code related to a given component can live in one file (or a couple of specific files), so that you as a developer know exactly where to go to make changes to that component. In a vanilla JavaScript app, you'd have to create your own set of conventions to achieve this in an efficient, scalable way. Many JavaScript developers, if left to their own devices, could end up with all the code related to one part of the UI being spread out all over a file — or in another file altogether.

Routing

The most essential feature of the web is that it allows users to navigate from one page to another – it is, after all, a network of interlinked documents. When you follow a link on this very website, your browser communicates with a server and fetches new content to display for you. As it does so, the URL in your address bar changes. You can save this new URL and come back to the page later on, or share it with others so they can easily find the same page. Your browser remembers your navigation history and allows you to navigate back and forth, too. This is called server-side routing.

Modern web applications typically do not fetch and render new HTML files — they load a single HTML shell, and continually update the DOM inside it (referred to as single page apps, or SPAs) without navigating users to new addresses on the web. Each new pseudo-webpage is usually called a view, and by default, no routing is done.

When an SPA is complex enough, and renders enough unique views, it's important to bring routing functionality into your application. People are used to being able to link to specific pages in an application, travel forward and backward in their navigation history, etc., and their experience suffers when these standard web features are broken. When routing is handled by a client application in this fashion, it is aptly called client-side routing.

It's possible to make a router using the native capabilities of JavaScript and the browser, but popular, actively developed frameworks have companion libraries that make routing a more intuitive part of the development process.

使用框架的注意事项

Being an effective web developer means using the most appropriate tools for the job. JavaScript frameworks make front-end application development easy, but they are not a silver bullet that will solve all problems. This section talks about some of the things you should consider when using frameworks. Bear in mind that you might not need a framework at all — beware that you don't end up using a framework just for the sake of it.

Familiarity with the tool

Just like vanilla JavaScript, frameworks take time to learn and have their quirks. Before you decide to use a framework for a project, be sure you have time to learn enough of its features for it to be useful to you rather than it working against you, and be sure that your teammates are comfortable with it as well.

Overengineering

If your web development project is a personal portfolio with a few pages, and those pages have little or no interactive capability, a framework (and all of its JavaScript) may not be necessary at all. That said, frameworks are not a monolith, and some of them are better-suited to small projects than others. In an article for Smashing Magazine, Sarah Drasner writes about how Vue can replace jQuery as a tool for making small portions of a webpage interactive.

Larger code base and abstraction

Frameworks allow you to write more declarative code – and sometimes less code overall – by dealing with the DOM interactions for you, behind the scenes. This abstraction is great for your experience as a developer, but it isn't free. In order to translate what you write into DOM changes, frameworks have to run their own code, which in turn makes your final piece of software larger and more computationally expensive to operate.

Some extra code is inevitable, and a framework that supports tree-shaking (removal of any code that isn't actually used in the app during the build process) will allow you to keep your applications small, but this is still a factor you need to keep in mind when considering your app's performance, especially on more network/storage-constrained devices, like mobile phones.

The abstraction of frameworks affects not only your JavaScript, but your relationship with the very nature of the web. No matter how you build for the web, the end result, the layer that your users ultimately interact with, is HTML. Writing your whole application in JavaScript can make you lose sight of HTML and the purpose of its various tags, and lead you to produce an HTML document that is un-semantic and inaccessible. In fact, it's possible to write a fragile application that depends entirely on JavaScript and will not function without it.

Frameworks are not the source of our problems. With the wrong priorities, it's possible for any application to be fragile, bloated, and inaccessible. Frameworks do, however, amplify our priorities as developers. If your priority is to make a complex web app, it's easy to do that. However, if your priorities don't carefully guard performance and accessibility, frameworks will amplify your fragility, your bloat, and your inaccessibility. Modern developer priorities, amplified by frameworks, have inverted the structure of the web in many places. Instead of a robust, content-first network of documents, the web now often puts JavaScript first and user experience last.

框架驱动页面的可访问性

Let's build on what we said in the previous section, and talk a bit more about accessibility. Making user interfaces accessible always requires some thought and effort, and frameworks can complicate that process. You often have to employ advanced framework APIs to access native browser features like ARIA live regions or focus management.

In some cases, framework applications create accessibility barriers that do not exist for traditional websites. The biggest example of this is in client-side routing, as mentioned earlier.

With traditional (server-side) routing, navigating the web has predictable results. The browser knows to set focus to the top of the page and assistive technologies will announce the title of the page. These things happen every time you navigate to a new page.

With client-side routing, your browser is not loading new web pages, so it doesn't know that it should automatically adjust focus or announce a new page title. Framework authors have devoted immense time and labor to writing JavaScript that recreates these features, and even then, no framework has done so perfectly.

The upshot is that you should consider accessibility from the very start of every web project, but bear in mind that abstracted codebases that use frameworks are more likely to suffer from major accessibility issues if you don't.

如何选择一个框架

Each of the frameworks discussed in this module take different approaches to web application development. Each is regularly improving or changing, and each has its pros and cons. Choosing the right framework is a team- and project-dependent process, and you should do your own research to uncover what suits your needs. That said, we've identified a few questions you can ask in order to research your options more effectively:

  1. What browsers does the framework support?
  2. What domain-specific languages does the framework utilize?
  3. Does the framework have a strong community and good docs (and other support) available?

The table in this section provides a glanceable summary of the current browser support offered by each framework, as well as the domain-specific languages with which it can be used.

Broadly, domain-specific languages (DSLs) are programming languages relevant in specific areas of software development. In the context of frameworks, DSLs are variations on JavaScript or HTML that make it easier to develop with that framework. Crucially, none of the frameworks require a developer to use a specific DSL, but they have almost all been designed with a specific DSL in mind. Choosing not to employ a framework’s preferred DSL will mean you miss out on features that would otherwise improve your developer experience.

You should seriously consider the support matrix and DSLs of a framework when making a choice for any new project. Mismatched browser support can be a barrier to your users; mismatched DSL support can be a barrier to you and your teammates.

Framework Browser support Preferred DSL Supported DSLs
Angular IE9+ TypeScript HTML-based; TypeScript
React Modern (IE9+ with Polyfills) JSX JSX; TypeScript
Vue IE9+ HTML-based HTML-based, JSX, Pug
Ember Modern (IE9+ in Ember version 2.18) Handlebars Handlebars, TypeScript

Note: DSLs we've described as "HTML-based" do not have official names. They are not really true DSLs, but they are non-standard HTML, so we believe they are worth highlighting.

Citations for this table:

Does the framework have a strong community?

This is perhaps the hardest metric to measure, because community size does not correlate directly to easy-to-access numbers. You can check a project's number of GitHub stars or weekly npm downloads to get an idea of its popularity, but sometimes the best thing to do is search a few forums or talk to other developers. It is not just about the community's size, but also how welcoming and inclusive it is, and how good available documentation is.

Opinions on the web

Don't just take our word on this matter — there are discussions all over the web. The Wikimedia Foundation recently chose to use Vue for its front-end, and posted a request for comments (RFC) on framework adoption. Eric Gardner, the author of the RFC, took time to outline the needs of the Wikimedia project and why certain frameworks were good choices for the team. This RFC serves as a great example of the kind of research you should do for yourself when planning to use a front-end framework.

The State of JavaScript survey is a helpful collection of feedback from JavaScript developers. It covers many topics related to JavaScript, including data about both the use of frameworks and developer sentiment toward them. Currently, there are several years of data available, allowing you to get a sense of a framework's popularity.

The Vue team has exhaustively compared Vue to other popular frameworks. There may be some bias in this comparison (which they note), but it's a valuable resource nonetheless.

客户端框架的替代方案

If you’re looking for tools to expedite the web development process, and you know your project isn’t going to require intensive client-side JavaScript, you could reach for one of a handful of other solutions for building the web:

  • A content management system
  • Server-side rendering
  • A static site generator

Content management systems

Content-management systems (CMSes) are any tools that allow a user to create content for the web without directly writing code themselves. They're a good solution for large projects, especially projects that require input from content writers who have limited coding ability, or for programmers who want to save time. They do, however, require a significant amount of time to set up, and utilizing a CMS means that you surrender at least some measure of control over the final output of your website. For example: if your chosen CMS doesn't author accessible content by default, it's often difficult to improve this.

Popular examples include Wordpress, Joomla, and Drupal.

Server-side rendering

Server-side rendering (SSR) is an application architecture in which it is the server's job to render a single-page application. This is the opposite of client-side rendering, which is the most common and most straightforward way to build a JavaScript application. Server-side rendering is easier on the client's device, because you're only sending a rendered HTML file to them, but it can be difficult to set up compared to a client-side-rendered application.

All of the frameworks covered in this module support server-side rendering as well as client-side rendering. Check out Next.js for React, Nuxt.js for Vue (yes it is confusing, and no, these projects are not related!), FastBoot for Ember, and Angular Universal for Angular.

Note: Some SSR solutions are written and maintained by the community, whereas some are "official" solutions provided by the framework's maintainer.

Static site generators

Static site generators are programs that dynamically generate all the webpages of a multi-page website — including any relevant CSS or JavaScript — so that they can be published in any number of places. The publishing host could be a GitHub pages branch, a Netlify instance, or any private server of your choosing, for example. There are a number of advantages of this approach, mostly around performance (your user's device isn’t building the page with JavaScript; it's already complete) and security (static pages have fewer attack vectors). These sites can still utilize JavaScript where they need to, but they are not dependent upon it. Static site generators take time to learn, just like any other tool, which can be a barrier to your development process.

Static sites can have as few or as many unique pages as you want. Just as frameworks empower you to quickly write client-side JavaScript applications, static site generators allow you a way to quickly create HTML files you would otherwise have written individually. Like frameworks, static site generators allow developers to write components that define common pieces of your web pages, and to compose those components together to create a final page. In the context of static site generators, these components are called templates. Web pages built by static site generators can even be home to framework applications: if you want one specific page of your statically-generated website to boot up a React application when your user visits it for example, you can do that.

Static site generators have been around for quite a long time, but they have seen a bit of a revival in the recent history of the web. A handful of powerful options are now available, such as Hugo, Jekyll, Eleventy, and Gatsby.

If you'd like to learn more about static site generators on the whole, check out Tatiana Mac's Beginner's guide to Eleventy. In the first article of the series, she explains what a static site generator is, and how it relates to other means of publishing web content.

总结

And that brings us to the end of our introduction to frameworks — we’ve not taught you any code yet, but hopefully we've given you a useful background on why you'd use frameworks in the first place and how to go about choosing one, and made you excited to learn more and get stuck in!

Our next article goes down to a lower level, looking at the specific kinds of features frameworks tend to offer, and why they work like they do.

In this module