Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Перепись приложения. Нативного.Перепись приложения. Нативного.
На JS. DoneНа JS. Done
Тимофей Лавренюк
@geek_timofey
1
О себеО себе
2
О проектеО проекте
3 . 1
3 . 2
Архитектура
3 . 3
Архитектура
3 . 3
ЯдроЯдро
Архитектура
3 . 3
ЯдроЯдро
RPC ServerRPC ServerАрхитектура
3 . 3
ЯдроЯдро
А что умеет?А что умеет?
3 . 4
ЯдроЯдро
Работа с локальной БДА что умеет?А что умеет?
3 . 4
ЯдроЯдро
ШифрованиеРабота с локальной БДА что умеет?А что умеет?
3 . 4
ЯдроЯдро
ШифрованиеРабота с локальной БД
Общение с RPC-сервером
А что умеет?А что умеет?
3 . 4
ЯдроЯдро
ШифрованиеРабота с локальной БД
Работа с PDFОбщение с RPC-сервером
А что умеет?А что умеет?
3 . 4
Настал 2017 годНастал 2017 год
3 . 5
Настал 2017 годНастал 2017 год
Нужна web-версия...
3 . 5
СРОЧНО НУЖНАСРОЧНО НУЖНА
WEB-ВЕРСИЯ !!!11WEB-ВЕРСИЯ !!!11 3 . 6
3 . 7
WEB-ВерсияWEB-Версия
1.01.0
3 . 8
Старая архитектура
3 . 9
SPASPA
Старая архитектура
3 . 9
SPASPA
REST APIREST API
ЯдроЯдро
Старая архитектура
3 . 9
SPASPA
REST APIREST API
ЯдроЯдро
RPC ServerRPC ServerСтарая архитектура
3 . 9
Старая WEB-версия
3 . 10
Не было режима автораНе было режима автора
Старая WEB-версия
3 . 10
Не было режима автораНе было режима автора
Зависило от интернетЗависило от интернет
соединениясоединения
Старая WEB-версия...
Не было режима автораНе было режима автора
Зависило от интернетЗависило от интернет
соединениясоединения
Был PHPБыл PHP
Ст...
3 . 11
Полноценное web-приложениеПолноценное web-приложение
Задача:Задача:
3 . 12
Полноценное web-приложениеПолноценное web-приложение
Задача:Задача:
Не уступающее нативным клиентам
3 . 12
3 . 13
Увидел PHP
3 . 14
Пришлось переписать
веб приложение
3 . 15
Новая WEB-версия
3 . 16
Есть режим автораЕсть режим автора
Новая WEB-версия
3 . 16
Есть режим автораЕсть режим автора
Работает в OfflineРаботает в Offline
Новая WEB-версия
3 . 16
Есть режим автораЕсть режим автора
Работает в OfflineРаботает в Offline
Не уступает нативнымНе уступает нативным
клиентамклиен...
Криптография
Offline + Web Worker Работа с PDFОбщение с RPC-сервером
Framework Progressive Web App
4
КриптографияКриптография
5 . 1
Основная проблемаОсновная проблема
5 . 2
Основная проблемаОсновная проблема
Никто не знает как работает шифрование в проекте
5 . 2
5 . 3
5 . 4
5 . 5
RSARSA
AESAES
Основные алгоритмы
5 . 6
RSARSA
5 . 7
AESAES
cipher = encrypt(block, key) // шифруем block с помощью key
block = decrypt(cipher, key) // расшифровываем cipher с...
Как реализовать алгоритмыКак реализовать алгоритмы
шифрования?шифрования?
5 . 9
5 . 10
JS библиотека
5 . 10
JS библиотека
Web Crypto API
5 . 10
JS библиотека
Web Crypto API
OpenSSL -> WebAssembly
5 . 10
JS библиотекаJS библиотека
5 . 11
JS библиотекаJS библиотека
+ Изоморфный код
5 . 11
JS библиотекаJS библиотека
+ Поддержка RSA
+ Изоморфный код
5 . 11
JS библиотекаJS библиотека
+ Поддержка RSA
+ Изоморфный код
- Производительность
5 . 11
JS библиотекаJS библиотека
+ Поддержка RSA
+ Изоморфный код
- Производительность
- Размер
5 . 11
Web Crypto APIWeb Crypto API
5 . 12
Web Crypto APIWeb Crypto API
+ Размер
5 . 12
Web Crypto APIWeb Crypto API
+ Размер
+ Производительность
5 . 12
Web Crypto APIWeb Crypto API
- Неполная поддержка RSA
+ Размер
+ Производительность
5 . 12
Web Crypto APIWeb Crypto API
- Неполная поддержка RSA
- Изоморфный код
+ Размер
+ Производительность
5 . 12
Алгоритм PBKDF2Алгоритм PBKDF2
5 . 13
OpenSSL -> WebAssemblyOpenSSL -> WebAssembly
5 . 14
OpenSSL -> WebAssemblyOpenSSL -> WebAssembly
+ Изоморфный код
5 . 14
OpenSSL -> WebAssemblyOpenSSL -> WebAssembly
+ Изоморфный код
+ Производительность
5 . 14
OpenSSL -> WebAssemblyOpenSSL -> WebAssembly
+ Изоморфный код
+ Производительность
- Размер
5 . 14
JS библиотекаJS библиотека
5 . 15
Node-ForgeNode-Forge
JS библиотекаJS библиотека
5 . 15
Node-ForgeNode-Forge
JS библиотекаJS библиотека
Про улучшение оптимизации - в следующих слайдах...
5 . 15
NodeForge FailsNodeForge Fails
5 . 16
Offline + Web WorkerOffline + Web Worker
6 . 1
Что хранить в Offline?Что хранить в Offline?
6 . 2
СтатикаСтатика
Что хранить в Offline?Что хранить в Offline?
6 . 2
СтатикаСтатика
Что хранить в Offline?Что хранить в Offline?
6 . 2
СтатикаСтатика
Данные пользователяДанные пользователя
Что хранить в Offline?Что хранить в Offline?
6 . 2
СтатикаСтатика
Данные пользователяДанные пользователя
Что хранить в Offline?Что хранить в Offline?
6 . 2
СтатикаСтатика
Данные пользователяДанные пользователя
ФайлыФайлы
Что хранить в Offline?Что хранить в Offline?
6 . 2
СтатикаСтатика
Данные пользователяДанные пользователя
ФайлыФайлы
Что хранить в Offline?Что хранить в Offline?
6 . 2
СтатикаСтатика
7 . 1
Service WorkerService Worker
7 . 2
7 . 3
7 . 3
{
"globDirectory": "dist",
"globPatterns": [
"index.html",
"*.js",
"assets/**/*.{png,svg}",
"assets/*.{png,svg}"
],
"swSrc...
{
"assets": [
"src/assets",
"src/service-workers",
"src/manifest.json",
{
"glob": "workbox-sw.js",
"input": "node_modules/...
importScripts('workbox-3.5.0/workbox-sw.js');
workbox.setConfig({
debug: true,
modulePathPrefix: 'workbox-3.5.0/'
});
work...
workbox injectManifest
7 . 7
workbox injectManifest
workbox.precaching.precacheAndRoute([
{
"url": "index.html",
"revision": "4f8109353581284e76b88e568...
СтатикаСтатика
7 . 8
Данные пользователяДанные пользователя
8 . 1
Service WorkerService Worker
8 . 2
Persistent StoragePersistent Storage
8 . 3
8 . 4
LocalStorageLocalStorage
8 . 4
LocalStorageLocalStorage Небольшой лимит
8 . 4
File APIFile API
LocalStorageLocalStorage Небольшой лимит
8 . 4
File APIFile API FileWriter deprecated
LocalStorageLocalStorage Небольшой лимит
8 . 4
File APIFile API FileWriter deprecated
CookiesCookies
LocalStorageLocalStorage Небольшой лимит
8 . 4
File APIFile API FileWriter deprecated
CookiesCookies WATTT??
LocalStorageLocalStorage Небольшой лимит
8 . 4
 CacheStorage CacheStorage
File APIFile API FileWriter deprecated
CookiesCookies WATTT??
LocalStorageLocalStorage Небольшо...
 CacheStorage CacheStorage Нет гибкости
File APIFile API FileWriter deprecated
CookiesCookies WATTT??
LocalStorageLocalSto...
 CacheStorage CacheStorage Нет гибкости
File APIFile API FileWriter deprecated
CookiesCookies WATTT??
WebSQLWebSQL
LocalSt...
 CacheStorage CacheStorage Нет гибкости
File APIFile API FileWriter deprecated
CookiesCookies WATTT??
WebSQLWebSQL Depreca...
 CacheStorage CacheStorage Нет гибкости
File APIFile API FileWriter deprecated
CookiesCookies WATTT??
WebSQLWebSQL Depreca...
 CacheStorage CacheStorage Нет гибкости
File APIFile API FileWriter deprecated
CookiesCookies WATTT??
WebSQLWebSQL Depreca...
IndexedDBIndexedDB
8 . 5
IndexedDBIndexedDB
объектно-ориентированная база данныхобъектно-ориентированная база данных
8 . 5
IndexedDBIndexedDB
объектно-ориентированная база данныхобъектно-ориентированная база данных
хранит обьекты, проиндексирова...
IndexedDBIndexedDB
объектно-ориентированная база данныхобъектно-ориентированная база данных
хранит обьекты, проиндексирова...
IndexedDBIndexedDB
объектно-ориентированная база данныхобъектно-ориентированная база данных
хранит обьекты, проиндексирова...
IndexedDBIndexedDB
объектно-ориентированная база данныхобъектно-ориентированная база данных
хранит обьекты, проиндексирова...
https://caniuse.bitsofco.de/embed/index.html?
feat=indexeddb&periods=future_2,future_1,current&accessible-
colours=false
П...
DebugDebug 8 . 7
IndexedDB в боюIndexedDB в бою
9 . 1
9 . 2
1. Открыть или создать базу
9 . 2
1. Открыть или создать базу
var open = indexedDB.open("MyDatabase", 1);
9 . 2
1. Открыть или создать базу
var open = indexedDB.open("MyDatabase", 1);
2. Создать Schema
9 . 2
1. Открыть или создать базу
var open = indexedDB.open("MyDatabase", 1);
2. Создать Schema
open.onupgradeneeded = () => {
c...
9 . 3
3. Создать транзакцию
9 . 3
3. Создать транзакцию
open.onsuccess = () => {
const db = open.result
const tx = db.transaction("MyObjectStore", "readwrit...
4. Запросить данные
3. Создать транзакцию
open.onsuccess = () => {
const db = open.result
const tx = db.transaction("MyObj...
4. Запросить данные
const getJohn = store.get(12345); // по id
const getBob = index.get(["Smith", "Bob"]); // через index
...
9 . 4
5. Получить данные
9 . 4
5. Получить данные
getJohn.onsuccess = () => {
console.log(getJohn.result.name.first); // => "John"
};
getBob.onsuccess = ...
5. Получить данные
getJohn.onsuccess = () => {
console.log(getJohn.result.name.first); // => "John"
};
getBob.onsuccess = ...
5. Получить данные
getJohn.onsuccess = () => {
console.log(getJohn.result.name.first); // => "John"
};
getBob.onsuccess = ...
Boilerblate!!!1Boilerblate!!!1
9 . 5
Недостатки чистого IndexedDBНедостатки чистого IndexedDB
9 . 6
Недостатки чистого IndexedDBНедостатки чистого IndexedDB
Тяжело поддерживать
9 . 6
Недостатки чистого IndexedDBНедостатки чистого IndexedDB
Тяжело поддерживать
Не поддержки JOIN'ов
9 . 6
Недостатки чистого IndexedDBНедостатки чистого IndexedDB
Тяжело поддерживать
Не поддержки JOIN'ов
Нельзя частично обновить...
Недостатки чистого IndexedDBНедостатки чистого IndexedDB
Тяжело поддерживать
Не поддержки JOIN'ов
Нельзя частично обновить...
Недостатки чистого IndexedDBНедостатки чистого IndexedDB
Тяжело поддерживать
Не поддержки JOIN'ов
Нельзя частично обновить...
"Никто не использует IndexedDB в чистом виде"
- Все JS-разработчики
9 . 7
"Никто не использует IndexedDB в чистом виде"
- Все JS-разработчики
https://developer.mozilla.org/en-US/docs/Web/API/Index...
9 . 8
БиблиотекиБиблиотеки
ОберткиОбертки
9 . 8
БиблиотекиБиблиотеки
ОберткиОбертки
DB EngineDB Engine
9 . 8
БиблиотекиБиблиотеки
ОберткиОбертки
Idb
ZangoDb
MiniMongo
jsStore
PouchDB
Dexie
LocalForage
DB EngineDB Engine
9 . 8
БиблиотекиБиблиотеки
ОберткиОбертки
Idb
ZangoDb
MiniMongo
jsStore
PouchDB
Dexie
LocalForage
DB EngineDB Engine
YDN-DB
AlaS...
9 . 9
9 . 10
КроссбраузерностьКроссбраузерность
9 . 10
КроссбраузерностьКроссбраузерность
Chrome
Firefox
IE 11+, Edge
Safari 10+
9 . 10
SQL-подобный APISQL-подобный APIКроссбраузерностьКроссбраузерность
Chrome
Firefox
IE 11+, Edge
Safari 10+
9 . 10
SQL-подобный APISQL-подобный API
select, insert, update, delete
group by, order by, limit, skip
join
КроссбраузерностьКрос...
SQL-подобный APISQL-подобный API
select, insert, update, delete
group by, order by, limit, skip
join
КроссбраузерностьКрос...
Создание SchemaСоздание Schema
9 . 11
Создание SchemaСоздание Schema
const schemaBuilder = lf.schema.create('KEEPSOLID_SIGN_DB', 1.0);
schemaBuilder.createTable...
Создание SchemaСоздание Schema
const schemaBuilder = lf.schema.create('KEEPSOLID_SIGN_DB', 1.0);
schemaBuilder.createTable...
Типы полейТипы полей
9 . 12
Типы полейТипы полей
String
9 . 12
Типы полейТипы полей
String
Number
9 . 12
Типы полейТипы полей
String
Number
Integer (32bit)
9 . 12
Типы полейТипы полей
String
Number
Integer (32bit)
Boolean
9 . 12
Типы полейТипы полей
String
Number
Integer (32bit)
Boolean
Object
9 . 12
Типы полейТипы полей
String
Number
Integer (32bit)
Boolean
Object
Date
9 . 12
Типы полейТипы полей
String
Number
Integer (32bit)
Boolean
Object
Date
Array Buffer
9 . 12
SQL-подобный APISQL-подобный API
SQL Lovefield
9 . 13
SQL-подобный APISQL-подобный API
SQL Lovefield
SELECT *
FROM Documents
WHERE type = "TEMPLATE"
9 . 13
SQL-подобный APISQL-подобный API
SQL Lovefield
SELECT *
FROM Documents
WHERE type = "TEMPLATE"
Database
.select()
.from(do...
SQL-подобный APISQL-подобный API
SQL Lovefield
SELECT *
FROM Documents
WHERE type = "TEMPLATE"
Database
.select()
.from(do...
SQL-подобный APISQL-подобный API
SQL Lovefield
SELECT *
FROM Documents
WHERE type = "TEMPLATE"
Database
.select()
.from(do...
SQL Lovefield
9 . 14
SQL Lovefield
SELECT *
FROM Documents d, Files f
WHERE d.fileId = f.id
AND d.id = '123'
9 . 14
SQL Lovefield
SELECT *
FROM Documents d, Files f
WHERE d.fileId = f.id
AND d.id = '123'
Database
.select()
.from(document,...
SQL Lovefield
SELECT *
FROM Documents d, Files f
WHERE d.fileId = f.id
AND d.id = '123'
Database
.select()
.from(document,...
SQL Lovefield
SELECT *
FROM Documents d, Files f
WHERE d.fileId = f.id
AND d.id = '123'
Database
.select()
.from(document,...
function idb_and (index1, keyRange1, index2, keyRange2, onfound, onfinish) {
var openCursorRequest1 = index1.openCursor(ke...
function idb_and (index1, keyRange1, index2, keyRange2, onfound, onfinish) {
var openCursorRequest1 = index1.openCursor(ke...
Интересные особенностиИнтересные особенности
9 . 16
Интересные особенностиИнтересные особенности
Позволяет задавать Schema в YAML (SPAC)
9 . 16
Интересные особенностиИнтересные особенности
Позволяет задавать Schema в YAML (SPAC)
Типы Storage: IndexedDB, Memory, Fire...
Интересные особенностиИнтересные особенности
Позволяет задавать Schema в YAML (SPAC)
Типы Storage: IndexedDB, Memory, Fire...
Интересные особенностиИнтересные особенности
Позволяет задавать Schema в YAML (SPAC)
Типы Storage: IndexedDB, Memory, Fire...
Data ObservationData Observation
9 . 17
Data ObservationData Observation
var query = db.select()
.from(documents)
.where(documents.id.eq('1'));
var handler = func...
НюансыНюансы
9 . 18
Изменение SchemaИзменение Schema
9 . 19
Вывод ошибокВывод ошибок
9 . 20
Вывод ошибокВывод ошибок
Constraint error: (202) Attempted to insert NULL value to non-nullable field
Documents.signOrder.
...
Хранение файловХранение файлов
10 . 1
10 . 2
ArrayBuffer
10 . 2
Offline + Web WorkerOffline + Web Worker
11 . 1
11 . 2
FrameworkFramework
12 . 1
АрхитектураАрхитектура
12 . 2
Redux + Side Effects + Entities + Selectors
12 . 3
Side EffectsSide Effects
@Effect()
documentCreate$ = this.actions$.pipe(
ofType(DocumentActions.Types.DocumentCreate),
map(a...
EntitiesEntities
export interface Document {
id: string;
name: string;
}
export interface State extends EntityState<Docume...
EntitiesEntities
export interface Document {
id: string;
name: string;
}
export interface State extends EntityState<Docume...
EntitiesEntities
export interface Document {
id: string;
name: string;
}
export interface State extends EntityState<Docume...
Entity adapterEntity adapter
addOne
addMany
addAll
removeOne
removeMany
removeAll
updateOne
updateMany
upsertOne
upsertMan...
SelectorsSelectors
export const getDocumentState = (state: AppState) => state.documents;
export const getDocumentEntities ...
BoilerplateBoilerplate
12 . 8
SchematicsSchematics
ng generate action
store
entity
reducer
effect
container
feature
12 . 9
class GetDocumentPreviewAction implements IDocumentAction {
readonly type = DocumentActionTypes.GetDocumentPreview;
docume...
https://github.com/pelotom/unionize
import { unionize, ofType, UnionOf } from 'unionize';
const DocumentActions = unionize...
Коммуникация с Web WorkerКоммуникация с Web Worker
12 . 12
12 . 13
Effect
12 . 13
Effect
Action
12 . 13
Effect
Action
ReduxRedux
12 . 13
Effect
Action
ReduxRedux
12 . 13
Effect
Action
ReduxRedux ComutterComutter
12 . 13
Effect
Action
ReduxRedux ComutterComutter
12 . 13
Effect
Action
ReduxRedux Web WorkerComutterComutter
12 . 13
Effect
Action
ReduxRedux Web WorkerComutterComutter
12 . 13
Effect
Action
ReduxRedux Web Worker
Success/Failure
Action
ComutterComutter
12 . 13
Effect
Action
ReduxRedux Web Worker
Success/Failure
Action
ComutterComutter
12 . 13
Redux Devtools
12 . 14
ВыводыВыводы
13 . 1
13 . 2
Спасибо за вниманиеСпасибо за внимание
Тимофей Лавренюк
@geek_timofey
14
Upcoming SlideShare
Loading in …5
×

of

Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 1 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 2 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 3 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 4 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 5 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 6 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 7 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 8 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 9 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 10 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 11 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 12 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 13 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 14 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 15 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 16 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 17 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 18 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 19 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 20 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 21 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 22 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 23 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 24 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 25 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 26 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 27 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 28 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 29 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 30 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 31 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 32 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 33 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 34 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 35 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 36 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 37 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 38 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 39 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 40 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 41 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 42 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 43 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 44 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 45 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 46 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 47 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 48 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 49 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 50 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 51 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 52 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 53 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 54 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 55 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 56 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 57 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 58 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 59 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 60 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 61 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 62 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 63 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 64 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 65 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 66 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 67 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 68 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 69 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 70 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 71 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 72 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 73 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 74 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 75 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 76 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 77 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 78 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 79 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 80 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 81 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 82 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 83 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 84 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 85 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 86 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 87 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 88 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 89 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 90 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 91 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 92 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 93 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 94 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 95 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 96 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 97 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 98 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 99 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 100 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 101 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 102 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 103 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 104 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 105 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 106 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 107 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 108 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 109 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 110 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 111 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 112 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 113 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 114 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 115 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 116 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 117 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 118 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 119 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 120 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 121 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 122 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 123 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 124 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 125 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 126 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 127 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 128 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 129 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 130 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 131 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 132 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 133 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 134 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 135 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 136 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 137 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 138 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 139 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 140 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 141 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 142 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 143 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 144 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 145 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 146 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 147 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 148 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 149 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 150 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 151 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 152 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 153 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 154 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 155 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 156 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 157 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 158 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 159 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 160 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 161 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 162 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 163 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 164 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 165 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 166 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 167 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 168 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 169 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 170 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 171 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 172 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 173 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 174 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 175 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 176 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 177 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 178 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 179 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 180 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 181 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 182 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 183 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 184 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 185 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 186 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 187 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 188 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 189 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 190 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 191 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 192 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 193 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 194 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 195 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 196 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 197 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 198 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 199 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 200 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 201 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 202 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 203 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 204 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 205 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 206 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 207 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 208 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 209 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 210 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 211 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 212 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 213 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 214 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 215 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 216 Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10 Slide 217
Upcoming SlideShare
What to Upload to SlideShare
Next
Download to read offline and view in fullscreen.

0 Likes

Share

Download to read offline

Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10

Download to read offline

KeepSolid Sign — приложение для подписи документов под все популярные платформы. Его ядро написано на C++ и однажды поступила задача сделать веб-версию. Тимофей Лавренюк рассказывает о том, через что получилось пройти, чтобы в итоге сделать веб-приложение не хуже нативного.

Related Books

Free with a 30 day trial from Scribd

See all

Related Audiobooks

Free with a 30 day trial from Scribd

See all
  • Be the first to like this

Перепись приложения. Нативного. На JS. Done. | Odessa Frontend Meetup #10

  1. 1. Перепись приложения. Нативного.Перепись приложения. Нативного. На JS. DoneНа JS. Done Тимофей Лавренюк @geek_timofey 1
  2. 2. О себеО себе 2
  3. 3. О проектеО проекте 3 . 1
  4. 4. 3 . 2
  5. 5. Архитектура 3 . 3
  6. 6. Архитектура 3 . 3
  7. 7. ЯдроЯдро Архитектура 3 . 3
  8. 8. ЯдроЯдро RPC ServerRPC ServerАрхитектура 3 . 3
  9. 9. ЯдроЯдро А что умеет?А что умеет? 3 . 4
  10. 10. ЯдроЯдро Работа с локальной БДА что умеет?А что умеет? 3 . 4
  11. 11. ЯдроЯдро ШифрованиеРабота с локальной БДА что умеет?А что умеет? 3 . 4
  12. 12. ЯдроЯдро ШифрованиеРабота с локальной БД Общение с RPC-сервером А что умеет?А что умеет? 3 . 4
  13. 13. ЯдроЯдро ШифрованиеРабота с локальной БД Работа с PDFОбщение с RPC-сервером А что умеет?А что умеет? 3 . 4
  14. 14. Настал 2017 годНастал 2017 год 3 . 5
  15. 15. Настал 2017 годНастал 2017 год Нужна web-версия... 3 . 5
  16. 16. СРОЧНО НУЖНАСРОЧНО НУЖНА WEB-ВЕРСИЯ !!!11WEB-ВЕРСИЯ !!!11 3 . 6
  17. 17. 3 . 7
  18. 18. WEB-ВерсияWEB-Версия 1.01.0 3 . 8
  19. 19. Старая архитектура 3 . 9
  20. 20. SPASPA Старая архитектура 3 . 9
  21. 21. SPASPA REST APIREST API ЯдроЯдро Старая архитектура 3 . 9
  22. 22. SPASPA REST APIREST API ЯдроЯдро RPC ServerRPC ServerСтарая архитектура 3 . 9
  23. 23. Старая WEB-версия 3 . 10
  24. 24. Не было режима автораНе было режима автора Старая WEB-версия 3 . 10
  25. 25. Не было режима автораНе было режима автора Зависило от интернетЗависило от интернет соединениясоединения Старая WEB-версия 3 . 10
  26. 26. Не было режима автораНе было режима автора Зависило от интернетЗависило от интернет соединениясоединения Был PHPБыл PHP Старая WEB-версия 3 . 10
  27. 27. 3 . 11
  28. 28. Полноценное web-приложениеПолноценное web-приложение Задача:Задача: 3 . 12
  29. 29. Полноценное web-приложениеПолноценное web-приложение Задача:Задача: Не уступающее нативным клиентам 3 . 12
  30. 30. 3 . 13
  31. 31. Увидел PHP 3 . 14
  32. 32. Пришлось переписать веб приложение 3 . 15
  33. 33. Новая WEB-версия 3 . 16
  34. 34. Есть режим автораЕсть режим автора Новая WEB-версия 3 . 16
  35. 35. Есть режим автораЕсть режим автора Работает в OfflineРаботает в Offline Новая WEB-версия 3 . 16
  36. 36. Есть режим автораЕсть режим автора Работает в OfflineРаботает в Offline Не уступает нативнымНе уступает нативным клиентамклиентам Новая WEB-версия 3 . 16
  37. 37. Криптография Offline + Web Worker Работа с PDFОбщение с RPC-сервером Framework Progressive Web App 4
  38. 38. КриптографияКриптография 5 . 1
  39. 39. Основная проблемаОсновная проблема 5 . 2
  40. 40. Основная проблемаОсновная проблема Никто не знает как работает шифрование в проекте 5 . 2
  41. 41. 5 . 3
  42. 42. 5 . 4
  43. 43. 5 . 5
  44. 44. RSARSA AESAES Основные алгоритмы 5 . 6
  45. 45. RSARSA 5 . 7
  46. 46. AESAES cipher = encrypt(block, key) // шифруем block с помощью key block = decrypt(cipher, key) // расшифровываем cipher с помощью key 5 . 8
  47. 47. Как реализовать алгоритмыКак реализовать алгоритмы шифрования?шифрования? 5 . 9
  48. 48. 5 . 10
  49. 49. JS библиотека 5 . 10
  50. 50. JS библиотека Web Crypto API 5 . 10
  51. 51. JS библиотека Web Crypto API OpenSSL -> WebAssembly 5 . 10
  52. 52. JS библиотекаJS библиотека 5 . 11
  53. 53. JS библиотекаJS библиотека + Изоморфный код 5 . 11
  54. 54. JS библиотекаJS библиотека + Поддержка RSA + Изоморфный код 5 . 11
  55. 55. JS библиотекаJS библиотека + Поддержка RSA + Изоморфный код - Производительность 5 . 11
  56. 56. JS библиотекаJS библиотека + Поддержка RSA + Изоморфный код - Производительность - Размер 5 . 11
  57. 57. Web Crypto APIWeb Crypto API 5 . 12
  58. 58. Web Crypto APIWeb Crypto API + Размер 5 . 12
  59. 59. Web Crypto APIWeb Crypto API + Размер + Производительность 5 . 12
  60. 60. Web Crypto APIWeb Crypto API - Неполная поддержка RSA + Размер + Производительность 5 . 12
  61. 61. Web Crypto APIWeb Crypto API - Неполная поддержка RSA - Изоморфный код + Размер + Производительность 5 . 12
  62. 62. Алгоритм PBKDF2Алгоритм PBKDF2 5 . 13
  63. 63. OpenSSL -> WebAssemblyOpenSSL -> WebAssembly 5 . 14
  64. 64. OpenSSL -> WebAssemblyOpenSSL -> WebAssembly + Изоморфный код 5 . 14
  65. 65. OpenSSL -> WebAssemblyOpenSSL -> WebAssembly + Изоморфный код + Производительность 5 . 14
  66. 66. OpenSSL -> WebAssemblyOpenSSL -> WebAssembly + Изоморфный код + Производительность - Размер 5 . 14
  67. 67. JS библиотекаJS библиотека 5 . 15
  68. 68. Node-ForgeNode-Forge JS библиотекаJS библиотека 5 . 15
  69. 69. Node-ForgeNode-Forge JS библиотекаJS библиотека Про улучшение оптимизации - в следующих слайдах... 5 . 15
  70. 70. NodeForge FailsNodeForge Fails 5 . 16
  71. 71. Offline + Web WorkerOffline + Web Worker 6 . 1
  72. 72. Что хранить в Offline?Что хранить в Offline? 6 . 2
  73. 73. СтатикаСтатика Что хранить в Offline?Что хранить в Offline? 6 . 2
  74. 74. СтатикаСтатика Что хранить в Offline?Что хранить в Offline? 6 . 2
  75. 75. СтатикаСтатика Данные пользователяДанные пользователя Что хранить в Offline?Что хранить в Offline? 6 . 2
  76. 76. СтатикаСтатика Данные пользователяДанные пользователя Что хранить в Offline?Что хранить в Offline? 6 . 2
  77. 77. СтатикаСтатика Данные пользователяДанные пользователя ФайлыФайлы Что хранить в Offline?Что хранить в Offline? 6 . 2
  78. 78. СтатикаСтатика Данные пользователяДанные пользователя ФайлыФайлы Что хранить в Offline?Что хранить в Offline? 6 . 2
  79. 79. СтатикаСтатика 7 . 1
  80. 80. Service WorkerService Worker 7 . 2
  81. 81. 7 . 3
  82. 82. 7 . 3
  83. 83. { "globDirectory": "dist", "globPatterns": [ "index.html", "*.js", "assets/**/*.{png,svg}", "assets/*.{png,svg}" ], "swSrc": "src/service-workers/main.worker.js", "swDest": "dist/service-worker.js" } workbox.config.js 7 . 4
  84. 84. { "assets": [ "src/assets", "src/service-workers", "src/manifest.json", { "glob": "workbox-sw.js", "input": "node_modules/workbox-sw/build", "output": "./workbox-3.5.0" }, { "glob": "workbox-core.dev.js", "input": "node_modules/workbox-core/build/", "output": "./workbox-3.5.0" }, { "glob": "workbox-precaching.dev.js", "input": "node_modules/workbox-precaching/build/", "output": "./workbox-3.5.0" } ], } angular.json 7 . 5
  85. 85. importScripts('workbox-3.5.0/workbox-sw.js'); workbox.setConfig({ debug: true, modulePathPrefix: 'workbox-3.5.0/' }); workbox.skipWaiting(); workbox.clientsClaim(); workbox.precaching.precacheAndRoute([]); main.worker.js 7 . 6
  86. 86. workbox injectManifest 7 . 7
  87. 87. workbox injectManifest workbox.precaching.precacheAndRoute([ { "url": "index.html", "revision": "4f8109353581284e76b88e568d642376" }, { "url": "0.js", "revision": "2af14762103b4c1f18e620bd30a53d2e" }, { "url": "main.js", "revision": "ef2fb7f5913e6614c9ee3621ad299d1b" } ]) service-worker.js 7 . 7
  88. 88. СтатикаСтатика 7 . 8
  89. 89. Данные пользователяДанные пользователя 8 . 1
  90. 90. Service WorkerService Worker 8 . 2
  91. 91. Persistent StoragePersistent Storage 8 . 3
  92. 92. 8 . 4
  93. 93. LocalStorageLocalStorage 8 . 4
  94. 94. LocalStorageLocalStorage Небольшой лимит 8 . 4
  95. 95. File APIFile API LocalStorageLocalStorage Небольшой лимит 8 . 4
  96. 96. File APIFile API FileWriter deprecated LocalStorageLocalStorage Небольшой лимит 8 . 4
  97. 97. File APIFile API FileWriter deprecated CookiesCookies LocalStorageLocalStorage Небольшой лимит 8 . 4
  98. 98. File APIFile API FileWriter deprecated CookiesCookies WATTT?? LocalStorageLocalStorage Небольшой лимит 8 . 4
  99. 99.  CacheStorage CacheStorage File APIFile API FileWriter deprecated CookiesCookies WATTT?? LocalStorageLocalStorage Небольшой лимит 8 . 4
  100. 100.  CacheStorage CacheStorage Нет гибкости File APIFile API FileWriter deprecated CookiesCookies WATTT?? LocalStorageLocalStorage Небольшой лимит 8 . 4
  101. 101.  CacheStorage CacheStorage Нет гибкости File APIFile API FileWriter deprecated CookiesCookies WATTT?? WebSQLWebSQL LocalStorageLocalStorage Небольшой лимит 8 . 4
  102. 102.  CacheStorage CacheStorage Нет гибкости File APIFile API FileWriter deprecated CookiesCookies WATTT?? WebSQLWebSQL Deprecated LocalStorageLocalStorage Небольшой лимит 8 . 4
  103. 103.  CacheStorage CacheStorage Нет гибкости File APIFile API FileWriter deprecated CookiesCookies WATTT?? WebSQLWebSQL Deprecated IndexedDBIndexedDB LocalStorageLocalStorage Небольшой лимит 8 . 4
  104. 104.  CacheStorage CacheStorage Нет гибкости File APIFile API FileWriter deprecated CookiesCookies WATTT?? WebSQLWebSQL Deprecated IndexedDBIndexedDB Большой лимит Хорошая поддержка Не Deprecated LocalStorageLocalStorage Небольшой лимит 8 . 4
  105. 105. IndexedDBIndexedDB 8 . 5
  106. 106. IndexedDBIndexedDB объектно-ориентированная база данныхобъектно-ориентированная база данных 8 . 5
  107. 107. IndexedDBIndexedDB объектно-ориентированная база данныхобъектно-ориентированная база данных хранит обьекты, проиндексированные с ключомхранит обьекты, проиндексированные с ключом 8 . 5
  108. 108. IndexedDBIndexedDB объектно-ориентированная база данныхобъектно-ориентированная база данных хранит обьекты, проиндексированные с ключомхранит обьекты, проиндексированные с ключом выполнение операций происходит асинхронновыполнение операций происходит асинхронно 8 . 5
  109. 109. IndexedDBIndexedDB объектно-ориентированная база данныхобъектно-ориентированная база данных хранит обьекты, проиндексированные с ключомхранит обьекты, проиндексированные с ключом выполнение операций происходит асинхронновыполнение операций происходит асинхронно умеет хранить JS-объекты и блобыумеет хранить JS-объекты и блобы 8 . 5
  110. 110. IndexedDBIndexedDB объектно-ориентированная база данныхобъектно-ориентированная база данных хранит обьекты, проиндексированные с ключомхранит обьекты, проиндексированные с ключом выполнение операций происходит асинхронновыполнение операций происходит асинхронно имеет жутко неудобное низкоуровневое APIимеет жутко неудобное низкоуровневое API умеет хранить JS-объекты и блобыумеет хранить JS-объекты и блобы 8 . 5
  111. 111. https://caniuse.bitsofco.de/embed/index.html? feat=indexeddb&periods=future_2,future_1,current&accessible- colours=false ПоддержкаПоддержка 8 . 6
  112. 112. DebugDebug 8 . 7
  113. 113. IndexedDB в боюIndexedDB в бою 9 . 1
  114. 114. 9 . 2
  115. 115. 1. Открыть или создать базу 9 . 2
  116. 116. 1. Открыть или создать базу var open = indexedDB.open("MyDatabase", 1); 9 . 2
  117. 117. 1. Открыть или создать базу var open = indexedDB.open("MyDatabase", 1); 2. Создать Schema 9 . 2
  118. 118. 1. Открыть или создать базу var open = indexedDB.open("MyDatabase", 1); 2. Создать Schema open.onupgradeneeded = () => { const db = open.result; const store = db.createObjectStore("MyObjectStore", {keyPath: "id"}); const index = store.createIndex("NameIndex", ["name.last", "name.first"]); }; 9 . 2
  119. 119. 9 . 3
  120. 120. 3. Создать транзакцию 9 . 3
  121. 121. 3. Создать транзакцию open.onsuccess = () => { const db = open.result const tx = db.transaction("MyObjectStore", "readwrite") const store = tx.objectStore("MyObjectStore"); const index = store.index("NameIndex"); } 9 . 3
  122. 122. 4. Запросить данные 3. Создать транзакцию open.onsuccess = () => { const db = open.result const tx = db.transaction("MyObjectStore", "readwrite") const store = tx.objectStore("MyObjectStore"); const index = store.index("NameIndex"); } 9 . 3
  123. 123. 4. Запросить данные const getJohn = store.get(12345); // по id const getBob = index.get(["Smith", "Bob"]); // через index 3. Создать транзакцию open.onsuccess = () => { const db = open.result const tx = db.transaction("MyObjectStore", "readwrite") const store = tx.objectStore("MyObjectStore"); const index = store.index("NameIndex"); } 9 . 3
  124. 124. 9 . 4
  125. 125. 5. Получить данные 9 . 4
  126. 126. 5. Получить данные getJohn.onsuccess = () => { console.log(getJohn.result.name.first); // => "John" }; getBob.onsuccess = () => { console.log(getBob.result.name.first); // => "Bob" }; 9 . 4
  127. 127. 5. Получить данные getJohn.onsuccess = () => { console.log(getJohn.result.name.first); // => "John" }; getBob.onsuccess = () => { console.log(getBob.result.name.first); // => "Bob" }; 5. Закрыть транзакцию 9 . 4
  128. 128. 5. Получить данные getJohn.onsuccess = () => { console.log(getJohn.result.name.first); // => "John" }; getBob.onsuccess = () => { console.log(getBob.result.name.first); // => "Bob" }; 5. Закрыть транзакцию tx.oncomplete = function() { db.close(); }; 9 . 4
  129. 129. Boilerblate!!!1Boilerblate!!!1 9 . 5
  130. 130. Недостатки чистого IndexedDBНедостатки чистого IndexedDB 9 . 6
  131. 131. Недостатки чистого IndexedDBНедостатки чистого IndexedDB Тяжело поддерживать 9 . 6
  132. 132. Недостатки чистого IndexedDBНедостатки чистого IndexedDB Тяжело поддерживать Не поддержки JOIN'ов 9 . 6
  133. 133. Недостатки чистого IndexedDBНедостатки чистого IndexedDB Тяжело поддерживать Не поддержки JOIN'ов Нельзя частично обновить документ 9 . 6
  134. 134. Недостатки чистого IndexedDBНедостатки чистого IndexedDB Тяжело поддерживать Не поддержки JOIN'ов Нельзя частично обновить документ Скудная сортировка 9 . 6
  135. 135. Недостатки чистого IndexedDBНедостатки чистого IndexedDB Тяжело поддерживать Не поддержки JOIN'ов Нельзя частично обновить документ Скудная сортировка Auto-commit транзакций 9 . 6
  136. 136. "Никто не использует IndexedDB в чистом виде" - Все JS-разработчики 9 . 7
  137. 137. "Никто не использует IndexedDB в чистом виде" - Все JS-разработчики https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API 9 . 7
  138. 138. 9 . 8
  139. 139. БиблиотекиБиблиотеки ОберткиОбертки 9 . 8
  140. 140. БиблиотекиБиблиотеки ОберткиОбертки DB EngineDB Engine 9 . 8
  141. 141. БиблиотекиБиблиотеки ОберткиОбертки Idb ZangoDb MiniMongo jsStore PouchDB Dexie LocalForage DB EngineDB Engine 9 . 8
  142. 142. БиблиотекиБиблиотеки ОберткиОбертки Idb ZangoDb MiniMongo jsStore PouchDB Dexie LocalForage DB EngineDB Engine YDN-DB AlaSQL Lovefield 9 . 8
  143. 143. 9 . 9
  144. 144. 9 . 10
  145. 145. КроссбраузерностьКроссбраузерность 9 . 10
  146. 146. КроссбраузерностьКроссбраузерность Chrome Firefox IE 11+, Edge Safari 10+ 9 . 10
  147. 147. SQL-подобный APISQL-подобный APIКроссбраузерностьКроссбраузерность Chrome Firefox IE 11+, Edge Safari 10+ 9 . 10
  148. 148. SQL-подобный APISQL-подобный API select, insert, update, delete group by, order by, limit, skip join КроссбраузерностьКроссбраузерность Chrome Firefox IE 11+, Edge Safari 10+ 9 . 10
  149. 149. SQL-подобный APISQL-подобный API select, insert, update, delete group by, order by, limit, skip join КроссбраузерностьКроссбраузерность Chrome Firefox IE 11+, Edge Safari 10+ Отличная производительностьОтличная производительность Оптимизация и анализ запросов 9 . 10
  150. 150. Создание SchemaСоздание Schema 9 . 11
  151. 151. Создание SchemaСоздание Schema const schemaBuilder = lf.schema.create('KEEPSOLID_SIGN_DB', 1.0); schemaBuilder.createTable('Documents') .addColumn('id', lf.Type.STRING) .addColumn('parentId', lf.Type.OBJECT) .addColumn('type', lf.Type.STRING) .addColumn('signOrder', lf.Type.NUMBER) .addColumn('encryptionKey', lf.Type.STRING) .addIndex('idxSignOrder', ['signOrder'], false, lf.Order.DESC); .addPrimaryKey(['id']); schemaBuilder.connect().then((db) => { // Можно работать с базой }); 9 . 11
  152. 152. Создание SchemaСоздание Schema const schemaBuilder = lf.schema.create('KEEPSOLID_SIGN_DB', 1.0); schemaBuilder.createTable('Documents') .addColumn('id', lf.Type.STRING) .addColumn('parentId', lf.Type.OBJECT) .addColumn('type', lf.Type.STRING) .addColumn('signOrder', lf.Type.NUMBER) .addColumn('encryptionKey', lf.Type.STRING) .addIndex('idxSignOrder', ['signOrder'], false, lf.Order.DESC); .addPrimaryKey(['id']); schemaBuilder.connect().then((db) => { // Можно работать с базой }); 9 . 11
  153. 153. Типы полейТипы полей 9 . 12
  154. 154. Типы полейТипы полей String 9 . 12
  155. 155. Типы полейТипы полей String Number 9 . 12
  156. 156. Типы полейТипы полей String Number Integer (32bit) 9 . 12
  157. 157. Типы полейТипы полей String Number Integer (32bit) Boolean 9 . 12
  158. 158. Типы полейТипы полей String Number Integer (32bit) Boolean Object 9 . 12
  159. 159. Типы полейТипы полей String Number Integer (32bit) Boolean Object Date 9 . 12
  160. 160. Типы полейТипы полей String Number Integer (32bit) Boolean Object Date Array Buffer 9 . 12
  161. 161. SQL-подобный APISQL-подобный API SQL Lovefield 9 . 13
  162. 162. SQL-подобный APISQL-подобный API SQL Lovefield SELECT * FROM Documents WHERE type = "TEMPLATE" 9 . 13
  163. 163. SQL-подобный APISQL-подобный API SQL Lovefield SELECT * FROM Documents WHERE type = "TEMPLATE" Database .select() .from(document) .where(document.type.eq('TEMPLATE')) .exec() 9 . 13
  164. 164. SQL-подобный APISQL-подобный API SQL Lovefield SELECT * FROM Documents WHERE type = "TEMPLATE" Database .select() .from(document) .where(document.type.eq('TEMPLATE')) .exec() SELECT encryptionKey FROM Documents WHERE signOrder >= 1 ORDER BY signOrder DESC LIMIT 10 9 . 13
  165. 165. SQL-подобный APISQL-подобный API SQL Lovefield SELECT * FROM Documents WHERE type = "TEMPLATE" Database .select() .from(document) .where(document.type.eq('TEMPLATE')) .exec() SELECT encryptionKey FROM Documents WHERE signOrder >= 1 ORDER BY signOrder DESC LIMIT 10 Database .select(document.encryptionKey) .from(document) .where(document.signOrder.gte(1)) .orderBy(document.signOrder, lf.Order.DESC) .limit(10) .exec() 9 . 13
  166. 166. SQL Lovefield 9 . 14
  167. 167. SQL Lovefield SELECT * FROM Documents d, Files f WHERE d.fileId = f.id AND d.id = '123' 9 . 14
  168. 168. SQL Lovefield SELECT * FROM Documents d, Files f WHERE d.fileId = f.id AND d.id = '123' Database .select() .from(document, file) .where(lf.op.and( document.fileId.eq(file.id), document.id.eq('123'), )) .exec() 9 . 14
  169. 169. SQL Lovefield SELECT * FROM Documents d, Files f WHERE d.fileId = f.id AND d.id = '123' Database .select() .from(document, file) .where(lf.op.and( document.fileId.eq(file.id), document.id.eq('123'), )) .exec() SELECT * FROM document INNER JOIN file ON document.fileId = file.id WHERE document.id = '123' 9 . 14
  170. 170. SQL Lovefield SELECT * FROM Documents d, Files f WHERE d.fileId = f.id AND d.id = '123' Database .select() .from(document, file) .where(lf.op.and( document.fileId.eq(file.id), document.id.eq('123'), )) .exec() SELECT * FROM document INNER JOIN file ON document.fileId = file.id WHERE document.id = '123' Database .select() .from(document) .innerJoin( file, document.fileId.eq(file.id) ) .where(document.id.eq('123')) .exec() 9 . 14
  171. 171. function idb_and (index1, keyRange1, index2, keyRange2, onfound, onfinish) { var openCursorRequest1 = index1.openCursor(keyRange1); var openCursorRequest2 = index2.openCursor(keyRange2); assert(index1.objectStore === index2.objectStore); var primKey = index1.objectStore.keyPath; var set = {}; var resolved = 0; function complete() { if (++resolved === 2) onfinish(); } function union(item) { var key = JSON.stringify(item[primKey]); if (!set.hasOwnProperty(key)) { set[key] = true; onfound(item); } } openCursorRequest1.onsuccess = function (event) { var cursor = event.target.result; if (cursor) { union(cursor.value); } else { complete(); } } openCursorRequest2.onsuccess = function (event) { var cursor = event.target.result; if (cursor) { union(cursor.value); } else { complete(); } } } Чистый API 9 . 15
  172. 172. function idb_and (index1, keyRange1, index2, keyRange2, onfound, onfinish) { var openCursorRequest1 = index1.openCursor(keyRange1); var openCursorRequest2 = index2.openCursor(keyRange2); assert(index1.objectStore === index2.objectStore); var primKey = index1.objectStore.keyPath; var set = {}; var resolved = 0; function complete() { if (++resolved === 2) onfinish(); } function union(item) { var key = JSON.stringify(item[primKey]); if (!set.hasOwnProperty(key)) { set[key] = true; onfound(item); } } openCursorRequest1.onsuccess = function (event) { var cursor = event.target.result; if (cursor) { union(cursor.value); } else { complete(); } } openCursorRequest2.onsuccess = function (event) { var cursor = event.target.result; if (cursor) { union(cursor.value); } else { complete(); } } } Чистый API 9 . 15
  173. 173. Интересные особенностиИнтересные особенности 9 . 16
  174. 174. Интересные особенностиИнтересные особенности Позволяет задавать Schema в YAML (SPAC) 9 . 16
  175. 175. Интересные особенностиИнтересные особенности Позволяет задавать Schema в YAML (SPAC) Типы Storage: IndexedDB, Memory, Firebase 9 . 16
  176. 176. Интересные особенностиИнтересные особенности Позволяет задавать Schema в YAML (SPAC) Типы Storage: IndexedDB, Memory, Firebase Поддерживает Import/Export в Javascript-объект 9 . 16
  177. 177. Интересные особенностиИнтересные особенности Позволяет задавать Schema в YAML (SPAC) Типы Storage: IndexedDB, Memory, Firebase Поддерживает Import/Export в Javascript-объект Поддерживает Data Observation 9 . 16
  178. 178. Data ObservationData Observation 9 . 17
  179. 179. Data ObservationData Observation var query = db.select() .from(documents) .where(documents.id.eq('1')); var handler = function(changes) { // Будет вызываться всегда, когда происходит изменение данных }; db.observe(query, handler); db.update(documents) .set(documents.title, 'New Title') .where(documents.id.eq('1')) .exec(); db.unobserve(query, handler); 9 . 17
  180. 180. НюансыНюансы 9 . 18
  181. 181. Изменение SchemaИзменение Schema 9 . 19
  182. 182. Вывод ошибокВывод ошибок 9 . 20
  183. 183. Вывод ошибокВывод ошибок Constraint error: (202) Attempted to insert NULL value to non-nullable field Documents.signOrder. 9 . 20
  184. 184. Хранение файловХранение файлов 10 . 1
  185. 185. 10 . 2
  186. 186. ArrayBuffer 10 . 2
  187. 187. Offline + Web WorkerOffline + Web Worker 11 . 1
  188. 188. 11 . 2
  189. 189. FrameworkFramework 12 . 1
  190. 190. АрхитектураАрхитектура 12 . 2
  191. 191. Redux + Side Effects + Entities + Selectors 12 . 3
  192. 192. Side EffectsSide Effects @Effect() documentCreate$ = this.actions$.pipe( ofType(DocumentActions.Types.DocumentCreate), map(action => action.payload.query), exhaustMap(query => this.dbService.createDocument(query) ), flatMap(() => [ new DocumentAction.DocumentCreateSuccess(); new DocumentAction.GenerateDocumentPreview(); ]) ); 12 . 4
  193. 193. EntitiesEntities export interface Document { id: string; name: string; } export interface State extends EntityState<Document> { activeDocumentId: number | null; } 12 . 5
  194. 194. EntitiesEntities export interface Document { id: string; name: string; } export interface State extends EntityState<Document> { activeDocumentId: number | null; } export const adapter: EntityAdapter<Document> = createEntityAdapter<Document>(); 12 . 5
  195. 195. EntitiesEntities export interface Document { id: string; name: string; } export interface State extends EntityState<Document> { activeDocumentId: number | null; } export const adapter: EntityAdapter<Document> = createEntityAdapter<Document>(); 12 . 5
  196. 196. Entity adapterEntity adapter addOne addMany addAll removeOne removeMany removeAll updateOne updateMany upsertOne upsertMany map 12 . 6
  197. 197. SelectorsSelectors export const getDocumentState = (state: AppState) => state.documents; export const getDocumentEntities = (state: DocumentState) => state.entities; export const getDocumentEntities = createSelector( getDocumentState, getDocumentEntities ); export const getAllDocuments = createSelector(getDocumentEntities, entities => Object.keys(entities).map(id => entities[id]) ); 12 . 7
  198. 198. BoilerplateBoilerplate 12 . 8
  199. 199. SchematicsSchematics ng generate action store entity reducer effect container feature 12 . 9
  200. 200. class GetDocumentPreviewAction implements IDocumentAction { readonly type = DocumentActionTypes.GetDocumentPreview; documentType: DocumentType; constructor(public payload: any) { } } class GetDocumentPreviewSuccessAction implements IDocumentAction { readonly type = DocumentActionTypes.GetDocumentPreviewSuccess; documentType: DocumentType; constructor(public payload: IFileWithData) { } } class GetDocumentPreviewFailureAction implements IDocumentAction { readonly type = DocumentActionTypes.GetDocumentPreviewFailure; documentType: DocumentType; } 12 . 10
  201. 201. https://github.com/pelotom/unionize import { unionize, ofType, UnionOf } from 'unionize'; const DocumentActions = unionize({ GET_DOCUMENT_PREVIEW: ofType<{ id: string }>(), GET_DOCUMENT_PREVIEW_SUCCESS: ofType<IFileWithData>() GET_DOCUMENT_PREVIEW_FAILURE: {} }); type DocumentAction = UnionOf<typeof DocumentActions>; 12 . 11
  202. 202. Коммуникация с Web WorkerКоммуникация с Web Worker 12 . 12
  203. 203. 12 . 13
  204. 204. Effect 12 . 13
  205. 205. Effect Action 12 . 13
  206. 206. Effect Action ReduxRedux 12 . 13
  207. 207. Effect Action ReduxRedux 12 . 13
  208. 208. Effect Action ReduxRedux ComutterComutter 12 . 13
  209. 209. Effect Action ReduxRedux ComutterComutter 12 . 13
  210. 210. Effect Action ReduxRedux Web WorkerComutterComutter 12 . 13
  211. 211. Effect Action ReduxRedux Web WorkerComutterComutter 12 . 13
  212. 212. Effect Action ReduxRedux Web Worker Success/Failure Action ComutterComutter 12 . 13
  213. 213. Effect Action ReduxRedux Web Worker Success/Failure Action ComutterComutter 12 . 13
  214. 214. Redux Devtools 12 . 14
  215. 215. ВыводыВыводы 13 . 1
  216. 216. 13 . 2
  217. 217. Спасибо за вниманиеСпасибо за внимание Тимофей Лавренюк @geek_timofey 14

KeepSolid Sign — приложение для подписи документов под все популярные платформы. Его ядро написано на C++ и однажды поступила задача сделать веб-версию. Тимофей Лавренюк рассказывает о том, через что получилось пройти, чтобы в итоге сделать веб-приложение не хуже нативного.

Views

Total views

147

On Slideshare

0

From embeds

0

Number of embeds

0

Actions

Downloads

4

Shares

0

Comments

0

Likes

0

×