diff --git a/README.md b/README.md
index 079d7f2..33b3744 100755
--- a/README.md
+++ b/README.md
@@ -72,6 +72,7 @@ See [live demo](https://codesandbox.io/s/nuxt-components-cou9k) or [video exampl
### Lazy Imports
Nuxt by default does code-splitting per page and components. But sometimes we also need to lazy load them:
+
- Component size is rather big (or has big dependencies imported) like a text-editor
- Component is rendered conditionally with `v-if` or being in a modal
@@ -88,18 +89,18 @@ You now can easily import a component on-demand:
```
@@ -127,10 +128,7 @@ For clarity, it is recommended that component file name matches its name. You ca
If for any reason different prefix is desired, we can add specific directory with the `prefix` option: (See [directories](#directories) section)
```js
-components: [
- '~/components/',
- { path: '~/components/foo/', prefix: 'foo' }
-]
+components: ['~/components/', { path: '~/components/foo/', prefix: 'foo' }]
```
## Overwriting Components
@@ -169,7 +167,7 @@ export default {
components: [
'~/components', // shortcut to { path: '~/components' }
{ path: '~/components/awesome/', prefix: 'awesome' }
- ],
+ ]
}
```
@@ -210,15 +208,13 @@ If you prefer to split your SFCs into `.js`, `.vue` and `.css`, you can only ena
```js
// nuxt.config.js
export default {
- components: [
- { path: '~/components', extensions: ['vue'] }
- ]
+ components: [{ path: '~/components', extensions: ['vue'] }]
}
```
#### pattern
-- Type: `string` ([glob pattern]( https://github.com/isaacs/node-glob#glob-primer))
+- Type: `string` ([glob pattern](https://github.com/isaacs/node-glob#glob-primer))
- Default: `**/*.${extensions.join(',')}`
Accept Pattern that will be run against specified `path`.
@@ -226,7 +222,7 @@ Accept Pattern that will be run against specified `path`.
#### ignore
- Type: `Array`
-- Items: `string` ([glob pattern]( https://github.com/isaacs/node-glob#glob-primer))
+- Items: `string` ([glob pattern](https://github.com/isaacs/node-glob#glob-primer))
- Default: `[]`
Ignore patterns that will be run against specified `path`.
@@ -244,8 +240,8 @@ Example below adds `awesome-`/`Awesome` prefix to the name of components in `awe
// nuxt.config.js
export default {
components: [
- '~/components',
- { path: '~/components/awesome/', prefix: 'awesome' }
+ '~/components',
+ { path: '~/components/awesome/', prefix: 'awesome' }
]
}
```
@@ -261,7 +257,7 @@ components/
Click on me 🤘
-
+
```
@@ -298,7 +294,7 @@ Level are use to define a hint when overwriting the components which have the sa
export default {
components: [
'~/components', // default level is 0
- { path: 'my-theme/components', level: 1 }
+ { path: 'my-theme/components', level: 1 }
]
}
```
@@ -314,9 +310,7 @@ These properties are used in production to configure how [components with `Lazy`
```js
export default {
- components: [
- { path: 'my-theme/components', prefetch: true }
- ]
+ components: [{ path: 'my-theme/components', prefetch: true }]
}
```
@@ -330,6 +324,13 @@ const componets = {
}
```
+#### isAsync
+
+- Type: Boolean
+- Default: `false` unless component name ends with `.async.vue`
+
+This flag indicates, component should be loaded async (with a seperate chunk) regardless of using `Lazy` prefix or not.
+
## Migration guide
## `v1` to `v2`
@@ -337,9 +338,9 @@ const componets = {
Starting with `nuxt@2.15`, Nuxt uses `@nuxt/components` v2:
- All components are globally available so you can move `components/global/`
-to `components/` and `global: true` is not required anymore
+ to `components/` and `global: true` is not required anymore
- Full path inside `components` is used to prefix component names. If you were structing your
-components in multiple directories, should either add prefix or register in `components` section of `nuxt.config` or use new `pathPrefix` option.
+ components in multiple directories, should either add prefix or register in `components` section of `nuxt.config` or use new `pathPrefix` option.
**Example:**
@@ -363,7 +364,7 @@ export default {
'~/components/templates',
'~/components/atoms',
'~/components/molecules',
- '~/components/organisms',
+ '~/components/organisms'
]
}
```
@@ -393,8 +394,8 @@ Then in `awesome-ui/nuxt.js` you can use the `components:dir` hook:
```js
import { join } from 'path'
-export default function () {
- this.nuxt.hook('components:dirs', (dirs) => {
+export default function() {
+ this.nuxt.hook('components:dirs', dirs => {
// Add ./components dir to the list
dirs.push({
path: join(__dirname, 'components'),
@@ -408,10 +409,7 @@ That's it! Now in your project, you can import your ui library as a Nuxt module
```js
export default {
- buildModules: [
- '@nuxt/components',
- 'awesome-ui/nuxt'
- ]
+ buildModules: ['@nuxt/components', 'awesome-ui/nuxt']
}
```
@@ -438,15 +436,11 @@ Next: publish your `awesome-ui` module to [npm](https://www.npmjs.com) and share
[npm-version-src]: https://img.shields.io/npm/v/@nuxt/components/latest.svg?style=flat-square
[npm-version-href]: https://npmjs.com/package/@nuxt/components
-
[npm-downloads-src]: https://img.shields.io/npm/dt/@nuxt/components.svg?style=flat-square
[npm-downloads-href]: https://npmjs.com/package/@nuxt/components
-
[github-actions-ci-src]: https://img.shields.io/github/workflow/status/nuxt/typescript/test?label=ci&style=flat-square
[github-actions-ci-href]: https://github.com/nuxt/components/actions?query=workflow%3Aci
-
[codecov-src]: https://img.shields.io/codecov/c/github/nuxt/components.svg?style=flat-square
[codecov-href]: https://codecov.io/gh/nuxt/components
-
[license-src]: https://img.shields.io/npm/l/@nuxt/components.svg?style=flat-square
[license-href]: https://npmjs.com/package/@nuxt/components
diff --git a/package.json b/package.json
index f9d6893..35af333 100644
--- a/package.json
+++ b/package.json
@@ -19,7 +19,7 @@
],
"scripts": {
"build": "siroc build",
- "dev": "nuxt-ts test/fixture",
+ "dev": "nuxt dev test/fixture",
"lint": "eslint --ext .ts,.js,.vue .",
"prepare": "yarn link && yarn link @nuxt/components",
"prepublishOnly": "yarn build",
diff --git a/src/index.ts b/src/index.ts
index 10fc6db..36f4ba8 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -74,6 +74,7 @@ const componentsModule: Module = function () {
path: dirPath,
extensions,
pattern: dirOptions.pattern || `**/*.{${extensions.join(',')},}`,
+ isAsync: dirOptions.isAsync ?? !nuxt.options.dev /* async only for prod by default */,
// TODO: keep test/unit/utils.ts updated
ignore: [
'**/*.stories.{js,ts,jsx,tsx}', // ignore storybook files
diff --git a/src/loader.ts b/src/loader.ts
index e454332..124d66e 100644
--- a/src/loader.ts
+++ b/src/loader.ts
@@ -4,7 +4,7 @@ import { matcher } from './scan'
import type { Component } from './types'
function install (this: WebpackLoader.LoaderContext, content: string, components: Component[]) {
- const imports = '{' + components.map(c => `${c.pascalName}: ${c.import}`).join(',') + '}'
+ const imports = '{' + components.map(c => `${c.pascalName}: ${c.isAsync ? c.asyncImport : c.import}`).join(',') + '}'
let newContent = '/* nuxt-component-imports */\n'
newContent += `installComponents(component, ${imports})\n`
diff --git a/src/scan.ts b/src/scan.ts
index 4a11fce..18e8c82 100644
--- a/src/scan.ts
+++ b/src/scan.ts
@@ -17,7 +17,7 @@ export async function scanComponents (dirs: ScanDir[], srcDir: string): Promise<
const filePaths = new Set()
const scannedPaths: string[] = []
- for (const { path, pattern, ignore = [], prefix, extendComponent, pathPrefix, level, prefetch = false, preload = false } of dirs.sort(sortDirsByPathLength)) {
+ for (const { path, pattern, ignore = [], prefix, extendComponent, pathPrefix, level, prefetch = false, preload = false, isAsync: dirIsAsync } of dirs.sort(sortDirsByPathLength)) {
const resolvedNames = new Map()
for (const _file of await globby(pattern!, { cwd: path, ignore })) {
@@ -39,6 +39,8 @@ export async function scanComponents (dirs: ScanDir[], srcDir: string): Promise<
if (fileName.toLowerCase() === 'index') {
fileName = pathPrefix === false ? basename(dirname(filePath)) : '' /* inherits from path */
}
+ const isAsync = fileName.endsWith('.async') ? true : dirIsAsync
+ fileName = fileName.replace(/\.async$/, '')
const fileNameParts = splitByCase(fileName)
const componentNameParts: string[] = []
@@ -66,12 +68,13 @@ export async function scanComponents (dirs: ScanDir[], srcDir: string): Promise<
const shortPath = relative(srcDir, filePath)
const chunkName = 'components/' + kebabName
- let component = {
+ let component: Component = {
filePath,
pascalName,
kebabName,
chunkName,
shortPath,
+ isAsync,
import: '',
asyncImport: '',
export: 'default',
diff --git a/src/types.ts b/src/types.ts
index f59c983..bf2197a 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -6,7 +6,7 @@ export interface Component {
export: string
filePath: string
shortPath: string
- async?: boolean
+ isAsync?: boolean
chunkName: string
/** @deprecated */
global: boolean
@@ -20,6 +20,7 @@ export interface ScanDir {
pattern?: string | string[]
ignore?: string[]
prefix?: string
+ isAsync?: boolean
/** @deprecated */
global?: boolean | 'dev'
pathPrefix?: boolean
diff --git a/templates/components/index.js b/templates/components/index.js
index 494a6d7..6ebd6bd 100644
--- a/templates/components/index.js
+++ b/templates/components/index.js
@@ -1,17 +1,17 @@
import { wrapFunctional } from './utils'
<%= options.getComponents().map(c => {
- const exp = c.pascalName === c.export ? c.pascalName : `${c.export} as ${c.pascalName}`
- return `export { ${exp} } from '../${relativeToBuild(c.filePath)}'`
-}).join('\n') %>
-
-<%= options.getComponents().map(c => {
- const exp = c.export === 'default' ? `c.default || c` : `c['${c.export}']`
const magicComments = [
`webpackChunkName: "${c.chunkName}"`,
c.prefetch === true || typeof c.prefetch === 'number' ? `webpackPrefetch: ${c.prefetch}` : false,
c.preload === true || typeof c.preload === 'number' ? `webpackPreload: ${c.preload}` : false,
].filter(Boolean).join(', ')
-
- return `export const Lazy${c.pascalName} = import('../${relativeToBuild(c.filePath)}' /* ${magicComments} */).then(c => wrapFunctional(${exp}))`
+ if (c.isAsync) {
+ const exp = c.export === 'default' ? `c.default || c` : `c['${c.export}']`
+ const asyncImport = `import('../${relativeToBuild(c.filePath)}' /* ${magicComments} */).then(c => wrapFunctional(${exp}))`
+ return `export const ${c.pascalName} = ${asyncImport}`
+ } else {
+ const exp = c.export === 'default' ? `default as ${c.pascalName}` : c.pascalName
+ return `export { ${exp} } from '../${relativeToBuild(c.filePath)}'`
+ }
}).join('\n') %>
diff --git a/templates/components/plugin.js b/templates/components/plugin.js
index 3bdefa5..3394d07 100644
--- a/templates/components/plugin.js
+++ b/templates/components/plugin.js
@@ -1,22 +1,7 @@
import Vue from 'vue'
-import { wrapFunctional } from './utils'
-
-<% const components = options.getComponents() %>
-
-const components = {
-<%= components.map(c => {
- const exp = c.export === 'default' ? `c.default || c` : `c['${c.export}']`
- const magicComments = [
- `webpackChunkName: "${c.chunkName}"`,
- c.prefetch === true || typeof c.prefetch === 'number' ? `webpackPrefetch: ${c.prefetch}` : false,
- c.preload === true || typeof c.preload === 'number' ? `webpackPreload: ${c.preload}` : false,
- ].filter(Boolean).join(', ')
-
- return ` ${c.pascalName.replace(/^Lazy/, '')}: () => import('../${relativeToBuild(c.filePath)}' /* ${magicComments} */).then(c => wrapFunctional(${exp}))`
-}).join(',\n') %>
-}
+import * as components from './index'
for (const name in components) {
Vue.component(name, components[name])
- Vue.component('Lazy' + name, components[name])
+ Vue.component('Lazy' + name, () => Promise.resolve(components[name]))
}
diff --git a/templates/components/readme_md b/templates/components/readme_md
index 58b82e8..0100fe6 100644
--- a/templates/components/readme_md
+++ b/templates/components/readme_md
@@ -11,6 +11,7 @@ const components = options.getComponents()
const list = components.map(c => {
const pascalName = c.pascalName.replace(/^Lazy/, '')
const kebabName = c.kebabName.replace(/^lazy-/, '')
- return `- \`<${pascalName}>\` | \`<${kebabName}>\` (${c.shortPath})`
+ const tags = c.isAsync ? ' [async]' : ''
+ return `- \`<${pascalName}>\` | \`<${kebabName}>\` (${c.shortPath})${tags}`
})
%><%= list.join('\n') %>
diff --git a/test/fixture/components/global/Big.vue b/test/fixture/components/global/Big.async.vue
similarity index 100%
rename from test/fixture/components/global/Big.vue
rename to test/fixture/components/global/Big.async.vue
diff --git a/test/fixture/nuxt.config.ts b/test/fixture/nuxt.config.ts
index 52a8a64..1950b48 100644
--- a/test/fixture/nuxt.config.ts
+++ b/test/fixture/nuxt.config.ts
@@ -8,9 +8,13 @@ const config: NuxtConfig = {
nuxtComponents
],
+ typescript: {
+ typeCheck: false
+ },
+
components: [
'~/components',
- { path: '~/components/global', global: true },
+ { path: '~/components/global', global: true, isAsync: false },
{ path: '~/components/no-prefix', pathPrefix: false },
{ path: '~/components/multifile', extensions: ['vue'] },
'~/non-existent',