Skip to content

Commit

Permalink
Update vue 3 template.
Browse files Browse the repository at this point in the history
Add fontawesome and vee-validate by default.
  • Loading branch information
ryanelian committed Apr 7, 2021
1 parent 9751b71 commit 6bf4e46
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 43 deletions.
4 changes: 2 additions & 2 deletions templates/vue3/client/js/components/Hello.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { computed, defineComponent, ref } from 'vue';
export default defineComponent({
props: {
language: {
sdk: {
type: String,
required: true
},
Expand All @@ -36,7 +36,7 @@ export default defineComponent({
};
// https://v3.vuejs.org/guide/composition-api-introduction.html#standalone-computed-properties
const message = computed(() => `Hello from ${props.language} and ${props.compiler}!`);
const message = computed(() => `Hello from ${props.sdk} and ${props.compiler}!`);
// Everything that are returned will be exposed to the component template!
return {
Expand Down
8 changes: 8 additions & 0 deletions templates/vue3/client/js/icons.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { library } from '@fortawesome/fontawesome-svg-core';
import { faChevronUp, faCheck } from '@fortawesome/free-solid-svg-icons';
import { } from '@fortawesome/free-regular-svg-icons';

library.add(faChevronUp, faCheck);

// Reduce dll size by only importing icons which are actually being used:
// https://fontawesome.com/how-to-use/use-with-node-js
1 change: 1 addition & 0 deletions templates/vue3/client/js/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ import 'ts-polyfill/lib/es2019-object';
import 'ts-polyfill/lib/es2019-string';
import 'ts-polyfill/lib/es2020-string';

import './icons';
import './vue-project';
47 changes: 24 additions & 23 deletions templates/vue3/client/js/vue-project.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
import * as Vue from 'vue';
import Vue from 'vue';
import { renderAsyncComponent } from './vue-renderer';

type VueAsync = () => Promise<typeof import('*.vue')>;
import { defineRule, Form, Field } from 'vee-validate';
import AllRules from '@vee-validate/rules';
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';

function renderAsyncComponent(tag: string, factory: VueAsync) {
const ac = Vue.defineAsyncComponent(factory);
const elements = document.getElementsByTagName(tag);

for (const e of elements) {
const props: Record<string, unknown> = {};
// enable passing HTML attributes as component props
if (e.hasAttributes()) {
for (const attr of e.attributes) {
if (attr.name.startsWith(':')) {
props[attr.name.substr(1)] = JSON.parse(attr.value);
} else {
// simple string
props[attr.name] = attr.value;
}
}
}
// define validation rules
Object.keys(AllRules).forEach(rule => {
defineRule(rule, AllRules[rule]);
});

const app = Vue.createApp(ac, props);
app.mount(e);
}
/**
* allows declaring components that can be used in all components.
* usually these components are third-party libraries
* or any first-party reusable components such as a custom submit button.
* @param app
*/
function configure(app: Vue.App) {
// https://v3.vuejs.org/style-guide/#component-name-casing-in-templates-strongly-recommended
app.component('fa-icon', FontAwesomeIcon);
app.component('vv-form', Form);
app.component('vv-field', Field);
}

renderAsyncComponent('Hello', () => import('./components/Hello.vue'));
// use this file to render top-level components asynchronously.

// for example: allows calling <Hello sdk="instapack" language="vue"></Hello> in HTML!
renderAsyncComponent('Hello', () => import('./components/Hello.vue'), configure);
54 changes: 54 additions & 0 deletions templates/vue3/client/js/vue-renderer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import Vue from 'vue';

type VueAsync = () => Promise<typeof import('*.vue')>;

type ConfigureVueApp = (app: Vue.App<Element>) => void;

/**
* Convert a hyphenated string to camelCase.
*/
function hyphenToCamelCase(name: string) {
return name.replace(/-(.)/g, (_match: string, char: string) => {
return char.toUpperCase();
});
}

/**
* Attempts to extract element attributes as string map.
* @param el
* @returns
*/
function convertElementAttributesToPropsMap(el: Element): Record<string, string> {
if (el.hasAttributes() === false) {
return {};
}
const result: Record<string, string> = {};

for (const attribute of el.attributes) {
const name = hyphenToCamelCase(attribute.name);
result[name] = attribute.value;
}

return result;
}

/**
* For each matching HTML Elements, render and mount a Vue Component asynchronously.
* Passes Element attributes as string to props. Kebab-case attributes will be converted to camel-case.
* @param tag
* @param factory
* @param configure
*/
export function renderAsyncComponent(tag: string, factory: VueAsync, configure?: ConfigureVueApp) {
const ac = Vue.defineAsyncComponent(factory);
const elements = document.getElementsByTagName(tag);

for (const el of elements) {
const props = convertElementAttributesToPropsMap(el)
const app = Vue.createApp(ac, props);
if (configure) {
configure(app);
}
app.mount(el);
}
}
40 changes: 22 additions & 18 deletions templates/vue3/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,32 @@
"output": "wwwroot"
},
"dependencies": {
"@types/luxon": "^1.25.0",
"@types/requirejs": "^2.1.32",
"axios": "^0.21.0",
"bootstrap": "^4.5.3",
"jquery": "^3.5.1",
"@fortawesome/fontawesome-svg-core": "^1.2.35",
"@fortawesome/free-regular-svg-icons": "^5.15.3",
"@fortawesome/free-solid-svg-icons": "^5.15.3",
"@fortawesome/vue-fontawesome": "3.0.0-3",
"@popperjs/core": "^2.9.2",
"@types/luxon": "^1.26.3",
"@vee-validate/rules": "^4.1.20",
"axios": "^0.21.1",
"bootstrap": "5.0.0-beta3",
"linq": "^3.2.3",
"luxon": "^1.25.0",
"popper.js": "^1.16.1",
"sweetalert2": "^10.10.1",
"luxon": "^1.26.0",
"sweetalert2": "^10.15.7",
"ts-polyfill": "^3.8.2",
"tslib": "^2.0.3",
"tslib": "^2.2.0",
"vee-validate": "^4.2.4",
"vue": "^3.0.2"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "4.8.1",
"@typescript-eslint/parser": "4.8.1",
"@vue/compiler-sfc": "3.0.2",
"eslint": "7.13.0",
"eslint-config-prettier": "^6.15.0",
"eslint-plugin-vue": "^7.1.0",
"typescript": "^4.1.2",
"vue-eslint-parser": "^7.1.1",
"vue-loader": "16.0.0-rc.2"
"@typescript-eslint/eslint-plugin": "4.21.0",
"@typescript-eslint/parser": "4.21.0",
"@vue/compiler-sfc": "3.0.11",
"eslint": "7.23.0",
"eslint-config-prettier": "^8.1.0",
"eslint-plugin-vue": "^7.8.0",
"typescript": "^4.2.3",
"vue-eslint-parser": "^7.6.0",
"vue-loader": "16.2.0"
}
}

0 comments on commit 6bf4e46

Please sign in to comment.