Выбор технологии для создания простого веб-приложения может быть очень сложным. В нашем распоряжении множество инструментов, и каждый из них, кажется, сулит нам Святой Грааль. Давайте попробуем некоторые из них, чтобы лучше понять.

В этой статье мы рассмотрим различные фреймворки и библиотеки, создав одно и то же приложение To-Do List пять раз. Мы собираемся попробовать Angular, Aurelia, Ember.js, React и Polymer 2 . Мы не собираемся сосредотачиваться на TDD или на том, как писать тесты. Мы просто собираемся создать действительно простое базовое приложение, чтобы увидеть, как работает каждый из этих инструментов.

Угловой

Angular - это платформа разработки для создания мобильных и настольных веб-приложений с использованием Typescript / JavaScript.

Создание проекта

Установка Angular CLI

Во-первых, нам нужно установить Angular CLI. Сделать это можно так:

npm install -g @angular/cli

Установка Anguar CLI с помощью npm

Создание проекта

Теперь мы собираемся сгенерировать новый проект:

ng new todo
cd todo

Создание проекта

Теперь нам нужно установить модули Node и запустить наш проект:

npm install
ng serve

Установка зависимостей и запуск сервера

Теперь наше приложение доступно по адресу localhost: 4200. Мы собираемся создать класс для наших задач и сервис:

ng g class task
ng g service task

Создание нашего класса и нашего сервиса

Давайте код

Для этого примера мы также собираемся создать фиктивные данные.

import { Task } from './task';
export const TASKS: Task[] = [
  { id: 1, title: 'Take out the trash', status: false },
  { id: 2, title: 'Fix the roof', status: false },
  { id: 3, title: 'Clean the house', status: false }
];

файл mock-tasks.ts

Теперь давайте сначала определим наш класс задачи:

export class Task {
    id: number;
    title: string;
    status: boolean;
    constructor(id?: number, title?: string, status?: boolean) {
        this.id = id;
        this.title = title || '';
        this.status = status || false;
    }
}

файл task.ts

Теперь мы можем создать наш сервис:

import { Injectable } from '@angular/core';
import { Task } from './task';
import { TASKS } from './mock-tasks';
@Injectable()
export class TaskService  {
  tasks: Task[] = TASKS;
  constructor() { }
  getTasks(): Promise<Task[]> {
    return Promise.resolve(this.tasks);
  }
  add(title: string): Promise<Task> {
    return new Promise(() => {
        const newTask = new Task(this.tasks.length + 1, title, false);
        this.tasks.push(newTask);
        return newTask;
      }
    );
  }
  delete(task: Task): Promise<number> {
    return new Promise(() => {
        const index = this.tasks.findIndex((obj => obj.id === task.id));
        this.tasks.splice(index, 1);
        return task.id;
      }
    );
  }
  changeStatus(task: Task): Promise<Task> {
    return new Promise(() => {
        task.status = true;
        return task;
      }
    );
  }
}

файл task.service.ts

Теперь, когда наш основной класс и наша служба готовы, мы можем настроить наш app.component.ts следующим образом:

import { Component, OnInit } from '@angular/core';
import { Task } from './task';
import { TaskService } from './task.service';
@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
  providers: [TaskService]
})
export class AppComponent implements OnInit {
  title = 'To-do List';
  tasks: Task[];
  constructor(private taskService: TaskService) { }
  ngOnInit(): void {
    this.getTasks();
  }
  getTasks(): void {
    this.taskService.getTasks().then(tasks => this.tasks = tasks);
  }
  addTask(title: string): void {
    title = title.trim();
    if (!title) { return; }
    this.taskService.add(title)
      .then(task => {
        this.tasks.push(task);
      });
  }
  deleteTask(task: Task): void {
    this.taskService.delete(task)
      .then(() => {
        const index = this.findTaskIndex(task.id);
        this.tasks.splice(index, 1);
      });
  }
  changeStatus(task: Task): void {
    this.taskService.changeStatus(task)
      .then(updatedTask => {
        const index = this.findTaskIndex(task.id);
        this.tasks[index] = updatedTask;
      });
  }
  findTaskIndex(id: number): number {
    return this.tasks.findIndex((obj => obj.id === id));
  }
}

