Resolve "Infinite scrolling of Thread message feed"
Part of #2245 (closed)
-
add FIXME for the permalink test https://gitlab.com/gitlab-org/gitter/webapp/merge_requests/1582#note_214553697
What has been done
- the thread messages API endpoint accepts
beforeId
,afterId
andlimit
arguments. - Vuex actions and state to support infinite scrolling
- Adding slimmed down version of
vue-intersect
and using it to recognise user reaching either end of the TMF - styling of TMF supports long lists
- TMF is always scrolled all the way down to the last message
- Replacing
done
from action test withasync
/await
and adding an argument to mock action responses
What doesn't work
- fetching
aroundId
messages, if the permalink isn't within the last 50 messages, it will just show as the first message without its context- the focus on the last message interferes with permalink highlight in TMF right now that will get solved with introducing
aroundId
permalink fetch - there is an issue https://gitlab.com/gitlab-org/gitter/webapp/issues/2287
- the focus on the last message interferes with permalink highlight in TMF right now that will get solved with introducing
- links at the top and at the bottom of the list that provide an alternative to intersection observer
Testing strategy
- change the fetch limit to a smaller amount (e.g. 15). (alternatively, create 50+ messages)
- open TMF with more than 15 messages (notice that it automatically scrolls all the way down)
- scroll up and notice that older messages are fetched and displayed
- validate that after the whole history is fetched, no further requests to the API are being made
Webpack/babel issues faced in this MR
vue-intersect
Webpack issue with Adding vue-intersect
(following diff) causes vue-ssr-renderer to fail on sytax error (not knowing import
syntax).
diff --git a/package-lock.json b/package-lock.json
index 3f14d13ff..f4992db55 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -33128,6 +33128,11 @@
"integrity": "sha512-KmvZVtmM26BQOMK1rwUZsrqxEGeKiYSZGA7SNWE6uExx8UX/cj9hq2MRV/wWC3Cq6AoeDGk57rL9YMFRel/q+g==",
"dev": true
},
+ "vue-intersect": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/vue-intersect/-/vue-intersect-1.1.3.tgz",
+ "integrity": "sha512-8ry42W6zHrpCpWtIiCMsYVBmEdQf9upAZnIFh8ffpCFbfhQcOOtX2xpwyzPaVAoW2MSZuSDGjaKK6Cy1z+Ap8w=="
+ },
"vue-jest": {
"version": "4.0.0-beta.2",
"resolved": "https://registry.npmjs.org/vue-jest/-/vue-jest-4.0.0-beta.2.tgz",
diff --git a/package.json b/package.json
index fb9713417..e655985ae 100644
--- a/package.json
+++ b/package.json
@@ -178,6 +178,7 @@
"useragent": "2.3.0",
"uuid": "^3.3.2",
"vue": "^2.6.8",
+ "vue-intersect": "^1.1.3",
"vue-server-renderer": "^2.6.8",
"vue-template-compiler": "^2.6.8",
"vuedraggable": "^2.21.0",
diff --git a/public/js/vue/thread-message-feed/components/index.vue b/public/js/vue/thread-message-feed/components/index.vue
index 5f1744975..0934e756d 100644
--- a/public/js/vue/thread-message-feed/components/index.vue
+++ b/public/js/vue/thread-message-feed/components/index.vue
@@ -4,6 +4,7 @@ import ThreadHeader from './thread-header.vue';
import ChatInput from './chat-input.vue';
import ChatItem from './chat-item.vue';
import LoadingSpinner from '../../components/loading-spinner.vue';
+import Intersect from 'vue-intersect';
export default {
name: 'ThreadMessageFeed',
@@ -11,8 +12,12 @@ export default {
ChatInput,
ThreadHeader,
LoadingSpinner,
- ChatItem
+ ChatItem,
+ Intersect
},
+ data: () => ({
+ msg: ''
+ }),
computed: {
...mapGetters({
parentMessage: 'threadMessageFeed/parentMessage',
@@ -44,13 +49,17 @@ export default {
<div v-else-if="childMessagesRequest.loading" class="loading-message">
Loading thread <loading-spinner />
</div>
- <chat-item
- v-for="message in childMessages"
- v-else
- :key="message.id"
- :message="message"
- :use-compact-styles="true"
- />
+ <div v-else>
+ <intersect @enter="msg = 'Intersected'" @leave="msg = 'Not intersected'">
+ <div>{{ msg }}</div>
+ </intersect>
+ <chat-item
+ v-for="message in childMessages"
+ :key="message.id"
+ :message="message"
+ :use-compact-styles="true"
+ />
+ </div>
</div>
<chat-input :user="user" thread />
</section>
Async/Await in Vuex
Using async
/await
in Vuex causes ssr-renderer to throw following error:
(node:24041) UnhandledPromiseRejectionWarning: ReferenceError: regeneratorRuntime is not defined
at server-bundle.js:6895:7
at Module.<anonymous> (public/js/vue/thread-message-feed/store/index.js:130:24)
at Module../public/js/vue/thread-message-feed/store/index.js (server-bundle.js:6937:30)
at __webpack_require__ (webpack/bootstrap:19:0)
at Module../public/js/vue/store/index.js (server-bundle.js:5749:84)
at __webpack_require__ (webpack/bootstrap:19:0)
at Module../public/js/vue/entry-server.js (public/js/vue/entry-server.js:1:0)
at __webpack_require__ (webpack/bootstrap:19:0)
at server-bundle.js:85:18
at Object.<anonymous> (server-bundle.js:88:10)
at evaluateModule (/Users/tomas/workspace/gitter/webapp/node_modules/vue-server-renderer/build.dev.js:9274:21)
at /Users/tomas/workspace/gitter/webapp/node_modules/vue-server-renderer/build.dev.js:9332:18
at new Promise (<anonymous>)
at /Users/tomas/workspace/gitter/webapp/node_modules/vue-server-renderer/build.dev.js:9324:14
at Object.renderToString (/Users/tomas/workspace/gitter/webapp/node_modules/vue-server-renderer/build.dev.js:9500:9)
at renderToString (/Users/tomas/workspace/gitter/webapp/server/handlers/renderers/vue-ssr-renderer.js:107:19)
This can be fixed by using @babel/plugin-transform-runtime
as a babel plugin (right now we only use it in tests). But then the frontend code starts failing (because babel stops understanding CommonJS modules in favour of ES modules).
diff --git a/babel.config.js b/babel.config.js
index a65a78459..eef8c5c1a 100644
--- a/babel.config.js
+++ b/babel.config.js
@@ -1,7 +1,8 @@
'use strict';
const presets = ['@babel/preset-env'];
-const plugins = [];
+// needed for async/await in Vuex store
+const plugins = ['@babel/plugin-transform-runtime'];
// Jest is running in node environment, so we need additional plugins
const isJest = !!process.env.JEST_WORKER_ID;
@@ -11,11 +12,5 @@ if (isJest) {
module.exports = {
plugins,
- presets,
- env: {
- test: {
- // from https://github.com/facebook/jest/issues/3126#issuecomment-465926747
- plugins: ['@babel/plugin-transform-runtime']
- }
- }
+ presets
};
The browser errors caused by the change:
Which is a predicted consequence of using the @babel/plugin-transform-runtime
and having CommonJS modules.
After spending hours on tweaking webpack and babel and researching this issue, I'm opting in for the 2 following workarounds:
- using promises in Vuex store
- Copying code from vue-intersect into our codebase
Edited by Tomas Vik