-
-
Notifications
You must be signed in to change notification settings - Fork 5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(nuxt,schema): add directives folder #29203
base: main
Are you sure you want to change the base?
Conversation
Run & review this pull request in StackBlitz Codeflow. |
} | ||
} | ||
imports?.forEach(visit) | ||
presets?.forEach((preset) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
review this, I guess not necessary (getting some errors starting nuxt dev server, re-check this without ?
)
We also need to change the import to use |
We need a new release on |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry it took so long for the review! 🙏
I think what we should do is not register a directives/
folder but instead add a kit utility that registers custom directives for auto-importing.
If there is enough demand later on we might reconsider the folder but for now I think the main benefit is for modules to register directives (like vuetify).
For this I think we can either pass an additional option to the imports module, if required - maybe an array of directives? (Or if it's possible to configure unimport without this, we can go simpler.)
Do you have time to implement this?
WalkthroughThe changes introduce a new documentation file for the Changes
Assessment against linked issues
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
🧹 Outside diff range and nitpick comments (12)
packages/schema/src/types/imports.ts (1)
14-14
: LGTM! Consider enhancing the documentation link.The addition of './directives' to the default directories aligns well with the new auto-import feature for Vue directives. The change is non-breaking and maintains backward compatibility.
Consider updating the documentation link in the JSDoc to also reference the new directives documentation, as it currently only points to composables.
- * @see https://nuxt.com/docs/guide/directory-structure/composables#how-files-are-scanned + * @see https://nuxt.com/docs/guide/directory-structure/composables#how-files-are-scanned + * @see https://nuxt.com/docs/guide/directory-structure/directivesdocs/2.guide/2.directory-structure/1.directives.md (4)
1-8
: Consider enhancing the introduction with more context.The introduction could be more helpful for newcomers by:
- Explaining what Vue directives are and their purpose
- Mentioning the naming convention requirements upfront
- Including a link to Vue's official documentation on directives
Nuxt automatically imports any directive in this directory (along with directives that are registered by any modules you may be using). + +Vue directives are special attributes that allow you to apply custom behavior to DOM elements. They are prefixed with `v-` and can be used to handle various DOM manipulations, event handling, and more. + +:read-more{to="https://vuejs.org/guide/reusability/custom-directives.html" title="Vue Custom Directives"}
10-14
: Enhance the directory structure example with more details.Consider adding brief comments to indicate what each directive does, and use consistent file extensions.
```bash [Directory Structure] | directives/ ---| awesome.ts ---| focus.ts +--| awesome.ts # Example directive that adds awesome animations +--| focus.ts # Directive to auto-focus form inputs--- `27-27`: **Enhance the SSR warning with more details.** The SSR warning could be more helpful by including the actual error message and a clear example of the correct implementation. ```diff -If you have SSR enabled, you must use object notation in your directives. Otherwise, Vue will throw an error about missing `getSSRProps`. +If you have SSR enabled, you must use object notation in your directives and implement the `getSSRProps` function. Otherwise, Vue will throw an error like: + +```bash +[Vue warn]: Directive is missing getSSRProps in SSR +``` + +Here's how to properly implement an SSR-compatible directive: + +```ts +export const MyDirective = { + mounted(el: HTMLElement, binding: DirectiveBinding) { + // Client-side logic + }, + getSSRProps(binding, vnode) { + // Return SSR-specific props + return {} + } +} +```
45-45
: Fix the formatting of the example link.Add a newline before the link component to maintain consistent formatting.
+ :link-example{to="/docs/examples/features/auto-imports"}
packages/schema/src/config/adhoc.ts (1)
34-34
: Documentation update looks good, minor enhancement suggested.The updated comment correctly reflects the addition of
~/directives
to the default directories. However, consider making the documentation more explicit about the behavior of these default directories.Consider this minor enhancement to improve clarity:
- * Note that this option will not override the default directories (~/composables, ~/utils, ~/directives). + * Note that this option will extend, not override, the default directories (~/composables, ~/utils, ~/directives). + * These default directories will always be included regardless of the directories specified here.packages/nuxt/src/imports/directives.ts (6)
2-3
: Consolidate imports from 'unimport' into a single statementYou can improve code clarity by combining the imports from
'unimport'
.Apply this diff to consolidate the imports:
-import type { AddonsOptions, Import } from 'unimport' -import { createUnimport } from 'unimport' +import { createUnimport, type AddonsOptions, type Import } from 'unimport'
25-26
: Remove unnecessary optional chaining on 'imports'Since
imports
is defined and expected to be an array, the optional chaining operator?.
is unnecessary and can be removed for simplicity.Apply this diff:
-imports?.forEach(visit) +imports.forEach(visit)
26-31
: Avoid variable shadowing of 'imports' inside the loopThe variable
imports
is re-declared inside the loop, which shadows the outerimports
parameter and may cause confusion.Consider renaming the inner
imports
variable to prevent shadowing. Apply this diff:presets?.forEach((preset) => { if (preset && 'imports' in preset) { - const imports = preset.imports as Import[] - imports.forEach(visit) + const presetImports = preset.imports as Import[] + presetImports.forEach(visit) } })
28-29
: Ensure type safety without unnecessary castingInstead of casting
preset.imports
usingas Import[]
, consider ensuring proper typing to maintain type safety.Apply this diff:
- const presetImports = preset.imports as Import[] + const presetImports: Import[] = preset.imports || []
43-43
: Extend 'transformInclude' to handle additional file types if necessaryCurrently,
transformInclude
only processes Vue files withscript
ortemplate
types. If directives are used in other contexts, consider updating this function to accommodate them.
52-52
: Simplify conditional return statementYou can simplify the return statement for better readability.
Apply this diff:
- if (!s.hasChanged()) { return } + if (!s.hasChanged()) return
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (6)
docs/2.guide/2.directory-structure/1.directives.md
(1 hunks)packages/nuxt/src/imports/directives.ts
(1 hunks)packages/nuxt/src/imports/module.ts
(5 hunks)packages/nuxt/src/imports/presets.ts
(2 hunks)packages/schema/src/config/adhoc.ts
(1 hunks)packages/schema/src/types/imports.ts
(1 hunks)
🧰 Additional context used
🪛 LanguageTool
docs/2.guide/2.directory-structure/1.directives.md
[uncategorized] ~44-~44: Loose punctuation mark.
Context: ... default here export default Focus ``` :link-example{to="/docs/examples/features...
(UNLIKELY_OPENING_PUNCTUATION)
🔇 Additional comments (1)
packages/nuxt/src/imports/presets.ts (1)
245-246
: LGTM! The type additions enhance directive support.
The addition of DirectiveBinding
and WritableComputedRef
types to vueTypesPreset
aligns well with the PR's objective of supporting Vue directive auto-imports. The DirectiveBinding
type is particularly important as it provides proper typing for directive implementations.
Let's verify the types are being used in the new directives implementation:
Also applies to: 255-255
✅ Verification successful
Let me gather more information about the directive implementation to verify if the type is being used correctly.
Based on the gathered information, I can now generate the final response:
The DirectiveBinding
type addition is correctly implemented for directive support
The addition of DirectiveBinding
type to vueTypesPreset
is appropriate as it's being used in the documentation examples for directive implementations (docs/2.guide/2.directory-structure/1.directives.md
). The type is essential for providing proper typing support when developers create custom Vue directives in their Nuxt applications.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check for usage of DirectiveBinding type in directive-related files
# Expected: Find references in directive implementation files
# Search for DirectiveBinding usage
rg "DirectiveBinding" -A 5
# Search for files in the directives directory
fd "directives"
Length of output: 916
Script:
#!/bin/bash
# Check the content of directives.ts to see how DirectiveBinding is used
cat packages/nuxt/src/imports/directives.ts
# Search for any directive-related type definitions or implementations
ast-grep --pattern 'interface $_DirectiveBinding {
$$$
}'
# Look for directive-related imports from Vue
rg "import.*from 'vue'" -A 2
Length of output: 29413
```ts | ||
function mounted (el: HTMLElement, binding: TouchDirectiveBinding) { | ||
// ... | ||
} | ||
|
||
// other lifecycle hooks | ||
|
||
export const Focus = { | ||
mounted | ||
// ... | ||
} | ||
|
||
// DONT' USE export default here | ||
export default Focus | ||
``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Improve the implementation example for clarity and correctness.
The current example has several issues:
- It includes a discouraged
export default
statement - Uses unexplained type
TouchDirectiveBinding
- Contains incomplete code with "..." placeholders
Consider replacing it with a complete, working example:
-function mounted (el: HTMLElement, binding: TouchDirectiveBinding) {
+import type { DirectiveBinding } from 'vue'
+
+function mounted(el: HTMLElement, binding: DirectiveBinding) {
// ...
}
-// other lifecycle hooks
+function beforeMount(el: HTMLElement, binding: DirectiveBinding) {
+ // Initialize the element
+}
+
+function updated(el: HTMLElement, binding: DirectiveBinding) {
+ // Handle updates to directive arguments or value
+}
export const Focus = {
- mounted
- // ...
+ mounted,
+ beforeMount,
+ updated
}
-
-// DONT' USE export default here
-export default Focus
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
```ts | |
function mounted (el: HTMLElement, binding: TouchDirectiveBinding) { | |
// ... | |
} | |
// other lifecycle hooks | |
export const Focus = { | |
mounted | |
// ... | |
} | |
// DONT' USE export default here | |
export default Focus | |
``` | |
import type { DirectiveBinding } from 'vue' | |
function mounted(el: HTMLElement, binding: DirectiveBinding) { | |
// ... | |
} | |
function beforeMount(el: HTMLElement, binding: DirectiveBinding) { | |
// Initialize the element | |
} | |
function updated(el: HTMLElement, binding: DirectiveBinding) { | |
// Handle updates to directive arguments or value | |
} | |
export const Focus = { | |
mounted, | |
beforeMount, | |
updated | |
} |
@@ -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). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codebase verification
Documentation is inconsistent with the implementation
The implementation in packages/schema/src/types/imports.ts
shows the default directories as ['./composables', './utils', './directives']
, but the documentation in adhoc.ts
refers to them as (~/composables, ~/utils, ~/directives)
. The paths use different prefixes (./
vs ~/
), which could be confusing for users.
packages/schema/src/config/adhoc.ts
: Update the documentation to use./
prefix instead of~/
to match the actual implementationpackages/schema/src/types/imports.ts
: Line shows correct default value:@default ['./composables', './utils', './directives']
🔗 Analysis chain
Verify consistency with related configuration files.
Let's ensure this documentation change is consistent with the actual implementation and other configuration files.
Let me check the actual implementation details in the found files to verify the consistency.
Let me check one more thing to verify the actual implementation of these defaults.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Verify consistency of directives configuration across files
# Check for related configuration in schema types
echo "Checking schema types for directives configuration..."
rg -l "~/directives|./directives" "packages/schema/src/types/"
# Check for imports configuration in other files
echo "Checking other files for imports configuration..."
rg -l "imports.*dirs.*directives" "packages/"
# Check for documentation consistency
echo "Checking documentation consistency..."
rg -l "default.*directories.*(composables|utils|directives)" "packages/"
Length of output: 565
Script:
#!/bin/bash
# Check the implementation in imports.ts
echo "Content of imports.ts:"
cat packages/schema/src/types/imports.ts
# Check for any other references to these default directories
echo -e "\nSearching for default directory configurations:"
rg -A 5 "defaultDirs|default.*dirs" packages/schema/src/
Length of output: 1164
Script:
#!/bin/bash
# Search for the actual implementation of these defaults
echo "Searching for implementation of default directories:"
rg -A 10 "composables.*utils.*directives" packages/
# Also check the documentation
echo -e "\nChecking documentation mentions:"
rg -A 3 "default.*directories" packages/
Length of output: 1941
@@ -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')) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Avoid adding 'directives' directory to composablesDirs
Adding the 'directives'
directory to composablesDirs
may result in directives being scanned and processed as composables, which could cause unexpected behavior since directives and composables serve different purposes. It's advisable to handle the 'directives'
directory separately to maintain clarity and prevent potential conflicts.
Apply this diff to remove the 'directives'
directory from composablesDirs
:
- composablesDirs.push(resolve(layer.config.srcDir, 'directives'))
Ensure that directives are managed independently within their appropriate context.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
composablesDirs.push(resolve(layer.config.srcDir, 'directives')) |
const path = resolve(nuxt.options.srcDir, relativePath) | ||
if (directivesDir.includes(path)) { | ||
logger.info(`Directory \`${relativePath}/\` ${event === 'addDir' ? 'created' : 'removed'}`) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Normalize paths before comparison to ensure accurate detection
In the builder:watch
hook, the path
variable may not match entries in the directivesDir
array due to inconsistencies in path formats (e.g., different slashes or case sensitivity across platforms). To ensure accurate detection when directories are added or removed, consider normalizing path
before the comparison.
Apply this diff to normalize the path
variable:
const path = resolve(nuxt.options.srcDir, relativePath)
+ const normalizedPath = normalize(path)
- if (directivesDir.includes(path)) {
+ if (directivesDir.includes(normalizedPath)) {
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const path = resolve(nuxt.options.srcDir, relativePath) | |
if (directivesDir.includes(path)) { | |
logger.info(`Directory \`${relativePath}/\` ${event === 'addDir' ? 'created' : 'removed'}`) | |
const path = resolve(nuxt.options.srcDir, relativePath) | |
const normalizedPath = normalize(path) | |
if (directivesDir.includes(normalizedPath)) { | |
logger.info(`Directory \`${relativePath}/\` ${event === 'addDir' ? 'created' : 'removed'}`) |
🔗 Linked issue
resolves #28954
📚 Description
This PR includes:
directives
folder described here: allow auto import vue directives #28954 (comment)unimport
(v3.13.0
)imports
module to auto import directives and generating the corresponding dts entries (add the directives to the Vue module augmentation (Volar will show the directives in the template) )resolveDirectives
in the imports module: check Context belowunimport
: missingDirectiveBinding
(missing here andunimport
),ExtractDefaultPropTypes
andWritableComputedRef
(MaybeRef
andMaybeRefOrGetter
missing inunimport
)directives
folder in docs: addeddocs/2.guide/2.directory-structure/1.directives.md/
,not yet tested on my local with✔️ testednuxt.com
repositoryImportant
Context
Since we only need the directives and the dts, the imports module will do it for us (free, no changes, only the ones to update the new options in
unimport
). We can reuse theunimport
configuration to generate the imports and the dts to replaceresolveDirectives
without having to move that logic to the components loader as suggested by @danielroe in the issue: this new plugin will filter imports and presets imports withmeta.vueDirective
set to true.Warning
✔️
This PR in draft since we need this PR merged and released: unjs/unimport#380(unimport
updated to3.13.1
)FUTURE: we need to:
Directives
in Nuxt DevTools, right now shown asComposables
: fix(addon): wrong vue directives transform filter unjs/unimport#380 will allow also detect directives when using directives folder (viameta.vueDirective
in the imports): ✔️ feat: add directives page devtools#740Nuxt Devtools showing the directives
Testing
If you want to test this PR you will need to:
directives
folder in the playgroundgetSSRProps
)patchplayground/node_modules/nuxt/node_modules/unimport/dist/shared/unimport.0cf85d87.mjs
manually: chekc screenshot belowunimport
updated to3.13.1
with the fixunimport patchSummary by CodeRabbit
New Features
directives/
directory, detailing usage and requirements for Vue directives.DirectivesPlugin
to manage Vue directives within a Nuxt application.vueTypesPreset
with additional types for improved type safety.Bug Fixes
./directives
.Documentation