app.component.ts.file

И, наконец, мы можем определить шаблон нашего компонента:

<h1>{{title}}</h1>
<div>
  <label>New task:</label> <input #taskTitle />
  <button (click)="addTask(taskTitle.value); taskTitle.value=''">
    Add
  </button>
</div>
<h2>Tasks</h2>
<ul class="tasks">
  <li *ngFor="let task of tasks">
    {{task.id}} - {{task.title}}
    <div *ngIf="task.status; else notDoneBlock">Done</div>
    <ng-template #notDoneBlock>
      <p>Not done<br />
      <button (click)="changeStatus(task)">Done!</button></p>
    </ng-template>
    <p><button (click)="deleteTask(task)">Delete</button></p>
  </li>
</ul>

app.component.html

Контрольно-пропускной пункт

Если мы перейдем к localhost: 4200, мы можем заметить, что у нас есть действительно базовое приложение, в котором мы можем видеть некоторые задачи по умолчанию, создавать новые и удалять некоторые другие. Мы можем возразить, что наш код недостаточно хорош, что данные не сохраняются или тесты отсутствуют. Но дело не в этом.

В этом простом проекте мы увидели, как можно инициализировать проект Angular и как он структурирован. Мы также видим, что с помощью всего нескольких строк кода, написанного с помощью TypeScript, мы можем очень быстро что-то сгенерировать. Теперь у нас есть лучшее представление о том, сколько времени нам нужно на настройку базового проекта и как мы можем двигаться дальше.

Здание для производства

Мы можем построить наш проект для продакшена так:

ng build -prod --base-href ./

Здание для производства

Эта последняя команда сгенерирует для нас пакет.

Некоторые цифры

GitHub

Angular: 481 участник; 144 релиза; 8147 коммитов; 1551 выпуск

Angular CLI: 270 участников; 100 релизов; 1698 коммитов; 419 выпусков

Переполнение стека

Угловой: 61654 вопросов с тегами.

Аурелия

Aurelia - это клиентская платформа JavaScript для мобильных устройств, настольных компьютеров и Интернета, использующая простые соглашения.

Создание проекта

Установка Aurelia CLI

Во-первых, нам нужно установить Aurelia CLI. Сделать это можно так:

npm install aurelia-cli -g

Установка Aurelia CLI

Создание проекта

Теперь мы собираемся сгенерировать новый проект:

au new todo
cd todo

Создание проекта

Нам будет представлен список вопросов. Для этого примера мы выберем значения по умолчанию. Теперь мы можем запустить проект, который будет доступен по адресу localhost: 9000, с помощью следующей команды:

au run --watch

Запуск сервера

Давайте код

Для этого примера мы также собираемся создать фиктивные данные.

export const TASKS = [
  { id: 1, title: 'Take out the trash', status: false },
  { id: 2, title: 'Fix the roof', status: false },
  { id: 3, title: 'Clean the house', status: false }
];

файл mock-tasks.js

Теперь мы собираемся создать файл task.js:

export class Task {
  constructor(id, title) {
    this.id = id;
    this.title = title;
    this.status = false;
  }
}

файл task.js

Еще нам нужно создать сервис:

import { Task } from './task';
import { TASKS } from './mock-tasks';
export class TaskService  {
  tasks = TASKS;
  constructor() { }
  getTasks() {
    return Promise.resolve(this.tasks);
  }
  add(title) {
    return new Promise(() => {
        const newTask = new Task(this.tasks.length + 1, title, false);
        this.tasks.push(newTask);
        return newTask;
      }
    );
  }
  delete(task) {
    return new Promise(() => {
        const index = this.tasks.findIndex((obj => obj.id === task.id));
        this.tasks.splice(index, 1);
        return task.id;
      }
    );
  }
  changeStatus(task) {
    return new Promise(() => {
        task.status = true;
        return task;
      }
    );
  }
}

файл task-service.js

