Skip to content

Commit 62afdcf

Browse files
committed
Take a stab at porting existing components to Vue3
Signed-off-by: André Jaenisch <[email protected]>
1 parent e91229e commit 62afdcf

File tree

11 files changed

+384
-524
lines changed

11 files changed

+384
-524
lines changed

package-lock.json

Lines changed: 336 additions & 468 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
"dependencies": {
1010
"@claviska/jquery-minicolors": "2.3.6",
1111
"@primer/octicons": "17.2.0",
12+
"@vue/compiler-sfc": "3.2.37",
1213
"add-asset-webpack-plugin": "2.0.1",
1314
"css-loader": "6.7.1",
1415
"dropzone": "6.0.0-beta.2",
@@ -31,11 +32,10 @@
3132
"swagger-ui-dist": "4.11.1",
3233
"tributejs": "5.1.3",
3334
"uint8-to-base64": "0.2.0",
34-
"vue": "2.6.14",
35-
"vue-bar-graph": "1.3.1",
36-
"vue-calendar-heatmap": "0.8.4",
37-
"vue-loader": "15.9.8",
38-
"vue-template-compiler": "2.6.14",
35+
"vue": "3.2.37",
36+
"vue-bar-graph": "2.0.0",
37+
"vue-loader": "17.0.0",
38+
"vue3-calendar-heatmap": "2.0.0",
3939
"webpack": "5.72.1",
4040
"webpack-cli": "4.9.2",
4141
"workbox-routing": "6.5.3",

web_src/js/components/ActivityHeatmap.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
</div>
1616
</template>
1717
<script>
18-
import {CalendarHeatmap} from 'vue-calendar-heatmap';
18+
import {CalendarHeatmap} from 'vue3-calendar-heatmap';
1919
2020
export default {
2121
name: 'ActivityHeatmap',

web_src/js/components/DashboardRepoList.js

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
import Vue from 'vue';
1+
import {createApp, nextTick} from 'vue';
22
import $ from 'jquery';
33
import {initVueSvg, vueDelimiters} from './VueComponentLoader.js';
44

55
const {appSubUrl, assetUrlPrefix, pageData} = window.config;
66

7-
function initVueComponents() {
8-
Vue.component('repo-search', {
7+
function initVueComponents(app) {
8+
app.component('repo-search', {
99
delimiters: vueDelimiters,
1010
props: {
1111
searchLimit: {
@@ -141,7 +141,7 @@ function initVueComponents() {
141141
$(this.$el).find('.tooltip').popup();
142142
$(this.$el).find('.dropdown').dropdown();
143143
this.setCheckboxes();
144-
Vue.nextTick(() => {
144+
nextTick(() => {
145145
this.$refs.search.focus();
146146
});
147147
},
@@ -189,7 +189,7 @@ function initVueComponents() {
189189
this.reposFilter = filter;
190190
this.repos = [];
191191
this.page = 1;
192-
Vue.set(this.counts, `${filter}:${this.archivedFilter}:${this.privateFilter}`, 0);
192+
this.counts[`${filter}:${this.archivedFilter}:${this.privateFilter}`] = 0;
193193
this.searchRepos();
194194
},
195195

@@ -258,7 +258,7 @@ function initVueComponents() {
258258
this.page = 1;
259259
this.repos = [];
260260
this.setCheckboxes();
261-
Vue.set(this.counts, `${this.reposFilter}:${this.archivedFilter}:${this.privateFilter}`, 0);
261+
this.counts[`${this.reposFilter}:${this.archivedFilter}:${this.privateFilter}`] = 0;
262262
this.searchRepos();
263263
},
264264

@@ -280,7 +280,7 @@ function initVueComponents() {
280280
this.page = 1;
281281
this.repos = [];
282282
this.setCheckboxes();
283-
Vue.set(this.counts, `${this.reposFilter}:${this.archivedFilter}:${this.privateFilter}`, 0);
283+
this.counts[`${this.reposFilter}:${this.archivedFilter}:${this.privateFilter}`] = 0;
284284
this.searchRepos();
285285
},
286286

@@ -294,7 +294,7 @@ function initVueComponents() {
294294
this.page = 1;
295295
}
296296
this.repos = [];
297-
Vue.set(this.counts, `${this.reposFilter}:${this.archivedFilter}:${this.privateFilter}`, 0);
297+
this.counts[`${this.reposFilter}:${this.archivedFilter}:${this.privateFilter}`] = 0;
298298
this.searchRepos();
299299
},
300300

@@ -328,7 +328,7 @@ function initVueComponents() {
328328
if (searchedQuery === '' && searchedMode === '' && this.archivedFilter === 'both') {
329329
this.reposTotalCount = count;
330330
}
331-
Vue.set(this.counts, `${this.reposFilter}:${this.archivedFilter}:${this.privateFilter}`, count);
331+
this.counts[`${this.reposFilter}:${this.archivedFilter}:${this.privateFilter}`] = count;
332332
this.finalPage = Math.ceil(count / this.searchLimit);
333333
this.updateHistory();
334334
this.isLoading = false;
@@ -353,23 +353,22 @@ function initVueComponents() {
353353
});
354354
}
355355

356-
357356
export function initDashboardRepoList() {
358357
const el = document.getElementById('dashboard-repo-list');
359358
const dashboardRepoListData = pageData.dashboardRepoList || null;
360359
if (!el || !dashboardRepoListData) return;
361360

362-
initVueSvg();
363-
initVueComponents();
364-
new Vue({
365-
el,
361+
const app = createApp({
366362
delimiters: vueDelimiters,
367-
data: () => {
363+
data() {
368364
return {
369365
searchLimit: dashboardRepoListData.searchLimit || 0,
370366
subUrl: appSubUrl,
371367
uid: dashboardRepoListData.uid || 0,
372368
};
373369
},
374370
});
371+
initVueSvg(app);
372+
initVueComponents(app);
373+
app.mount(el);
375374
}

web_src/js/components/RepoBranchTagDropdown.js

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import Vue from 'vue';
1+
import {createApp, nextTick} from 'vue';
22
import $ from 'jquery';
33
import {vueDelimiters} from './VueComponentLoader.js';
44

@@ -37,8 +37,7 @@ export function initRepoBranchTagDropdown(selector) {
3737
});
3838
});
3939
$data.remove();
40-
new Vue({
41-
el: this,
40+
createApp({
4241
delimiters: vueDelimiters,
4342
data,
4443
computed: {
@@ -99,7 +98,7 @@ export function initRepoBranchTagDropdown(selector) {
9998
document.body.addEventListener('click', (event) => {
10099
if (this.$el.contains(event.target)) return;
101100
if (this.menuVisible) {
102-
Vue.set(this, 'menuVisible', false);
101+
this.menuVisible = false;
103102
}
104103
});
105104
},
@@ -135,15 +134,15 @@ export function initRepoBranchTagDropdown(selector) {
135134
if (this.submitForm) {
136135
$(`#${this.branchForm}`).trigger('submit');
137136
}
138-
Vue.set(this, 'menuVisible', false);
137+
this.menuVisible = false;
139138
}
140139
},
141140
createNewBranch() {
142141
if (!this.showCreateNewBranch) return;
143142
$(this.$refs.newBranchForm).trigger('submit');
144143
},
145144
focusSearchField() {
146-
Vue.nextTick(() => {
145+
nextTick(() => {
147146
this.$refs.searchField.focus();
148147
});
149148
},
@@ -212,6 +211,6 @@ export function initRepoBranchTagDropdown(selector) {
212211
}
213212
}
214213
}
215-
});
214+
}).mount(this);
216215
});
217216
}

web_src/js/components/VueComponentLoader.js

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import Vue from 'vue';
1+
import {createApp} from 'vue';
22
import {svgs} from '../svg.js';
33

44
export const vueDelimiters = ['${', '}'];
@@ -8,13 +8,15 @@ export function initVueEnv() {
88
if (vueEnvInited) return;
99
vueEnvInited = true;
1010

11+
/* As far as I could tell, this is no longer possible.
12+
* But there seem not to be a guide what to do instead.
1113
const isProd = window.config.runModeIsProd;
12-
Vue.config.productionTip = false;
1314
Vue.config.devtools = !isProd;
15+
*/
1416
}
1517

1618
let vueSvgInited = false;
17-
export function initVueSvg() {
19+
export function initVueSvg(app) {
1820
if (vueSvgInited) return;
1921
vueSvgInited = true;
2022

@@ -24,7 +26,7 @@ export function initVueSvg() {
2426
.replace(/height="[0-9]+"/, 'v-bind:height="size"')
2527
.replace(/width="[0-9]+"/, 'v-bind:width="size"');
2628

27-
Vue.component(name, {
29+
app.component(name, {
2830
props: {
2931
size: {
3032
type: String,
@@ -42,8 +44,7 @@ export function initVueApp(el, opts = {}) {
4244
}
4345
if (!el) return null;
4446

45-
return new Vue(Object.assign({
46-
el,
47-
delimiters: vueDelimiters,
48-
}, opts));
47+
return createApp(
48+
Object.assign({delimiters: vueDelimiters}, opts)
49+
).mount(el);
4950
}

web_src/js/features/contextpopup.js

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import $ from 'jquery';
2-
import Vue from 'vue';
2+
import {createApp} from 'vue';
33
import ContextPopup from '../components/ContextPopup.vue';
44
import {parseIssueHref} from '../utils.js';
55

@@ -20,14 +20,12 @@ export default function initContextPopups() {
2020
el.innerHTML = '<div></div>';
2121
this.parentNode.insertBefore(el, this.nextSibling);
2222

23-
const View = Vue.extend({
23+
const view = createApp({
2424
render: (createElement) => createElement(ContextPopup),
2525
});
2626

27-
const view = new View();
28-
2927
try {
30-
view.$mount(el.firstChild);
28+
view.mount(el.firstChild);
3129
} catch (err) {
3230
console.error(err);
3331
el.textContent = 'ContextPopup failed to load';

web_src/js/features/heatmap.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import Vue from 'vue';
1+
import {createApp} from 'vue';
22
import ActivityHeatmap from '../components/ActivityHeatmap.vue';
33

44
export default function initHeatmap() {
@@ -17,11 +17,11 @@ export default function initHeatmap() {
1717
return {date: new Date(v), count: heatmap[v]};
1818
});
1919

20-
const View = Vue.extend({
20+
const View = createApp({
2121
render: (createElement) => createElement(ActivityHeatmap, {props: {values}}),
2222
});
2323

24-
new View().$mount(el);
24+
View.mount(el);
2525
} catch (err) {
2626
console.error('Heatmap failed to load', err);
2727
el.textContent = 'Heatmap failed to load';
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import Vue from 'vue';
1+
import {createApp} from 'vue';
22
import PullRequestMergeForm from '../components/PullRequestMergeForm.vue';
33

44
export default function initPullRequestMergeForm() {
55
const el = document.getElementById('pull-request-merge-form');
66
if (!el) return;
77

8-
const View = Vue.extend({
8+
const View = createApp({
99
render: (createElement) => createElement(PullRequestMergeForm),
1010
});
11-
new View().$mount(el);
11+
View.mount(el);
1212
}

web_src/js/svg.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,6 @@ import octiconRepoTemplate from '../../public/img/svg/octicon-repo-template.svg'
1818
import octiconTriangleDown from '../../public/img/svg/octicon-triangle-down.svg';
1919
import octiconFile from '../../public/img/svg/octicon-file.svg';
2020

21-
import Vue from 'vue';
22-
2321
export const svgs = {
2422
'octicon-chevron-down': octiconChevronDown,
2523
'octicon-chevron-right': octiconChevronRight,
@@ -58,7 +56,8 @@ export function svg(name, size = 16, className = '') {
5856
return serializer.serializeToString(svgNode);
5957
}
6058

61-
export const SvgIcon = Vue.component('SvgIcon', {
59+
export const SvgIcon = {
60+
name: 'SvgIcon',
6261
props: {
6362
name: {type: String, required: true},
6463
size: {type: Number, default: 16},
@@ -72,4 +71,4 @@ export const SvgIcon = Vue.component('SvgIcon', {
7271
},
7372

7473
template: `<span v-html="svg" />`
75-
});
74+
};

webpack.config.js

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,12 @@ import AddAssetPlugin from 'add-asset-webpack-plugin';
44
import LicenseCheckerWebpackPlugin from 'license-checker-webpack-plugin';
55
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
66
import MonacoWebpackPlugin from 'monaco-editor-webpack-plugin';
7-
import VueLoader from 'vue-loader';
7+
import {VueLoaderPlugin} from 'vue-loader';
88
import EsBuildLoader from 'esbuild-loader';
99
import {parse, dirname} from 'path';
1010
import webpack from 'webpack';
1111
import {fileURLToPath} from 'url';
1212

13-
const {VueLoaderPlugin} = VueLoader;
1413
const {ESBuildMinifyPlugin} = EsBuildLoader;
1514
const {SourceMapDevToolPlugin} = webpack;
1615
const glob = (pattern) => fastGlob.sync(pattern, {
@@ -228,9 +227,6 @@ export default {
228227
},
229228
resolve: {
230229
symlinks: false,
231-
alias: {
232-
vue$: 'vue/dist/vue.esm.js', // needed because vue's default export is the runtime only
233-
},
234230
},
235231
watchOptions: {
236232
ignored: [

0 commit comments

Comments
 (0)