Skip to content

Commit 4ab4543

Browse files
committed
Move load to web worker
1 parent 6d084ad commit 4ab4543

27 files changed

+450
-376
lines changed

craco.config.js

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
module.exports = {
2+
webpack: {
3+
configure: {
4+
output: {
5+
// I need "this" for workerize-loader
6+
globalObject: "this"
7+
}
8+
}
9+
}
10+
};

package.json

+4-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"repository": "pomber/git-history",
55
"private": true,
66
"dependencies": {
7+
"@craco/craco": "^3.4.1",
78
"diff": "^4.0.1",
89
"js-base64": "^2.5.1",
910
"netlify-auth-providers": "^1.0.0-alpha5",
@@ -12,10 +13,11 @@
1213
"react-dom": "^16.8.1",
1314
"react-scripts": "2.1.3",
1415
"react-swipeable": "^4.3.2",
15-
"react-use": "^5.2.2"
16+
"react-use": "^5.2.2",
17+
"workerize-loader": "^1.0.4"
1618
},
1719
"scripts": {
18-
"start": "react-scripts start",
20+
"start": "craco start",
1921
"build": "react-scripts build",
2022
"format": "prettier --write \"**/*.{js,jsx,md,json,html,css,yml}\" --ignore-path .gitignore",
2123
"test-prettier": "prettier --check \"**/*.{js,jsx,md,json,html,css,yml}\" --ignore-path .gitignore",

src/animation.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1+
/* eslint-disable */
12
import { createAnimation, Stagger } from "./airframe/airframe";
23
import easing from "./airframe/easing";
34

4-
/* eslint-disable */
5-
65
const dx = 250;
76

87
/* @jsx createAnimation */

src/app-helpers.js

+1-37
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
import React, { useState, useEffect } from "react";
2-
import { getLanguage, loadLanguage } from "./language-detector";
1+
import React, { useEffect } from "react";
32

43
export function Center({ children }) {
54
return (
@@ -68,41 +67,6 @@ export function Error({ error, gitProvider }) {
6867
);
6968
}
7069

71-
export function useLoader(promiseFactory, deps) {
72-
const [state, setState] = useState({
73-
data: null,
74-
loading: true,
75-
error: null
76-
});
77-
78-
useEffect(() => {
79-
promiseFactory()
80-
.then(data => {
81-
setState({
82-
data,
83-
loading: false,
84-
error: false
85-
});
86-
})
87-
.catch(error => {
88-
setState({
89-
loading: false,
90-
error
91-
});
92-
});
93-
}, deps);
94-
95-
return [state.data, state.loading, state.error];
96-
}
97-
98-
export function useLanguageLoader(path) {
99-
return useLoader(async () => {
100-
const lang = getLanguage(path);
101-
await loadLanguage(lang);
102-
return lang;
103-
}, [path]);
104-
}
105-
10670
export function useDocumentTitle(title) {
10771
useEffect(() => {
10872
document.title = title;

src/app.js

+17-20
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,7 @@
11
import React, { useState, useEffect } from "react";
22
import History from "./history";
33
import Landing from "./landing";
4-
import {
5-
useLanguageLoader,
6-
useDocumentTitle,
7-
Loading,
8-
Error
9-
} from "./app-helpers";
4+
import { useDocumentTitle, Loading, Error } from "./app-helpers";
105
import getGitProvider from "./git-providers/providers";
116

127
export default function App() {
@@ -25,31 +20,32 @@ function InnerApp({ gitProvider }) {
2520

2621
useDocumentTitle(`Git History - ${fileName}`);
2722

28-
const [commits, commitsLoading, commitsError, loadMore] = useCommitsLoader(
23+
const [versions, loading, error, loadMore] = useVersionsLoader(
2924
gitProvider,
3025
path
3126
);
32-
const [lang, langLoading, langError] = useLanguageLoader(path);
33-
34-
const loading = langLoading || (!commits && commitsLoading);
35-
const error = langError || commitsError;
3627

3728
if (error) {
3829
return <Error error={error} gitProvider={gitProvider} />;
3930
}
4031

41-
if (loading) {
32+
if (!versions && loading) {
4233
return <Loading path={path} />;
4334
}
4435

45-
if (!commits.length) {
36+
if (!versions.length) {
4637
return <Error error={{ status: 404 }} gitProvider={gitProvider} />;
4738
}
4839

49-
return <History commits={commits} language={lang} loadMore={loadMore} />;
40+
const commits = versions.map(v => v.commit);
41+
const slideLines = versions.map(v => v.lines);
42+
43+
return (
44+
<History commits={commits} slideLines={slideLines} loadMore={loadMore} />
45+
);
5046
}
5147

52-
function useCommitsLoader(gitProvider, path) {
48+
function useVersionsLoader(gitProvider) {
5349
const [state, setState] = useState({
5450
data: null,
5551
loading: true,
@@ -69,7 +65,7 @@ function useCommitsLoader(gitProvider, path) {
6965

7066
useEffect(() => {
7167
gitProvider
72-
.getCommits(path, state.last)
68+
.getVersions(state.last)
7369
.then(data => {
7470
setState(old => ({
7571
data,
@@ -80,12 +76,13 @@ function useCommitsLoader(gitProvider, path) {
8076
}));
8177
})
8278
.catch(error => {
83-
setState({
79+
setState(old => ({
80+
...old,
8481
loading: false,
85-
error
86-
});
82+
error: error.message
83+
}));
8784
});
88-
}, [path, state.last]);
85+
}, [state.last]);
8986

9087
return [state.data, state.loading, state.error, loadMore];
9188
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
const cache = {};
2+
3+
async function getCommits({ repo, sha, path, last, token }) {
4+
if (!cache[path]) {
5+
let fields =
6+
"values.path,values.commit.date,values.commit.message,values.commit.hash,values.commit.author.*,values.commit.links.html, values.commit.author.user.nickname, values.commit.author.user.links.avatar.href, values.commit.links.html.href";
7+
// fields = "*.*.*.*.*";
8+
const commitsResponse = await fetch(
9+
`https://api.bitbucket.org/2.0/repositories/${repo}/filehistory/${sha}/${path}?fields=${fields}`,
10+
{ headers: token ? { Authorization: `bearer ${token}` } : {} }
11+
);
12+
13+
if (!commitsResponse.ok) {
14+
throw {
15+
status: commitsResponse.status === 403 ? 404 : commitsResponse.status,
16+
body: commitsJson
17+
};
18+
}
19+
20+
const commitsJson = await commitsResponse.json();
21+
22+
cache[path] = commitsJson.values.map(({ commit }) => ({
23+
sha: commit.hash,
24+
date: new Date(commit.date),
25+
author: {
26+
login: commit.author.user
27+
? commit.author.user.nickname
28+
: commit.author.raw,
29+
avatar: commit.author.user && commit.author.user.links.avatar.href
30+
},
31+
commitUrl: commit.links.html.href,
32+
message: commit.message
33+
}));
34+
}
35+
36+
const commits = cache[path].slice(0, last);
37+
38+
await Promise.all(
39+
commits.map(async commit => {
40+
if (!commit.content) {
41+
const info = await getContent(repo, commit.sha, path, token);
42+
commit.content = info.content;
43+
}
44+
})
45+
);
46+
47+
return commits;
48+
}
49+
50+
async function getContent(repo, sha, path, token) {
51+
const contentResponse = await fetch(
52+
`https://api.bitbucket.org/2.0/repositories/${repo}/src/${sha}/${path}`,
53+
{ headers: token ? { Authorization: `bearer ${token}` } : {} }
54+
);
55+
56+
if (contentResponse.status === 404) {
57+
return { content: "" };
58+
}
59+
60+
if (!contentResponse.ok) {
61+
throw {
62+
status: contentResponse.status,
63+
body: contentJson
64+
};
65+
}
66+
67+
const content = await contentResponse.text();
68+
69+
return { content };
70+
}
71+
72+
export default {
73+
getCommits
74+
};

src/git-providers/bitbucket-provider.js

+16-71
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,15 @@
11
import netlify from "netlify-auth-providers";
22
import React from "react";
3-
const TOKEN_KEY = "bitbucket-token";
43

5-
function getHeaders() {
6-
const token = window.localStorage.getItem(TOKEN_KEY);
7-
return token ? { Authorization: `Bearer ${token}` } : {};
8-
}
4+
import versioner from "./versioner";
5+
import { SOURCE } from "./sources";
6+
7+
const TOKEN_KEY = "bitbucket-token";
98

109
function isLoggedIn() {
1110
return !!window.localStorage.getItem(TOKEN_KEY);
1211
}
1312

14-
async function getContent(repo, sha, path) {
15-
const contentResponse = await fetch(
16-
`https://api.bitbucket.org/2.0/repositories/${repo}/src/${sha}/${path}`,
17-
{ headers: getHeaders() }
18-
);
19-
20-
if (contentResponse.status === 404) {
21-
return { content: "" };
22-
}
23-
24-
if (!contentResponse.ok) {
25-
throw contentResponse;
26-
}
27-
28-
const content = await contentResponse.text();
29-
30-
return { content };
31-
}
32-
3313
function getUrlParams() {
3414
const [, owner, reponame, , sha, ...paths] = window.location.pathname.split(
3515
"/"
@@ -52,52 +32,6 @@ function showLanding() {
5232
return !repo;
5333
}
5434

55-
const cache = {};
56-
57-
async function getCommits(path, last) {
58-
const [repo, sha] = getUrlParams();
59-
60-
if (!cache[path]) {
61-
let fields =
62-
"values.path,values.commit.date,values.commit.message,values.commit.hash,values.commit.author.*,values.commit.links.html, values.commit.author.user.nickname, values.commit.author.user.links.avatar.href, values.commit.links.html.href";
63-
// fields = "*.*.*.*.*";
64-
const commitsResponse = await fetch(
65-
`https://api.bitbucket.org/2.0/repositories/${repo}/filehistory/${sha}/${path}?fields=${fields}`,
66-
{ headers: getHeaders() }
67-
);
68-
if (!commitsResponse.ok) {
69-
throw commitsResponse;
70-
}
71-
const commitsJson = await commitsResponse.json();
72-
73-
cache[path] = commitsJson.values.map(({ commit }) => ({
74-
sha: commit.hash,
75-
date: new Date(commit.date),
76-
author: {
77-
login: commit.author.user
78-
? commit.author.user.nickname
79-
: commit.author.raw,
80-
avatar: commit.author.user && commit.author.user.links.avatar.href
81-
},
82-
commitUrl: commit.links.html.href,
83-
message: commit.message
84-
}));
85-
}
86-
87-
const commits = cache[path].slice(0, last);
88-
89-
await Promise.all(
90-
commits.map(async commit => {
91-
if (!commit.content) {
92-
const info = await getContent(repo, commit.sha, path);
93-
commit.content = info.content;
94-
}
95-
})
96-
);
97-
98-
return commits;
99-
}
100-
10135
function logIn() {
10236
// return new Promise((resolve, reject) => {
10337
var authenticator = new netlify({
@@ -125,10 +59,21 @@ function LogInButton() {
12559
);
12660
}
12761

62+
function getParams() {
63+
const [repo, sha, path] = getUrlParams();
64+
const token = window.localStorage.getItem(TOKEN_KEY);
65+
return { repo, sha, path, token };
66+
}
67+
68+
async function getVersions(last) {
69+
const params = { ...getParams(), last };
70+
return await versioner.getVersions(SOURCE.BITBUCKET, params);
71+
}
72+
12873
export default {
12974
showLanding,
13075
getPath,
131-
getCommits,
76+
getVersions,
13277
logIn,
13378
isLoggedIn,
13479
LogInButton
+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
async function getCommits({ path, last }) {
2+
// TODO cache
3+
const response = await fetch(
4+
`/api/commits?path=${encodeURIComponent(path)}&last=${last}`
5+
);
6+
const commits = await response.json();
7+
commits.forEach(c => (c.date = new Date(c.date)));
8+
9+
return commits;
10+
}
11+
12+
export default {
13+
getCommits
14+
};

0 commit comments

Comments
 (0)