Теперь мы можем заполнить наш файл app.js:

import { Task } from './task';
import { TaskService } from './task-service';
import { inject } from 'aurelia-framework';
@inject(TaskService)
export class App {
  constructor(taskService) {
    this.taskService = taskService;
    this.title = 'To-do List';
    this.tasks = [];
    this.taskTitle = '';
  }
  created() {
    this.taskService.getTasks().then(tasks => this.tasks = tasks);
  }
  addTask() {
        const title = this.taskTitle.trim();
    if (!title) { return; }
    this.taskService.add(title)
      .then(task => {
                this.tasks.push(task);
                this.taskTitle = '';
    });
  }
  deleteTask(task) {
    this.taskService.delete(task)
      .then(() => {
        const index = this.findTaskIndex(task.id);
        this.tasks.splice(index, 1);
      });
  }
  changeStatus(task) {
    this.taskService.changeStatus(task)
      .then(updatedTask => {
        const index = this.findTaskIndex(task.id);
        this.tasks[index] = updatedTask;
      });
  }
  findTaskIndex(id) {
    return this.tasks.findIndex((obj => obj.id === id));
  }
}

файл app.js

Наконец, нам нужно отредактировать наш шаблон app.html следующим образом:

<template>
  <h1>${title}</h1>
  <form submit.trigger="addTask()">
    <input type="text" value.bind="taskTitle">
    <button type="submit">Add</button>
  </form>
  <ul>
    <li repeat.for="task of tasks">
      ${task.id} - ${task.title}
      <div show.bind="!task.status">
        <p>Not done<br />
        <button click.trigger="changeStatus(task)">Done!</button></p>
      </div>
      <div show.bind="task.status">
        <p><button click.trigger="deleteTask(task)">Delete</button></p>
      </div>
    </li>    
  </ul>
</template>

файл app.html

Контрольно-пропускной пункт

Если мы перейдем к localhost: 9000, мы можем заметить, что у нас есть действительно базовое приложение, в котором мы можем видеть некоторые задачи по умолчанию, создавать новые и удалять некоторые другие. Фактически, наше приложение очень похоже на то, которое мы создали с помощью Angular.

В этом простом проекте мы увидели, как можно инициализировать проект Aurelia и как он структурирован. Теперь у нас есть лучшее представление о том, сколько времени нам нужно на настройку базового проекта и как мы можем двигаться дальше. На самом деле это было довольно просто, потому что даже здесь, если мы не используем TypeScript, а только JavaScript, наш код очень похож на наше предыдущее приложение.

Здание для производства

Мы можем построить наш проект для продакшена так:

au build --env prod

Здание для производства

Эта последняя команда сгенерирует для нас пакет.

Некоторые цифры

GitHub

Аурелия: 86 участников; 85 релизов; 572 коммитов; 54 вопроса

Aurelia CLI: 53 участника; 38 релизов; 834 коммитов; 93 проблемы

Переполнение стека

Аурелия: 2370 вопросов с тегами.

Ember.js

Ember.js - это веб-платформа JavaScript с открытым исходным кодом, основанная на шаблоне Модель – представление – модель просмотра (MVVM). Хотя в первую очередь он считается платформой для Интернета, в Ember также можно создавать настольные и мобильные приложения.

Создание проекта

Установка Ember CLI

Во-первых, нам нужно установить Ember CLI. Сделать это можно так:

npm install -g ember-cli

Установка Ember CLI

Создание проекта

Теперь мы собираемся сгенерировать новый проект и запустить его:

ember new todo
cd todo
ember serve

Создание проекта и запуск сервера

Наше приложение будет доступно по адресу localhost: 4200. Теперь мы сгенерируем то, что нам нужно:

ember g model task title:string status:boolean
ember g route tasks --path '/'
ember g route tasks/index
ember g http-mock tasks
ember g adapter application
ember generate serializer application
ember g controller tasks

Создание модели, маршрутов, адаптера, сериализатора и контроллера

Давайте код

Начнем с создания поддельных данных. Мы собираемся поместить то, что нам нужно, в файл server / mocks / tasks.js:

