Notice: Function _load_textdomain_just_in_time was called incorrectly. Translation loading for the acf domain was triggered too early. This is usually an indicator for some code in the plugin or theme running too early. Translations should be loaded at the init action or later. Please see Debugging in WordPress for more information. (This message was added in version 6.7.0.) in /home/evomark/public_html/wp-includes/functions.php on line 6121

Warning: Cannot modify header information - headers already sent by (output started at /home/evomark/public_html/wp-includes/functions.php:6121) in /home/evomark/public_html/wp-includes/rest-api/class-wp-rest-server.php on line 1896

Warning: Cannot modify header information - headers already sent by (output started at /home/evomark/public_html/wp-includes/functions.php:6121) in /home/evomark/public_html/wp-includes/rest-api/class-wp-rest-server.php on line 1896

Warning: Cannot modify header information - headers already sent by (output started at /home/evomark/public_html/wp-includes/functions.php:6121) in /home/evomark/public_html/wp-includes/rest-api/class-wp-rest-server.php on line 1896

Warning: Cannot modify header information - headers already sent by (output started at /home/evomark/public_html/wp-includes/functions.php:6121) in /home/evomark/public_html/wp-includes/rest-api/class-wp-rest-server.php on line 1896

Warning: Cannot modify header information - headers already sent by (output started at /home/evomark/public_html/wp-includes/functions.php:6121) in /home/evomark/public_html/wp-includes/rest-api/class-wp-rest-server.php on line 1896

Warning: Cannot modify header information - headers already sent by (output started at /home/evomark/public_html/wp-includes/functions.php:6121) in /home/evomark/public_html/wp-includes/rest-api/class-wp-rest-server.php on line 1896

Warning: Cannot modify header information - headers already sent by (output started at /home/evomark/public_html/wp-includes/functions.php:6121) in /home/evomark/public_html/wp-includes/rest-api/class-wp-rest-server.php on line 1896

