Skip to content

Commit 5e3d1a7

Browse files
committed
feat: Async components with Lazy prefix
Add support for lazy loading components, this is useful for performance optimisations.
1 parent 50680be commit 5e3d1a7

File tree

9 files changed

+67
-12
lines changed

9 files changed

+67
-12
lines changed

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,22 @@ Use them in any `.vue` as you would normally. Access your components with either
5151
Remove `imports` and `components` from the `script` section.
5252

5353

54+
### Async Component Loading
55+
56+
You can load your components async by prefixing your component name with `Lazy` or `lazy-`, depending on your
57+
syntax.
58+
59+
```html
60+
<template>
61+
<div>
62+
<!-- ComponentFoo will be loaded in async -->
63+
<LazyComponentFoo />
64+
<!-- ComponentBar will be loaded sync -->
65+
<ComponentBar />
66+
</div>
67+
</template>
68+
```
69+
5470
## Configuration
5571

5672
You can change the behaviour of the plugin by modifying the options in `./vue.config.js`.

examples/vue2/src/App.vue

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -111,22 +111,25 @@
111111
<v-btn>Test</v-btn>
112112
</td>
113113
</tr>
114+
<tr>
115+
<td>
116+
<code>Lazy Component</code>
117+
</td>
118+
<td>
119+
<lazy-lazy-component>Test</lazy-lazy-component>
120+
</td>
121+
</tr>
114122
</table>
115123
</v-main>
116124
</v-app>
117125
</div>
118126
</template>
119127

120128
<script>
121-
import HelloWorld from './components/HelloWorld';
122129
123130
export default {
124131
name: 'App',
125132
126-
components: {
127-
HelloWorld,
128-
},
129-
130133
data: () => ({
131134
//
132135
}),
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<template>
2+
<div>
3+
I should be lazy ✅
4+
</div>
5+
</template>

examples/vue3/src/App.vue

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,10 +78,17 @@
7878
</ValidationObserver>
7979
</td>
8080
</tr>
81+
<tr>
82+
<td>
83+
<code>Lazy Component</code>
84+
</td>
85+
<td>
86+
<lazy-lazy-component>Test</lazy-lazy-component>
87+
</td>
88+
</tr>
8189

8290
</table>
8391
</template>
84-
8592
<style>
8693
#app {
8794
font-family: Avenir, Helvetica, Arial, sans-serif;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<template>
2+
<div>
3+
I should be lazy ✅
4+
</div>
5+
</template>

src/loader.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,24 @@ export default async function loader(this: webpackLoader.LoaderContext, source:
2525
// make sure cache invalidation and recompile in watch mode
2626
scannedComponents.forEach(c => this.addDependency(c.filePath))
2727

28+
const generateLazyLoadImport = (c: Component) => {
29+
if (options.vueVersion === 3)
30+
return `Lazy${c.pascalName}: defineAsyncComponent(() => import('${c.shortPath.replace(';', '')}'))`
31+
32+
return `Lazy${c.pascalName}: () => import('${c.shortPath.replace(';', '')}')`
33+
}
34+
35+
const componentsWithLazyImports = scannedComponents.map(c => [c, {
36+
...c,
37+
pascalName: `Lazy${c.pascalName}`,
38+
import: generateLazyLoadImport(c),
39+
kebabName: `lazy-${c.kebabName}`,
40+
lazy: true,
41+
} as Component])
42+
.flat()
43+
2844
// the components to import
29-
const components: Component[] = matcher(tags, scannedComponents)
45+
const components: Component[] = matcher(tags, componentsWithLazyImports)
3046

3147
// only if we have components to inject
3248
if (components.length <= 0)

src/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export interface Component {
66
import: string
77
filePath: string
88
shortPath: string
9+
lazy: boolean | undefined
910
}
1011

1112
export enum Extensions {

src/vue2/injectComponents.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ export default function injectComponents(this: webpackLoader.LoaderContext, sour
1010
const injectScript
1111
= `/* vue-cli-plugin-import-components */
1212
${installComponentRuntime}
13-
${components.map(c => c.import).join('\n')}
14-
vueCliInstallComponent(component, {${components.map(c => c.pascalName).join(', ')}});`
13+
${components.filter(c => !c.lazy).map(c => c.import).join('\n')}
14+
vueCliInstallComponent(component, {${components.map(c => c.lazy ? c.import : c.pascalName).join(', ')}});`
1515

1616
const hotReload = source.indexOf('/* hot reload */')
1717
if (hotReload > -1)

src/vue3/injectComponents.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
import { Component } from '../types'
22

33
function injectImports(variable: string, components: Component[]) {
4-
return `${variable}.components = Object.assign({}, { ${components.map(c => c.pascalName).join(', ')} }, ${variable}.components);`
4+
return `${variable}.components = Object.assign({}, { ${components.map(c => c.lazy ? c.import : c.pascalName).join(', ')} }, ${variable}.components);`
55
}
66

77
export default function injectComponents(source: string, components: Component[]) {
8+
const lazyCode = !source.includes('defineAsyncComponent') && components.filter(c => c.lazy).length > 0 ? 'import { defineAsyncComponent } from \'vue\'' : ''
9+
810
let newContent
9-
= `/* vue-cli-plugin-import-components */\n${
10-
components.map(c => c.import).join('\n')}\n${
11+
= `/* vue-cli-plugin-import-components */\n${lazyCode}\n${
12+
components.filter(c => !c.lazy).map(c => c.import).join('\n')}\n${
1113
injectImports('script', components)}`
1214

1315
// script.options is used by vue-property-decorator

0 commit comments

Comments
 (0)