...
tasksRouter.get('/', function(req, res) {
    res.send({
      'tasks': [
        { taskId: 1, title: 'Take out the trash', status: false },
        { taskId: 2, title: 'Fix the roof', status: false },
        { taskId: 3, title: 'Clean the house', status: false }
      ]
    });
});
...

файлы server / mocks / tasks.js

Наша модель задачи должна выглядеть так:

import DS from 'ember-data';
export default DS.Model.extend({
    title: DS.attr('string'),
    isCompleted: DS.attr('boolean')
});

файл models / tasks.js

В наш файл controllers / tasks.js мы поместим следующий код:

import Ember from 'ember';
export default Ember.Controller.extend({
  actions: {
    addTask() {
        const title = this.get('newTitle');
        if (!title.trim()) { return; }
        const id = this.get('model.length') + 1 + new Date().getTime();
        const task = this.store.createRecord('task', {
            id,
            title,
            status: false
        });
        this.set('newTitle', '');
        task.save();
    },
    deleteTask(id) {
      this.store.findRecord('task', id).then((task) => task.destroyRecord());
    },
    changeStatus(id){
      this.store.findRecord('task', id).then((task) => task.set('status', true));
    }
  }
    
});

файл controllers / tasks.js

Теперь нам нужно определить наши маршруты. Сначала в наш файл routes / tasks.js поместим следующий код:

import Ember from 'ember';
export default Ember.Route.extend({
    model: function() {
    return this.store.findAll('task');
    }
});

файл routes / tasks.js

Наш файл router.js также должен выглядеть так:

import Ember from 'ember';
import config from './config/environment';
const Router = Ember.Router.extend({
  location: config.locationType,
  rootURL: config.rootURL
});
Router.map(function() {
  this.route('tasks', { path: '/' }, function() {});
});
export default Router;

файл router.js

Теперь нам нужно определить наш адаптер и наш сериализатор. Сделаем это так:

import DS from 'ember-data';
export default DS.RESTAdapter.extend({
  contentType: 'application/json',
  dataType: 'json',
  namespace: 'api'
});

файл adapters / application.js

import DS from 'ember-data';
export default DS.RESTSerializer.extend({
  primaryKey: 'taskId'
});

файл сериализаторов / application.js

Мы почти закончили. Нам просто нужно установить наши шаблоны.

{{outlet}}

templates / application.hbs

<h1>To-do List</h1>
<div>
  <label>New task:</label> {{input type="text" value=newTitle}}
  <button {{action "addTask"}}>Add</button>
