Created
September 1, 2021 05:48
-
-
Save labocho/aba235958add38cf04e037b336c5021e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import type {VNode, VueConstructor} from "vue"; | |
import Vue from "vue"; | |
// eslint-disable-next-line @typescript-eslint/no-explicit-any | |
function mountView(el: Element, component: VueConstructor, properties: any, components: any): void { | |
// eslint-disable-next-line no-new | |
new Vue({ | |
components, | |
el, | |
render: (createElement): VNode => { | |
return createElement(component, {props: properties}); | |
}, | |
}); | |
} | |
interface ComponentMap { | |
[key: string]: VueConstructor | undefined; | |
} | |
const components: ComponentMap = {}; | |
const VueMounter = { | |
mount(): void { | |
const els = document.querySelectorAll("[data-vue-component]"); | |
for (let i = els.length - 1; i >= 0; i -= 1) { | |
const el = els[i]; | |
const componentName = el.getAttribute("data-vue-component")!.replace(/\//gu, "-"); | |
const component = components[componentName]; | |
const propJson = el.getAttribute("data-vue-properties"); | |
const properties = propJson === null ? {} : JSON.parse(propJson); | |
if (component === undefined) { | |
throw `Vue component '${componentName} did not registered. Add Shopboy.mounter.register('${componentName}', ${componentName})'`; | |
} | |
mountView(el, component, properties, {[componentName]: component}); | |
} | |
}, | |
register(cmps: ComponentMap): void { | |
for (const [name, component] of Object.entries(cmps)) { | |
components[name] = component; | |
} | |
}, | |
}; | |
// components 以下の .vue を自動でロードして VueMounter に登録 | |
// ./components/foo/bar.vue なら data-vue-component="foo/bar" でマウントできる | |
// https://vuejs.org/v2/guide/components-registration.html#Automatic-Global-Registration-of-Base-Components | |
interface RequireComponent { | |
(fileName: string): VueConstructor | {default: VueConstructor}; | |
keys: () => string[]; | |
} | |
interface NodeRequireWithContext extends NodeRequire { | |
context: (a: string, b: boolean, c: RegExp) => RequireComponent; | |
} | |
const requireComponent = (require as NodeRequireWithContext).context( | |
"./components", // The relative path of the components folder | |
true, // Whether or not to look in subfolders | |
/[a-z0-9_]+\.vue$/u, // The regular expression used to match base component filenames | |
); | |
requireComponent.keys().forEach((fileName: string) => { | |
const componentConfig = requireComponent(fileName); | |
const name = fileName.replace(/^\.\//u, "").replace(/\//gu, "-").replace(/\.vue$/u, ""); | |
// eslint-disable-next-line no-prototype-builtins | |
const component = componentConfig.hasOwnProperty("default") ? (componentConfig as {default: VueConstructor}).default : componentConfig as VueConstructor; | |
VueMounter.register({[name]: component}); | |
}); | |
export {VueMounter}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment