Improve memory used in the Web IDE state by moving properties away from the file object
## Description There's opportunity for improving the memory footprint of the Vuex state in the Web IDE... This includes both the actual data being stored but also the number of callbacks and functions registered. <details><summary>Original description</summary> Over time in the Web IDE we have added more data into the Vuex store, most of the data doesn't get used. We should do an audit on the data & remove the data that is no longer required. We also need to figure out the hanging when receiving the file list. For this we pass the data into a web worker to put into the format that we require, however when the data comes back Vue makes it reactive which then makes the browser hang (the more files, the larger the hang). I'm not really sure what we can do here, but its worth investigating as its noticeable especially with GitLab CE. </details> ## Actionable items ### Remove dead code We'll clearly gain performance / reduce memory usage if we remove dead code. Even if the benefit is like 1ms, we should do it. I have identified that the following properties on the file object are not used anymore: 1. [x] `parentTreeUrl` !33654 1. [x] `permalink` !33654 1. [x] `commitsPath` !33654 1. [x] `blamePath` !33654 1. [x] `replaces` !33654 1. [x] `renderError` !33654 1. [x] `lastCommitPath` !33654 1. [x] `html` !33654 1. [x] `renderError` !33654 1. [ ] `lastCommit` ### Move some properties to view / utils Some properties on the file object are used in certain views. It is quite wasteful to store that property on every file, instead of computing the property in the particular view: 1. [x] `previewMode` -> should be moved to `repo_editor.vue`, compute based on file extension. !33870 1. [x] `eol` -> should be moved to `ide_status_list.vue`, compute based on file contents. !33870 1. [ ] `fileLanguage` -> we can write a util function that asks Monaco what language a file is using based on its extension. This would probably break in the future when we add support for custom languages via `.gitattributes`, but we can handle that later when we begin implementing that feature. 1. [x] `base64` -> When we upload a new file in the IDE, `base64` is set to true, and is false in all other cases. Finally when the file is about to be committed, we use this property to send a key `encoding` to the backend. The key has two values: `text` or `base64`. We can get rid of the `base64` property and when we commit, we can use a utility function called `isBase64` that computes on the file's `rawPath` (which will always be a data URL for a base64 file). !33870 1. [ ] `projectId` -> This properties are unnecessary on the file object since at a time only one project and branch can be open in the Web IDE. The usage can be replaced with `currentProjectId` in state. 1. [ ] `branchId` -> Same as above. Can be replaced with `currentBranchId` in state. 1. [ ] `url` -> Can be computed based on the `currentBranchId`, `currentProjectId` and `file.path`. We can define a getter called `getFileURL`, that does this job. 1. [ ] `parentPath` -> There is a util called `getPathParent` that does this. So we don't need this property on every file. 1. [ ] `name` -> The name of the file can be computed again by getting the `lastPathComponent`. 1. [ ] `binary` -> We have a util function called `isTextFile`. We can check if a file is binary or not by doing `!isTextFile(...)`. 1. [ ] `changed` -> We already have an array of `changedFiles`. We can create a getter called `isFileChanged`, that looks up the file in that array. This makes our lookup in `changedFiles` O(n), where n is the size of changed files, but it also reduces memory usage by O(n), where n is the number of files in a repository. So I think this optimises the average case, but worsens the worst case (where a very large folder is renamed and a lot of files are changed). Also, since the `changedFiles` array just contains references to the `state.entries` object, this can be turned into a `Set`. 1. [ ] `staged` -> Same as above, but for `stagedFiles` array. Except the items in this array are not references, so this array cannot be turned into a `Set`. 1. [ ] `opened` -> Similarly, we have an `openFiles` array. But this one is tricky because we use this property for folders too to determine which folders were open in the file tree. So to solve this one for both files and folders, we might need to introduce a new property in state called `openFolders` Also, if we get rid of the three properties above, we wouldn't need to clone objects to use in `staged` and `opened` arrays. So those could be converted to `Set`s or array of references too. 1. [ ] `active` -> At a time, there can only be one file active. So it makes sense to turn the existing getter `activeFile` into a state property instead of storing `active` on each file. ### When we fetch data for a file, do not store all properties the backend returns in Vue state - [ ] We should only store the properties we really need. See https://gitlab.com/gitlab-org/gitlab/-/commit/c85b87639fe18241677e29b6d459945f4b0ee54f.
issue