</div>
<h2>Tasks</h2>
<ul class="tasks">
  {{#each model as |task|}}
    <li>
      {{task.id}} - {{task.title}}
      {{#if task.status}}
        <p><button {{action "deleteTask" task.id}}>Delete</button></p>
      {{else}}
        <p>Not done<br />
        <button {{action "changeStatus" task.id}}>Done!</button></p>
      {{/if}}
    </li>
  {{/each}}
</ul>

templates / tasks.hbs

Контрольно-пропускной пункт

Если мы перейдем к localhost: 4200, мы можем заметить, что у нас есть действительно базовое приложение, в котором мы можем видеть некоторые задачи по умолчанию, создавать новые и удалять некоторые другие.

В этом простом проекте мы увидели, как можно инициализировать проект Ember.js и как он структурирован. Теперь у нас есть лучшее представление о том, сколько времени нам нужно на настройку базового проекта и как мы можем двигаться дальше. Мы также можем видеть, что, даже если он имеет общие концепции с другими фреймворками, Ember.js значительно отличается, и нам нужно использовать другой подход.

Здание для производства

Мы можем построить наш проект для продакшена так:

ember build

Здание для производства

Эта последняя команда сгенерирует для нас пакет.

Некоторые цифры

GitHub

Ember.js: 673 автора; 255 релизов; 14762 коммитов; 242 вопроса

Ember CLI: 369 участников; 140 релизов; 7546 коммитов; 151 выпуск

Переполнение стека

Ember.js: 21528 вопросов с тегами

Реагировать

React - это библиотека JavaScript для создания пользовательских интерфейсов. React позволяет нам создавать большие веб-приложения, использующие данные, которые могут изменяться со временем, без перезагрузки страницы. Он направлен в первую очередь на обеспечение скорости, простоты и масштабируемости. React обрабатывает только пользовательские интерфейсы в приложениях. Это соответствует View в шаблоне Model-View-Controller (MVC) и может использоваться в сочетании с другими библиотеками или фреймворками JavaScript в MVC.

Создание проекта

Установка приложения Create React

Чтобы начать наш проект, нам нужно установить Create React App. Сделать это можно так:

npm install -g create-react-app

Установка приложения Create React

Создание проекта

Теперь мы собираемся сгенерировать новый проект и запустить его:

create-react-app todo
cd todo
npm start

Создание проекта и запуск сервера

Наш проект теперь доступен по адресу localhost: 3000.

Давайте код

Для этого примера мы также собираемся создать фиктивные данные. Давайте создадим файл mock / Tasks.js:

export const TASKS = [
  { id: 1, title: 'Take out the trash', status: false },
  { id: 2, title: 'Fix the roof', status: false },
  { id: 3, title: 'Clean the house', status: false }
];
export default TASKS;

файл mock / Tasks.js

Теперь нам нужно определить модель для Задачи и Интерфейса следующим образом:

function guidGenerator() {
  function S4() {
    return Math.floor((1 + Math.random()) * 0x10000)
      .toString(16)
      .substring(1);
  }
  return S4()+S4()+'-'+S4()+'-'+S4()+'-'+S4()+'-'+S4()+S4()+S4();
}
export default class Task {
    constructor(title, status, id) {
      this.title = title || '';
      this.status = status || false;
      this.id = id || guidGenerator();
    }
    
}

файл lib / Task.js

import Task from './Task';
import TASKS from '../mock/Tasks'
import { findIndex } from 'lodash';
export default class TaskDataInterface {
  constructor() {
    this.tasks = TASKS;
  }
  addTask(title) {
      const newTask = new Task(title);
      this.tasks.push(newTask);
      return newTask;
  }
  changeStatus(taskId) {
    const taskIndex = findIndex(this.tasks, (task) => task.id === taskId);
    if (taskIndex > -1) {
      this.tasks[taskIndex].status = !this.tasks[taskIndex].status;
    }
  }
  deleteTask(taskId) {
    const taskIndex = findIndex(this.tasks, (task) => task.id === taskId);
    if (taskIndex > -1) {
      this.tasks.splice(taskIndex, 1);
    }
  }
  getAllTasks() {
    return this.tasks.map(task => task);
  }
}

файл lib / TaskDataInterface.js

Теперь мы можем создать два компонента: один для самого списка, а другой для каждого элемента.

import React from 'react';
import SingleTask from './SingleTask'
export default class TasksList extends React.Component {
  render() {
    return (
      <div>
        <ul>
          {this.props.tasks.map(
            (task) =>
              <SingleTask
                key={task.id}
                taskId={task.id}
                title={task.title}
                status={task.status}
                changeStatus={this.props.changeStatus}
                deleteTask={this.props.deleteTask}
              />
          )}
        </ul>
          
      </div>
    );
  }
}

компоненты / файл TasksList.js

импортировать React из «react»;

export default class TaskTask extends React.Component {
  render() {
    return (
      <li>
        {this.props.taskId} - {this.props.title}
        {this.props.status ? (
          <p><button
            onClick={() => this.props.deleteTask(this.props.taskId)}>
              Delete
          </button></p>
        ) : (
          <p>Not done<br />
          <button
            onClick={() => this.props.changeStatus(this.props.taskId)}>
              Done!
          </button></p>
        )}
        
      </li>
    );
  }
}

компоненты / файл SingleTask.js

Теперь мы можем редактировать файлы App.js и index.js следующим образом:

import React, { Component } from 'react';
import './App.css';
import TasksList from './components/TasksList';
class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      tasks: this.props.dataInterface.getAllTasks()
    };
  }
  addTask = () => {
    if (this._taskInputField.value) {
      this.props.dataInterface.addTask(this._taskInputField.value);
      this.setState({tasks: this.props.dataInterface.getAllTasks()});
      this._taskInputField.value = '';
    }
  }
  changeStatus = taskId => {
    this.props.dataInterface.changeStatus(taskId);
    this.setState({tasks: this.props.dataInterface.getAllTasks()});
  }
  deleteTask = taskId => {
    this.props.dataInterface.deleteTask(taskId);
    this.setState({tasks: this.props.dataInterface.getAllTasks()});
  }
  render() {
    return (
      <div>
        <h1>To-do List</h1>
        <div>
          <label>New task: </label>
          <input
            type="text"
            ref={(c => this._taskInputField = c)}
          />
          <button onClick={this.addTask}>Add</button>
        </div>
        <h2>Tasks</h2>
        <TasksList
          tasks={this.state.tasks}
          changeStatus={this.changeStatus}
          deleteTask={this.deleteTask}
        />
      </div>
    );
  }
}
export default App;

Файл App.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import TaskDataInterface from './lib/TaskDataInterface';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
const taskDataInterface = new TaskDataInterface();
ReactDOM.render(<App dataInterface={taskDataInterface} />, document.getElementById('root'));
registerServiceWorker();

файл index.js

Контрольно-пропускной пункт

Если мы перейдем к localhost: 3000, мы можем заметить, что у нас есть действительно базовое приложение, в котором мы можем видеть некоторые задачи по умолчанию, создавать новые и удалять некоторые другие.

В этом простом проекте мы увидели, как можно инициализировать проект React и как он структурирован. Теперь у нас есть лучшее представление о том, сколько времени нам нужно на настройку базового проекта и как мы можем двигаться дальше. Мы также можем увидеть, даже если у него есть общие концепции с другими фреймворками, чем React отличается и как с помощью всего нескольких строк кода мы можем быстро чего-то достичь.

Здание для производства

Мы можем построить наш проект для продакшена так:

npm run build

Здание для производства

Эта последняя команда сгенерирует для нас пакет.

Некоторые цифры

GitHub

React: 1039 участников; 63 релиза; 8811 коммитов; 580 выпусков

Создание приложения React: 346 участников; 127 релизов; 1143 коммитов; 216 вопросов

Переполнение стека

React: 51656 вопросов с тегами

Полимер 2

Polymer - это библиотека JavaScript с открытым исходным кодом для создания веб-приложений с использованием веб-компонентов. Polymer позволяет нам создавать инкапсулированные, многоразовые элементы, которые работают так же, как стандартные элементы HTML, для использования при создании веб-приложений.

Создание проекта

Установка Polymer CLI

Чтобы начать наш проект, нам нужно установить Polymer CLI. Сделать это можно так:

npm install -g polymer-cli

Установка Polymer CLI

Создание проекта

Теперь мы собираемся сгенерировать новый проект и запустить его:

cd todo
polymer init
polymer serve

Создание проекта и запуск сервера

В процессе нам зададут несколько вопросов. В частности, нам нужно выбрать шаблон. Мы собираемся выбрать полимер-2-приложение. Если все в порядке, наш проект будет доступен по адресу localhost: 8081.

Давайте код

Для этого примера мы также собираемся создать фиктивные данные. Создадим файл mock / tasks.js:

const TASKS = [
  { id: 1, title: 'Take out the trash', status: false },
  { id: 2, title: 'Fix the roof', status: false },
  { id: 3, title: 'Clean the house', status: false }
];

файл mock / tasks.js

Теперь мы собираемся заполнить наш файл todo-app.html следующим образом:

<link rel="import" href="../../bower_components/polymer/polymer.html">
<link rel="import" href="../../bower_components/polymer/polymer-element.html">
<script src="mock/tasks.js"></script>
<dom-module id="todo-app">
  <template>
    <style>
      :host {
        display: block;
      }
    </style>
    <h1>[[title]]</h1>
    <div>
      <label>New task:</label> <input type="text" id="newTask" value="{{term::input}}" />
      <button on-click="addTask">
        Add
      </button>
    </div>
    <h2>Tasks</h2>
    <ul>
      <template id="list" is="dom-repeat" items="[[tasks]]">
        <li>
          {{item.id}} - {{item.title}}
          <template is="dom-if" if="{{item.status}}">
            <p><button on-click="deleteTask">Delete</button></p>
          </template>
          <template is="dom-if" if="{{!item.status}}">
            <p>Not done<br />
            <button on-click="changeStatus">Done!</button></p>
          </template>
          
        </li>
      </template>
    </ul>
  </template>
  <script>
    class TodoApp extends Polymer.Element {
      static get is() { return 'todo-app'; }
      static get properties() {
        return {
          title: {
            type: String,
            value: 'To-do List'
          },
          term: {
            type: String,
            value: ''
          },
          tasks: {
            type: Array,
            value: []
          }
        };
      }
      ready() {
        super.ready();
        this.set('tasks', TASKS);
      }
      addTask() {
        this.term = this.term.trim();
        if (!this.term) { return; }
        this.push('tasks', {id: this.guidGenerator(), title: this.term, status: false});
        this.term = '';
      }
      deleteTask(e) {
        const index = this.findTaskIndex(e.model.item.id);
        this.splice('tasks', index, 1);
      }
      changeStatus(e) {
        const index = this.findTaskIndex(e.model.item.id);
        const oldTask = this.tasks[index];
        this.set(`tasks.${index}.status`, true);
      }
      findTaskIndex(id) {
        return this.tasks.findIndex((obj => obj.id === id));
      }
      guidGenerator() {
        function S4() {
          return Math.floor((1 + Math.random()) * 0x10000)
            .toString(16)
            .substring(1);
        }
        return S4()+S4()+'-'+S4()+'-'+S4()+'-'+S4()+'-'+S4()+S4()+S4();
      }
    }
    window.customElements.define(TodoApp.is, TodoApp);
  </script>
</dom-module>

файл todo-app.html

Контрольно-пропускной пункт

Если мы перейдем к localhost: 8081, мы можем заметить, что у нас есть действительно базовое приложение, в котором мы можем видеть некоторые задачи по умолчанию, создавать новые и удалять некоторые другие.

С помощью этого простого проекта мы увидели, как мы можем инициализировать проект Polymer и как он структурирован. Теперь у нас есть лучшее представление о том, сколько времени нам нужно на настройку базового проекта и как мы можем двигаться дальше. Мы также можем видеть, что, даже если он имеет общие концепции с другими фреймворками, Polymer имеет другую философию.

Здание для производства

Мы можем построить наш проект для продакшена так:

polymer build

Здание для производства

Эта последняя команда сгенерирует для нас пакет. По умолчанию большинство оптимизаций отключено. Чтобы убедиться, что всегда используются правильные улучшения сборки, мы должны предоставить набор конфигураций сборки через поле «builds» нашего файла Polymer.json:

"builds": [{
  "bundle": true,
  "js": {"minify": true},
  "css": {"minify": true},
  "html": {"minify": true}
}]

файл полимера.json

Некоторые цифры

GitHub

Полимер: 119 участников; 115 релизов; 5433 коммитов; 668 выпусков

Polymer CLI: 34 участника; 46 релизов; 576 коммитов; 164 выпуска;

Переполнение стека

Полимер: 7105 вопросов с тегами

Вывод

Как мы можем завершить эту статью и можем ли мы это действительно сделать? Это хороший вопрос. В ходе различных испытаний мы играли с разными инструментами, которые разделяют одни и те же концепции, но имеют разную философию. К сожалению, для нас не существует волшебной формулы, которая подскажет, какую из них выбрать.

Это печально, но факт. Мы должны попробовать инструменты, которые, по нашему мнению, могут соответствовать нашим потребностям, а затем сравнить их по разным параметрам. Помимо производительности и простоты использования, важным моментом может быть рассмотрение сообщества, которое, возможно, выросло вокруг определенного инструмента.