Warning: Cannot modify header information - headers already sent by (output started at /home/evomark/public_html/wp-includes/functions.php:6121) in /home/evomark/public_html/wp-includes/rest-api/class-wp-rest-server.php on line 1896
{"id":785,"date":"2024-12-06T09:04:00","date_gmt":"2024-12-06T09:04:00","guid":{"rendered":"https:\/\/evomark.co.uk\/?page_id=785"},"modified":"2024-12-05T16:05:40","modified_gmt":"2024-12-05T16:05:40","slug":"vue-auto-vite-components","status":"publish","type":"page","link":"https:\/\/evomark.co.uk\/open-source-software\/vue-auto-vite-components\/","title":{"rendered":"Vue Auto Vite Components"},"content":{"rendered":"\n

Having a separate component for every task in Vue makes it amazingly simple to keep logic grouped together in a way that makes code-maintenance a breeze.<\/p>\n\n\n\n

Less fun, though, is having to write a dozen lines of imports inside every Single File Component in Vue. Even worse if you want those imports to be loaded asynchronously.<\/p>\n\n\n\n

Existing Solutions<\/h2>\n\n\n\n

If you’re using Nuxt, you’ll have automatic component registration\/loading out-of-the-box. For everyone else, there’s Unplugin Auto Components<\/a>. There’s just one problem here, every one of your components is registered as a synchronous component. This is fine for smaller apps, but for the bigger projects, that means every one of your components has to be loaded before anything can show.<\/p>\n\n\n\n

Our Different Approach<\/h2>\n\n\n\n

We decided to let users split their components into loading strategy by folder: sync, async and web.<\/p>\n\n\n\n

Sync components are loaded immediately and best for high-use components or ones that are need for common landing pages.<\/p>\n\n\n\n

Async components are registered with defineAsyncComponent<\/code> and therefore do not download until they are detected in your markup. You can also specify a custom loader component which can be useful for long-hydration elements.<\/p>\n\n\n\n

Finally, web components are a special case which registers the SFC as a native web-component. These files must use .ce.vue<\/code> extensions.<\/p>\n\n\n\n

Installation<\/h2>\n\n\n\n
\/\/ PNPM<\/span><\/div>
<\/span>pnpm<\/span> <\/span>add<\/span> vue3-auto-vite-components<\/span><\/div>
\n<\/span><\/div>
\/\/ NPM<\/span><\/div>
<\/span>npm<\/span> i vue3-auto-vite-components<\/span><\/div>
\n<\/span><\/div>
\/\/ Yarn<\/span><\/div>
<\/span>yarn<\/span> <\/span>add<\/span> vue3-auto-vite-components<\/span><\/div><\/code><\/pre><\/div>\n\n\n\n

Usage<\/h2>\n\n\n\n

This plugin should be used before your app is mounted.<\/p>\n\n\n\n

import<\/span> <\/span>{<\/span> createApp <\/span>}<\/span> <\/span>from<\/span> <\/span>\"vue\"<\/span>;<\/span><\/span><\/div>
<\/span>import<\/span> <\/span>App<\/span> <\/span>from<\/span> <\/span>\".\/App.vue\"<\/span>;<\/span><\/span><\/div>
<\/span>import<\/span> <\/span>{<\/span> registerComponents <\/span>}<\/span> <\/span>from<\/span> <\/span>\"vue3-auto-vite-components\"<\/span>;<\/span><\/span><\/div>
\n<\/span><\/div>
<\/span>createApp<\/span>(<\/span>App<\/span>)<\/span><\/span><\/div>
<\/span>.<\/span>use<\/span>(<\/span>registerComponents<\/span>,<\/span> <\/span>{<\/span><\/span><\/div>
\t<\/span>namespace<\/span>:<\/span> <\/span>\"Evo\"<\/span>,<\/span><\/span><\/div>
\t<\/span>sync<\/span>:<\/span> <\/span>import<\/span>.<\/span>meta<\/span>.<\/span>glob<\/span>(<\/span>\".\/components\/sync\/**\/*.vue\"<\/span>,<\/span> <\/span>{<\/span> <\/span>eager<\/span>:<\/span> <\/span>true<\/span> <\/span>}<\/span>)<\/span>,<\/span><\/span><\/div>
\t<\/span>async<\/span>:<\/span> <\/span>import<\/span>.<\/span>meta<\/span>.<\/span>glob<\/span>(<\/span>\".\/components\/async\/**\/*.vue\"<\/span>,<\/span> <\/span>{<\/span> <\/span>eager<\/span>:<\/span> <\/span>false<\/span> <\/span>}<\/span>)<\/span>,<\/span><\/span><\/div>
\t<\/span>asyncLoading<\/span>:<\/span> <\/span>import<\/span>.<\/span>meta<\/span>.<\/span>glob<\/span>(<\/span>\".\/components\/async\/**\/*Loading.vue\"<\/span>,<\/span> <\/span>{<\/span><\/span><\/div>
\t\t<\/span>eager<\/span>:<\/span> <\/span>true<\/span>,<\/span><\/span><\/div>
\t<\/span>}<\/span>)<\/span>,<\/span><\/span><\/div>
\t<\/span>web<\/span>:<\/span> <\/span>import<\/span>.<\/span>meta<\/span>.<\/span>glob<\/span>(<\/span>\".\/components\/web\/**\/*.vue\"<\/span>,<\/span> <\/span>{<\/span> <\/span>eager<\/span>:<\/span> <\/span>true<\/span> <\/span>}<\/span>)<\/span><\/span><\/div>
<\/span>}<\/span>)<\/span><\/span><\/div>
<\/span>.<\/span>mount<\/span>(<\/span>'#app'<\/span>)<\/span>;<\/span><\/div><\/code><\/pre><\/div>\n\n\n\n

Pay special attention to the eager<\/code> prop that is passed to the Vite glob loader.<\/p>\n\n\n\n

Namespace<\/h2>\n\n\n\n

In the code above, we pass \u201cEvo\u201d as a namespace. This means that every component registered is prefixed with it. For sync\/async components, that will be EvoComponent<\/code> and for web components, that will equal evo-component<\/code>.<\/p>\n\n\n\n

Name Resolution (Sync\/Async)<\/h2>\n\n\n\n

No distinction is made between async and sync components when generating a name (we wanted to make it easy to move them from one folder to the other without changing the component name) so don\u2019t have the same component in the same folder path in both async and sync globs.<\/p>\n\n\n\n

The final name of your component comprises three parts: the namespace, the path, and your component\u2019s name.<\/p>\n\n\n\n

Using the above, a component inside .\/components\/sync\/layout\/header\/Menu.vue<\/code> would be registered with the component name EvoLayoutHeaderMenu<\/code>.<\/p>\n\n\n\n

Or if you had .\/components\/async\/nav-items\/footer\/SocialLinks.vue<\/code>, then your registered component name would be EvoNavItemsFooterSocialLinks<\/code>.<\/p>\n\n\n\n

Note that any hyphens, underscores or spaces in your folder names are automatically converted to PascalCase.<\/p>\n\n\n\n

Async Loading Components<\/h2>\n\n\n\n

You can pass a separate asyncLoading<\/code> glob to the plugin options. When resolving an async component, the same location is checked for a Loading<\/code> component which is used while waiting for your async component to load. A common use of these is to show skeleton loaders while more complex components are initiated. See the Vue documentation<\/a> for more details.<\/p>\n\n\n\n

Using the SocialLinks component example above, the plugin would check if .\/components\/async\/nav-items\/footer\/SocialLinksLoading.vue<\/code> existed, and if so, this would be used as a loading component.<\/p>\n\n\n\n

Name Resolution (Web Components)<\/h2>\n\n\n\n

Vue and Vite can also be used to create web components \/ custom elements<\/a>. Since these are extended HTML elements, the names are resolved slightly differently.<\/p>\n\n\n\n

A component inside .\/components\/web\/layout\/Header.ce.vue<\/code> would be registered as <evo-layout-header><\/evo-layout-header><\/code>.<\/p>\n\n\n\n

Suggestions and Feedback<\/h2>\n\n\n\n

If you have any suggestions about this plugin or spot any issues, feel free to use our GitHub repository<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"

Having a separate component for every task in Vue makes it amazingly simple to keep logic grouped together in a way that makes code-maintenance a breeze. Less fun, though, is having to write a dozen lines of imports inside every Single File Component in Vue. Even worse if you want those imports to be loaded…<\/p>\n","protected":false},"author":2,"featured_media":786,"parent":218,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"templates\/open-source-software.php","meta":{"_acf_changed":false,"footnotes":""},"class_list":["post-785","page","type-page","status-publish","has-post-thumbnail","hentry"],"acf":[],"_links":{"self":[{"href":"https:\/\/evomark.co.uk\/wp-json\/wp\/v2\/pages\/785","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/evomark.co.uk\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/evomark.co.uk\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/evomark.co.uk\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/evomark.co.uk\/wp-json\/wp\/v2\/comments?post=785"}],"version-history":[{"count":1,"href":"https:\/\/evomark.co.uk\/wp-json\/wp\/v2\/pages\/785\/revisions"}],"predecessor-version":[{"id":787,"href":"https:\/\/evomark.co.uk\/wp-json\/wp\/v2\/pages\/785\/revisions\/787"}],"up":[{"embeddable":true,"href":"https:\/\/evomark.co.uk\/wp-json\/wp\/v2\/pages\/218"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/evomark.co.uk\/wp-json\/wp\/v2\/media\/786"}],"wp:attachment":[{"href":"https:\/\/evomark.co.uk\/wp-json\/wp\/v2\/media?parent=785"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}