mirror of https://github.com/fantasticit/think.git
client: use next-pwa, fix import different version yjs
This commit is contained in:
parent
2ee25bcb50
commit
d823775e3e
|
@ -39,6 +39,7 @@
|
|||
"node": ">=16.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^17.0.35",
|
||||
"husky": "^7.0.4",
|
||||
"lint-staged": "^12.4.1",
|
||||
"prettier": "^2.3.2",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
const semi = require('@douyinfe/semi-next').default({});
|
||||
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
|
||||
const withOffline = require('next-offline');
|
||||
const withPWA = require('next-pwa');
|
||||
const { getConfig } = require('@think/config');
|
||||
const config = getConfig();
|
||||
|
||||
|
@ -27,26 +27,11 @@ const nextConfig = semi({
|
|||
compiler: {
|
||||
removeConsole: true,
|
||||
},
|
||||
workboxOpts: {
|
||||
runtimeCaching: [
|
||||
{
|
||||
urlPattern: /.(png|jpg|jpeg|svg|webp)$/,
|
||||
handler: 'CacheFirst',
|
||||
},
|
||||
{
|
||||
urlPattern: /api/,
|
||||
handler: 'NetworkFirst',
|
||||
options: {
|
||||
cacheableResponse: {
|
||||
statuses: [0, 200],
|
||||
headers: {
|
||||
'x-sw': 'true',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
pwa: {
|
||||
disable: process.env.NODE_ENV !== 'production',
|
||||
dest: '.next',
|
||||
sw: 'service-worker.js',
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = withOffline(nextConfig);
|
||||
module.exports = withPWA(nextConfig);
|
||||
|
|
|
@ -71,7 +71,7 @@
|
|||
"markdown-it-sub": "^1.0.0",
|
||||
"markdown-it-sup": "^1.0.0",
|
||||
"next": "12.0.10",
|
||||
"next-offline": "^5.0.5",
|
||||
"next-pwa": "^5.5.2",
|
||||
"prosemirror-markdown": "^1.7.0",
|
||||
"prosemirror-model": "^1.16.1",
|
||||
"prosemirror-schema-list": "^1.1.6",
|
||||
|
@ -93,8 +93,6 @@
|
|||
"tippy.js": "^6.3.7",
|
||||
"toggle-selection": "^1.0.6",
|
||||
"viewerjs": "^1.10.4",
|
||||
"y-indexeddb": "^9.0.7",
|
||||
"y-prosemirror": "^1.0.14",
|
||||
"yjs": "^13.5.24"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -102,6 +100,7 @@
|
|||
"@types/react": "17.0.38",
|
||||
"@typescript-eslint/eslint-plugin": "^5.21.0",
|
||||
"@typescript-eslint/parser": "^5.21.0",
|
||||
"copy-webpack-plugin": "11.0.0",
|
||||
"eslint": "^8.14.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
|
@ -109,7 +108,9 @@
|
|||
"eslint-plugin-react": "^7.29.4",
|
||||
"eslint-plugin-react-hooks": "^4.5.0",
|
||||
"eslint-plugin-simple-import-sort": "^7.0.0",
|
||||
"fs-extra": "^10.0.0",
|
||||
"tsconfig-paths-webpack-plugin": "^3.5.2",
|
||||
"typescript": "4.5.5"
|
||||
"typescript": "4.5.5",
|
||||
"workbox-webpack-plugin": "^6.5.3"
|
||||
}
|
||||
}
|
|
@ -1,8 +1,13 @@
|
|||
import * as math from 'lib0/math';
|
||||
import { Plugin } from 'prosemirror-state'; // eslint-disable-line
|
||||
import { Decoration, DecorationSet } from 'prosemirror-view'; // eslint-disable-line
|
||||
import { absolutePositionToRelativePosition, relativePositionToAbsolutePosition, setMeta } from 'y-prosemirror';
|
||||
import { yCursorPluginKey, ySyncPluginKey } from 'y-prosemirror';
|
||||
import {
|
||||
absolutePositionToRelativePosition,
|
||||
relativePositionToAbsolutePosition,
|
||||
setMeta,
|
||||
yCursorPluginKey,
|
||||
ySyncPluginKey,
|
||||
} from 'tiptap/core/y-prosemirror/y-prosemirror';
|
||||
import * as Y from 'yjs';
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Extension } from '@tiptap/core';
|
||||
import { redo, undo, ySyncPlugin, yUndoPlugin, yUndoPluginKey } from 'y-prosemirror';
|
||||
import { redo, undo, ySyncPlugin, yUndoPlugin, yUndoPluginKey } from 'tiptap/core/y-prosemirror/y-prosemirror';
|
||||
import { UndoManager } from 'yjs';
|
||||
|
||||
declare module '@tiptap/core' {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { Transaction } from 'prosemirror-state';
|
||||
import { ySyncPluginKey } from 'y-prosemirror';
|
||||
import { ySyncPluginKey } from 'tiptap/core/y-prosemirror/y-prosemirror';
|
||||
|
||||
export function isChangeOrigin(transaction: Transaction): boolean {
|
||||
return !!transaction.getMeta(ySyncPluginKey);
|
||||
|
|
|
@ -0,0 +1,189 @@
|
|||
import * as idb from 'lib0/indexeddb.js';
|
||||
import * as mutex from 'lib0/mutex.js';
|
||||
import { Observable } from 'lib0/observable.js';
|
||||
import * as Y from 'yjs';
|
||||
|
||||
const customStoreName = 'custom';
|
||||
const updatesStoreName = 'updates';
|
||||
|
||||
export const PREFERRED_TRIM_SIZE = 500;
|
||||
|
||||
/**
|
||||
* @param {IndexeddbPersistence} idbPersistence
|
||||
*/
|
||||
export const fetchUpdates = (idbPersistence) => {
|
||||
const [updatesStore] = idb.transact(/** @type {IDBDatabase} */ (idbPersistence.db), [updatesStoreName]); // , 'readonly')
|
||||
return idb
|
||||
.getAll(updatesStore, idb.createIDBKeyRangeLowerBound(idbPersistence._dbref, false))
|
||||
.then((updates) =>
|
||||
idbPersistence._mux(() =>
|
||||
Y.transact(
|
||||
idbPersistence.doc,
|
||||
() => {
|
||||
updates.forEach((val) => Y.applyUpdate(idbPersistence.doc, val));
|
||||
},
|
||||
idbPersistence,
|
||||
false
|
||||
)
|
||||
)
|
||||
)
|
||||
.then(() =>
|
||||
idb.getLastKey(updatesStore).then((lastKey) => {
|
||||
idbPersistence._dbref = lastKey + 1;
|
||||
})
|
||||
)
|
||||
.then(() =>
|
||||
idb.count(updatesStore).then((cnt) => {
|
||||
idbPersistence._dbsize = cnt;
|
||||
})
|
||||
)
|
||||
.then(() => updatesStore);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {IndexeddbPersistence} idbPersistence
|
||||
* @param {boolean} forceStore
|
||||
*/
|
||||
export const storeState = (idbPersistence, forceStore = true) =>
|
||||
fetchUpdates(idbPersistence).then((updatesStore) => {
|
||||
if (forceStore || idbPersistence._dbsize >= PREFERRED_TRIM_SIZE) {
|
||||
idb
|
||||
.addAutoKey(updatesStore, Y.encodeStateAsUpdate(idbPersistence.doc))
|
||||
.then(() => idb.del(updatesStore, idb.createIDBKeyRangeUpperBound(idbPersistence._dbref, true)))
|
||||
.then(() =>
|
||||
idb.count(updatesStore).then((cnt) => {
|
||||
idbPersistence._dbsize = cnt;
|
||||
})
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
*/
|
||||
export const clearDocument = (name) => idb.deleteDB(name);
|
||||
|
||||
/**
|
||||
* @extends Observable<string>
|
||||
*/
|
||||
export class IndexeddbPersistence extends Observable {
|
||||
/**
|
||||
* @param {string} name
|
||||
* @param {Y.Doc} doc
|
||||
*/
|
||||
constructor(name, doc) {
|
||||
super();
|
||||
this.doc = doc;
|
||||
this.name = name;
|
||||
this._mux = mutex.createMutex();
|
||||
this._dbref = 0;
|
||||
this._dbsize = 0;
|
||||
/**
|
||||
* @type {IDBDatabase|null}
|
||||
*/
|
||||
this.db = null;
|
||||
this.synced = false;
|
||||
this._db = idb.openDB(name, (db) => idb.createStores(db, [['updates', { autoIncrement: true }], ['custom']]));
|
||||
/**
|
||||
* @type {Promise<IndexeddbPersistence>}
|
||||
*/
|
||||
this.whenSynced = this._db.then((db) => {
|
||||
this.db = db;
|
||||
const currState = Y.encodeStateAsUpdate(doc);
|
||||
return fetchUpdates(this)
|
||||
.then((updatesStore) => idb.addAutoKey(updatesStore, currState))
|
||||
.then(() => {
|
||||
this.emit('synced', [this]);
|
||||
this.synced = true;
|
||||
return this;
|
||||
});
|
||||
});
|
||||
/**
|
||||
* Timeout in ms untill data is merged and persisted in idb.
|
||||
*/
|
||||
this._storeTimeout = 1000;
|
||||
/**
|
||||
* @type {any}
|
||||
*/
|
||||
this._storeTimeoutId = null;
|
||||
/**
|
||||
* @param {Uint8Array} update
|
||||
*/
|
||||
this._storeUpdate = (update) =>
|
||||
this._mux(() => {
|
||||
if (this.db) {
|
||||
const [updatesStore] = idb.transact(/** @type {IDBDatabase} */ (this.db), [updatesStoreName]);
|
||||
idb.addAutoKey(updatesStore, update);
|
||||
if (++this._dbsize >= PREFERRED_TRIM_SIZE) {
|
||||
// debounce store call
|
||||
if (this._storeTimeoutId !== null) {
|
||||
clearTimeout(this._storeTimeoutId);
|
||||
}
|
||||
this._storeTimeoutId = setTimeout(() => {
|
||||
storeState(this, false);
|
||||
this._storeTimeoutId = null;
|
||||
}, this._storeTimeout);
|
||||
}
|
||||
}
|
||||
});
|
||||
doc.on('update', this._storeUpdate);
|
||||
this.destroy = this.destroy.bind(this);
|
||||
doc.on('destroy', this.destroy);
|
||||
}
|
||||
|
||||
destroy() {
|
||||
if (this._storeTimeoutId) {
|
||||
clearTimeout(this._storeTimeoutId);
|
||||
}
|
||||
this.doc.off('update', this._storeUpdate);
|
||||
this.doc.off('destroy', this.destroy);
|
||||
return this._db.then((db) => {
|
||||
db.close();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys this instance and removes all data from indexeddb.
|
||||
*
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
clearData() {
|
||||
return this.destroy().then(() => {
|
||||
idb.deleteDB(this.name);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {String | number | ArrayBuffer | Date} key
|
||||
* @return {Promise<String | number | ArrayBuffer | Date | any>}
|
||||
*/
|
||||
get(key) {
|
||||
return this._db.then((db) => {
|
||||
const [custom] = idb.transact(db, [customStoreName], 'readonly');
|
||||
return idb.get(custom, key);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {String | number | ArrayBuffer | Date} key
|
||||
* @param {String | number | ArrayBuffer | Date} value
|
||||
* @return {Promise<String | number | ArrayBuffer | Date>}
|
||||
*/
|
||||
set(key, value) {
|
||||
return this._db.then((db) => {
|
||||
const [custom] = idb.transact(db, [customStoreName]);
|
||||
return idb.put(custom, value, key);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {String | number | ArrayBuffer | Date} key
|
||||
* @return {Promise<undefined>}
|
||||
*/
|
||||
del(key) {
|
||||
return this._db.then((db) => {
|
||||
const [custom] = idb.transact(db, [customStoreName]);
|
||||
return idb.del(custom, key);
|
||||
});
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue