Compare commits

...

16 Commits

Author SHA1 Message Date
Joaquín Sánchez
9df517bdf3
Merge cf14552c5e into 9bf8465806 2024-11-19 23:30:26 +02:00
Jan-Niklas W.
9bf8465806
docs: update getting started to include WebStorm (#29845) 2024-11-19 20:39:14 +00:00
renovate[bot]
f94d3f2bc6
chore(deps): update resolutions @types/node to v22.9.1 (main) (#29981)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-19 15:32:36 -05:00
renovate[bot]
9c8cd4b74b
chore(deps): update devdependency eslint-plugin-perfectionist to v4 (main) (#29982)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Daniel Roe <daniel@roe.dev>
2024-11-19 15:32:33 -05:00
Daniel Roe
cf14552c5e
Merge remote-tracking branch 'origin/main' into feat-add-auto-import-directives 2024-11-02 23:44:08 +00:00
Daniel Roe
93722c95e5
Merge remote-tracking branch 'origin/main' into feat-add-auto-import-directives 2024-10-25 09:50:01 +01:00
userquin
e1ffa41c9f chore: update lock file 2024-09-28 11:47:19 +02:00
userquin
2461ed6fb1 Merge branch 'refs/heads/main' into feat-add-auto-import-directives
# Conflicts:
#	pnpm-lock.yaml
2024-09-28 11:46:47 +02:00
userquin
01828a42f8 chore: bump unimport to 3.13.1 2024-09-28 11:45:47 +02:00
userquin
6012e158f4 docs: update directives 2024-09-27 22:27:39 +02:00
userquin
c9bdb8af7f chore: include missing vue preset types 2024-09-27 22:14:40 +02:00
userquin
7244fdf0b2 chore: update directives plugin comment 2024-09-27 22:03:41 +02:00
userquin
b164e4966f chore: don't mix imports 2024-09-27 22:02:00 +02:00
userquin
ae77a33069 chore: fix docs 2024-09-27 21:58:53 +02:00
userquin
03bf85a185 chore: fix watch comment 2024-09-27 21:55:50 +02:00
userquin
7ec3c04236 feat(nuxt,schema): add directives folder 2024-09-27 20:25:41 +02:00
10 changed files with 357 additions and 265 deletions

View File

@ -21,8 +21,8 @@ Or follow the steps below to set up a new Nuxt project on your computer.
<!-- markdownlint-disable-next-line MD001 -->
#### Prerequisites
- **Node.js** - [`v18.0.0`](https://nodejs.org/en) or newer
- **Text editor** - We recommend [Visual Studio Code](https://code.visualstudio.com/) with the [official Vue extension](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (previously known as Volar)
- **Node.js** - [`18.x`](https://nodejs.org/en) or newer (but we recommend the [active LTS release](https://github.com/nodejs/release#release-schedule))
- **Text editor** - There is no IDE requirement, but we recommend [Visual Studio Code](https://code.visualstudio.com/) with the [official Vue extension](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (previously known as Volar) or [WebStorm](https://www.jetbrains.com/webstorm/), which, along with [other JetBrains IDEs](https://www.jetbrains.com/ides/), offers great Nuxt support right out-of-the-box.
- **Terminal** - In order to run Nuxt commands
::note

View File

@ -0,0 +1,45 @@
---
title: "directives"
head.title: "directives/"
description: "The directives/ directory is where you put all your Vue directives."
navigation.icon: i-ph-folder
---
Nuxt automatically imports any directive in this directory (along with directives that are registered by any modules you may be using).
```bash [Directory Structure]
| directives/
--| awesome.ts
--| focus.ts
```
```html [app.vue]
<template>
<div v-awesome v-focus>
</div>
</template>
```
## Directives
You must use always named exports for your directives.
If you have SSR enabled, you must use object notation in your directives. Otherwise, Vue will throw an error about missing `getSSRProps`.
```ts
function mounted (el: HTMLElement, binding: TouchDirectiveBinding) {
// ...
}
// other lifecycle hooks
export const Focus = {
mounted
// ...
}
// DONT' USE export default here
export default Focus
```
:link-example{to="/docs/examples/features/auto-imports"}

View File

@ -189,7 +189,6 @@ export default createConfigForNuxt({
},
},
// Sort rule keys in eslint config
// @ts-expect-error incorrect types 🤔
{
files: ['**/eslint.config.mjs'],
name: 'local/sort-eslint-config',

View File

@ -40,7 +40,7 @@
"@nuxt/ui-templates": "workspace:*",
"@nuxt/vite-builder": "workspace:*",
"@nuxt/webpack-builder": "workspace:*",
"@types/node": "22.9.0",
"@types/node": "22.9.1",
"@unhead/dom": "1.11.11",
"@unhead/shared": "1.11.11",
"@unhead/vue": "1.11.11",
@ -75,7 +75,7 @@
"@nuxt/webpack-builder": "workspace:*",
"@testing-library/vue": "8.1.0",
"@types/eslint__js": "8.42.3",
"@types/node": "22.9.0",
"@types/node": "22.9.1",
"@types/semver": "7.5.8",
"@unhead/schema": "1.11.11",
"@unhead/vue": "1.11.11",
@ -91,7 +91,7 @@
"devalue": "5.1.1",
"eslint": "9.15.0",
"eslint-plugin-no-only-tests": "3.3.0",
"eslint-plugin-perfectionist": "3.9.1",
"eslint-plugin-perfectionist": "4.0.2",
"eslint-typegen": "0.3.2",
"h3": "npm:h3-nightly@2.0.0-1718872656.6765a6e",
"happy-dom": "15.11.6",

View File

@ -0,0 +1,63 @@
import { createUnplugin } from 'unplugin'
import type { AddonsOptions, Import } from 'unimport'
import { createUnimport } from 'unimport'
import type { ImportPresetWithDeprecation } from 'nuxt/schema'
import MagicString from 'magic-string'
import { isVue } from '../core/utils'
export const DirectivesPlugin = ({
addons,
dirs,
imports,
presets,
}: {
addons: AddonsOptions
dirs: string[]
imports: Import[]
presets: ImportPresetWithDeprecation[]
}) => createUnplugin(() => {
const useImports: Import[] = []
function visit (i: Import) {
if (i.meta?.vueDirective === true) {
useImports.push(i)
}
}
imports?.forEach(visit)
presets?.forEach((preset) => {
if (preset && 'imports' in preset) {
const imports = preset.imports as Import[]
imports.forEach(visit)
}
})
const ctx = createUnimport({
dirs,
imports: useImports,
addons,
})
return {
name: 'nuxt:directives-transform',
enforce: 'post',
transformInclude (id) {
return isVue(id, { type: ['script', 'template'] })
},
async transform (code, id) {
const s = new MagicString(code)
await ctx.injectImports(s, id, {
autoImport: false,
})
if (!s.hasChanged()) { return }
return {
code: s.toString(),
map: s.generateMap(),
}
},
async buildStart () {
await ctx.init()
},
}
})

View File

@ -1,7 +1,7 @@
import { existsSync } from 'node:fs'
import { addBuildPlugin, addTemplate, addTypeTemplate, defineNuxtModule, isIgnored, logger, resolveAlias, tryResolveModule, updateTemplates, useNuxt } from '@nuxt/kit'
import { isAbsolute, join, normalize, relative, resolve } from 'pathe'
import type { Import, Unimport } from 'unimport'
import type { AddonVueDirectivesOptions, AddonsOptions, Import, Unimport } from 'unimport'
import { createUnimport, scanDirExports, toExports } from 'unimport'
import type { ImportPresetWithDeprecation, ImportsOptions, ResolvedNuxtTemplate } from 'nuxt/schema'
import escapeRE from 'escape-string-regexp'
@ -10,6 +10,7 @@ import { lookupNodeModuleSubpath, parseNodeModulePath } from 'mlly'
import { isDirectory } from '../utils'
import { TransformPlugin } from './transform'
import { defaultPresets } from './presets'
import { DirectivesPlugin } from './directives'
export default defineNuxtModule<Partial<ImportsOptions>>({
meta: {
@ -41,14 +42,65 @@ export default defineNuxtModule<Partial<ImportsOptions>>({
// Filter disabled sources
// options.sources = options.sources.filter(source => source.disabled !== true)
let directivesDir: string[] = []
if (options.scan) {
for (const layer of nuxt.options._layers) {
// Layer disabled scanning for itself
if (layer.config?.imports?.scan === false) {
continue
}
directivesDir.push(resolve(layer.config.srcDir, 'directives'))
}
directivesDir = directivesDir.map(dir => normalize(dir))
// Restart nuxt when directives directories are added/removed
nuxt.hook('builder:watch', (event, relativePath) => {
if (!['addDir', 'unlinkDir'].includes(event)) { return }
const path = resolve(nuxt.options.srcDir, relativePath)
if (directivesDir.includes(path)) {
logger.info(`Directory \`${relativePath}/\` ${event === 'addDir' ? 'created' : 'removed'}`)
return nuxt.callHook('restart')
}
})
}
// We need to enable vueDirectives when:
// - vueDirectives is explicitly set to true or callback enabled
// - autoImport is enabled: allow use directives from presets
// We also need to resolve the directives from any layer
function isDirectiveFactory (): true | AddonVueDirectivesOptions | undefined {
if (!options.scan && !options.autoImport) {
return undefined
}
if (!options.scan) {
return true
}
return {
isDirective: (normalizeImportFrom: string) => {
return directivesDir.some(dir => normalizeImportFrom.startsWith(dir))
},
}
}
const { addons: inlineAddons, ...rest } = options
const addons: AddonsOptions = {
addons: inlineAddons && Array.isArray(inlineAddons)
? [...inlineAddons]
: [],
vueDirectives: isDirectiveFactory(),
vueTemplate: options.autoImport,
}
// Create a context to share state between module internals
const ctx = createUnimport({
injectAtEnd: true,
...options,
addons: {
vueTemplate: options.autoImport,
...options.addons,
},
...rest,
addons,
presets,
})
@ -66,6 +118,7 @@ export default defineNuxtModule<Partial<ImportsOptions>>({
}
composablesDirs.push(resolve(layer.config.srcDir, 'composables'))
composablesDirs.push(resolve(layer.config.srcDir, 'utils'))
composablesDirs.push(resolve(layer.config.srcDir, 'directives'))
if (isNuxtV4) {
composablesDirs.push(resolve(layer.config.rootDir, 'shared', 'utils'))
@ -102,6 +155,8 @@ export default defineNuxtModule<Partial<ImportsOptions>>({
})
nuxt.options.alias['#imports'] = join(nuxt.options.buildDir, 'imports')
// Auto import directives
addBuildPlugin(DirectivesPlugin({ addons, dirs: directivesDir, imports: options.imports ?? [], presets }))
// Transform to inject imports in production mode
addBuildPlugin(TransformPlugin({ ctx, options, sourcemap: !!nuxt.options.sourcemap.server || !!nuxt.options.sourcemap.client }))

View File

@ -242,6 +242,8 @@ const vueTypesPreset = defineUnimportPreset({
'Component',
'ComponentPublicInstance',
'ComputedRef',
'DirectiveBinding',
'ExtractDefaultPropTypes',
'ExtractPropTypes',
'ExtractPublicPropTypes',
'InjectionKey',
@ -250,6 +252,7 @@ const vueTypesPreset = defineUnimportPreset({
'MaybeRef',
'MaybeRefOrGetter',
'VNode',
'WritableComputedRef',
],
})

View File

@ -31,7 +31,7 @@ export default defineUntypedSchema({
/**
* An array of custom directories that will be auto-imported.
* Note that this option will not override the default directories (~/composables, ~/utils).
* Note that this option will not override the default directories (~/composables, ~/utils, ~/directives).
* @example
* ```js
* imports: {

View File

@ -11,7 +11,7 @@ export interface ImportsOptions extends UnimportOptions {
/**
* Directories to scan for auto imports.
* @see https://nuxt.com/docs/guide/directory-structure/composables#how-files-are-scanned
* @default ['./composables', './utils']
* @default ['./composables', './utils', './directives']
*/
dirs?: string[]

File diff suppressed because it is too large Load Diff