fix(nuxt3): import top-level files and subdirectory indices (#2774)

This commit is contained in:
Daniel Roe 2022-01-18 16:43:41 +00:00 committed by GitHub
parent 8588f749ad
commit b38e394dfe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 56 additions and 15 deletions

View File

@ -12,6 +12,23 @@ Nuxt will automatically read the files in your `plugins` directory and load them
All plugins in your `plugins/` directory are auto-registered, so you should not add them to your `nuxt.config` separately. All plugins in your `plugins/` directory are auto-registered, so you should not add them to your `nuxt.config` separately.
:: ::
## Which files are registered
Only files at the top level of the `plugins/` directory (or index files within any subdirectories) will be registered as plugins.
For example:
```bash
plugins
| - myPlugin.ts
| - myOtherPlugin
| --- supportingFile.ts
| --- componentToRegister.vue
| --- index.ts
```
Only `myPlugin.ts` and `myOtherPlugin/index.ts` would be registered.
## Creating plugins ## Creating plugins
The only argument passed to a plugin is [`nuxtApp`](/docs/usage/nuxt-app). The only argument passed to a plugin is [`nuxtApp`](/docs/usage/nuxt-app).

View File

@ -8,7 +8,23 @@ head.title: Composables directory
Nuxt 3 supports `composables/` directory to automatically import your Vue composables into your application using auto-imports! Nuxt 3 supports `composables/` directory to automatically import your Vue composables into your application using auto-imports!
Example: (using named export) ## How files are scanned
Only files at the top level of the `composables/` directory (or index files within any subdirectories) will be scanned for composables.
For example:
```bash
composables
| - useFoo.ts
| - useBar
| --- supportingFile.ts
| --- index.ts
```
Only `useFoo.ts` and `useBar/index.ts` would be searched for imports - and if the latter is a default export, it would be registered as `useBar` rather than `index`.
## Example: (using named export)
```js [composables/useFoo.ts] ```js [composables/useFoo.ts]
import { useState } from '#app' import { useState } from '#app'
@ -18,7 +34,7 @@ export const useFoo = () => {
} }
``` ```
Example: (using default export) ## Example: (using default export)
```js [composables/use-foo.ts or composables/useFoo.ts] ```js [composables/use-foo.ts or composables/useFoo.ts]
import { useState } from '#app' import { useState } from '#app'

View File

@ -104,7 +104,7 @@ export function tryResolvePath (path: string, opts: ResolveOptions = {}) {
} }
} }
export async function resolveFiles (path: string, pattern: string) { export async function resolveFiles (path: string, pattern: string | string[]) {
const files = await globby(pattern, { const files = await globby(pattern, {
cwd: path, cwd: path,
followSymbolicLinks: true followSymbolicLinks: true

View File

@ -1,37 +1,42 @@
import { promises as fsp, existsSync } from 'fs' import { promises as fsp, existsSync } from 'fs'
import { parse as parsePath, join } from 'pathe' import { parse as parsePath } from 'pathe'
import { globby } from 'globby'
import { findExports } from 'mlly' import { findExports } from 'mlly'
import { camelCase } from 'scule' import { camelCase } from 'scule'
import { AutoImport } from '@nuxt/schema' import { AutoImport } from '@nuxt/schema'
import { resolveFiles } from '@nuxt/kit'
import { filterInPlace } from './utils' import { filterInPlace } from './utils'
export async function scanForComposables (dir: string, autoImports: AutoImport[]) { export async function scanForComposables (dir: string, autoImports: AutoImport[]) {
if (!existsSync(dir)) { return } if (!existsSync(dir)) { return }
const files = await globby(['*.{ts,js,tsx,jsx,mjs,cjs,mts,cts}'], { cwd: dir }) const files = await resolveFiles(dir, [
'*.{ts,js,mjs,cjs,mts,cts}',
'*/index.{ts,js,mjs,cjs,mts,cts}'
])
await Promise.all( await Promise.all(
files.map(async (file) => { files.map(async (path) => {
const importPath = join(dir, file)
// Remove original entries from the same import (for build watcher) // Remove original entries from the same import (for build watcher)
filterInPlace(autoImports, i => i.from !== importPath) filterInPlace(autoImports, i => i.from !== path)
const code = await fsp.readFile(join(dir, file), 'utf-8') const code = await fsp.readFile(path, 'utf-8')
const exports = findExports(code) const exports = findExports(code)
const defaultExport = exports.find(i => i.type === 'default') const defaultExport = exports.find(i => i.type === 'default')
if (defaultExport) { if (defaultExport) {
autoImports.push({ name: 'default', as: camelCase(parsePath(file).name), from: importPath }) let name = parsePath(path).name
if (name === 'index') {
name = parsePath(path.split('/').slice(0, -1).join('/')).name
}
autoImports.push({ name: 'default', as: camelCase(name), from: path })
} }
for (const exp of exports) { for (const exp of exports) {
if (exp.type === 'named') { if (exp.type === 'named') {
for (const name of exp.names) { for (const name of exp.names) {
autoImports.push({ name, as: name, from: importPath }) autoImports.push({ name, as: name, from: path })
} }
} else if (exp.type === 'declaration') { } else if (exp.type === 'declaration') {
autoImports.push({ name: exp.name, as: exp.name, from: importPath }) autoImports.push({ name: exp.name, as: exp.name, from: path })
} }
} }
}) })

View File

@ -73,7 +73,10 @@ export async function resolveApp (nuxt: Nuxt, app: NuxtApp) {
// Resolve plugins // Resolve plugins
app.plugins = [ app.plugins = [
...nuxt.options.plugins, ...nuxt.options.plugins,
...await resolveFiles(nuxt.options.srcDir, 'plugins/**/*.{js,ts,mjs,cjs}') ...await resolveFiles(nuxt.options.srcDir, [
'plugins/*.{ts,js,mjs,cjs,mts,cts}',
'plugins/*/index.*{ts,js,mjs,cjs,mts,cts}'
])
].map(plugin => normalizePlugin(plugin)) ].map(plugin => normalizePlugin(plugin))
// Extend app // Extend app