devskill 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +123 -0
- package/README.vn.md +104 -0
- package/SKILL_GUIDE.vn.md +252 -0
- package/bin/devskill.js +11 -0
- package/meta.ts +123 -0
- package/package.json +21 -0
- package/publish.sh +50 -0
- package/scripts/cli.ts +556 -0
- package/skills/builderx_api-contexts/SKILL.md +63 -0
- package/skills/builderx_api-contexts/references/core-multi-outbox.md +57 -0
- package/skills/builderx_api-controllers/SKILL.md +49 -0
- package/skills/builderx_api-controllers/references/core-fallback.md +62 -0
- package/skills/builderx_api-schemas/SKILL.md +76 -0
- package/skills/builderx_api-schemas/references/core-schema.md +78 -0
- package/skills/builderx_spa-api/SKILL.md +67 -0
- package/skills/builderx_spa-api/references/base-api.md +97 -0
- package/skills/builderx_spa-api/references/fetch.md +70 -0
- package/skills/builderx_spa-design/SKILL.md +82 -0
- package/skills/builderx_spa-design/references/core-text-design.md +64 -0
- package/skills/builderx_spa-design/references/features-feedback-actions.md +76 -0
- package/skills/builderx_spa-design/references/features-forms.md +91 -0
- package/skills/builderx_spa-design/references/features-layout-navigation.md +121 -0
- package/skills/builderx_spa-permission/SKILL.md +38 -0
- package/skills/builderx_spa-permission/references/has-permission.md +34 -0
- package/skills/composition-patterns/AGENTS.md +946 -0
- package/skills/composition-patterns/README.md +60 -0
- package/skills/composition-patterns/SKILL.md +89 -0
- package/skills/composition-patterns/SYNC.md +5 -0
- package/skills/composition-patterns/metadata.json +11 -0
- package/skills/composition-patterns/rules/_sections.md +29 -0
- package/skills/composition-patterns/rules/_template.md +24 -0
- package/skills/composition-patterns/rules/architecture-avoid-boolean-props.md +100 -0
- package/skills/composition-patterns/rules/architecture-compound-components.md +112 -0
- package/skills/composition-patterns/rules/patterns-children-over-render-props.md +87 -0
- package/skills/composition-patterns/rules/patterns-explicit-variants.md +100 -0
- package/skills/composition-patterns/rules/react19-no-forwardref.md +42 -0
- package/skills/composition-patterns/rules/state-context-interface.md +191 -0
- package/skills/composition-patterns/rules/state-decouple-implementation.md +113 -0
- package/skills/composition-patterns/rules/state-lift-state.md +125 -0
- package/skills/deploy-to-vercel/Archive.zip +0 -0
- package/skills/deploy-to-vercel/SKILL.md +296 -0
- package/skills/deploy-to-vercel/SYNC.md +5 -0
- package/skills/deploy-to-vercel/resources/deploy-codex.sh +301 -0
- package/skills/deploy-to-vercel/resources/deploy.sh +301 -0
- package/skills/pinia/SKILL.md +105 -0
- package/skills/pinia/references/api-in-composables.md +139 -0
- package/skills/pinia/references/setup-stores.md +105 -0
- package/skills/pinia/references/using-in-components.md +91 -0
- package/skills/pinia-options/SKILL.md +72 -0
- package/skills/pinia-options/references/core-option-stores.md +149 -0
- package/skills/pinia-options/references/using-in-options-api.md +105 -0
- package/skills/react-best-practices/AGENTS.md +3373 -0
- package/skills/react-best-practices/README.md +123 -0
- package/skills/react-best-practices/SKILL.md +143 -0
- package/skills/react-best-practices/SYNC.md +5 -0
- package/skills/react-best-practices/metadata.json +15 -0
- package/skills/react-best-practices/rules/_sections.md +46 -0
- package/skills/react-best-practices/rules/_template.md +28 -0
- package/skills/react-best-practices/rules/advanced-event-handler-refs.md +55 -0
- package/skills/react-best-practices/rules/advanced-init-once.md +42 -0
- package/skills/react-best-practices/rules/advanced-use-latest.md +39 -0
- package/skills/react-best-practices/rules/async-api-routes.md +38 -0
- package/skills/react-best-practices/rules/async-defer-await.md +80 -0
- package/skills/react-best-practices/rules/async-dependencies.md +51 -0
- package/skills/react-best-practices/rules/async-parallel.md +28 -0
- package/skills/react-best-practices/rules/async-suspense-boundaries.md +99 -0
- package/skills/react-best-practices/rules/bundle-barrel-imports.md +59 -0
- package/skills/react-best-practices/rules/bundle-conditional.md +31 -0
- package/skills/react-best-practices/rules/bundle-defer-third-party.md +49 -0
- package/skills/react-best-practices/rules/bundle-dynamic-imports.md +35 -0
- package/skills/react-best-practices/rules/bundle-preload.md +50 -0
- package/skills/react-best-practices/rules/client-event-listeners.md +74 -0
- package/skills/react-best-practices/rules/client-localstorage-schema.md +71 -0
- package/skills/react-best-practices/rules/client-passive-event-listeners.md +48 -0
- package/skills/react-best-practices/rules/client-swr-dedup.md +56 -0
- package/skills/react-best-practices/rules/js-batch-dom-css.md +107 -0
- package/skills/react-best-practices/rules/js-cache-function-results.md +80 -0
- package/skills/react-best-practices/rules/js-cache-property-access.md +28 -0
- package/skills/react-best-practices/rules/js-cache-storage.md +70 -0
- package/skills/react-best-practices/rules/js-combine-iterations.md +32 -0
- package/skills/react-best-practices/rules/js-early-exit.md +50 -0
- package/skills/react-best-practices/rules/js-flatmap-filter.md +60 -0
- package/skills/react-best-practices/rules/js-hoist-regexp.md +45 -0
- package/skills/react-best-practices/rules/js-index-maps.md +37 -0
- package/skills/react-best-practices/rules/js-length-check-first.md +49 -0
- package/skills/react-best-practices/rules/js-min-max-loop.md +82 -0
- package/skills/react-best-practices/rules/js-set-map-lookups.md +24 -0
- package/skills/react-best-practices/rules/js-tosorted-immutable.md +57 -0
- package/skills/react-best-practices/rules/rendering-activity.md +26 -0
- package/skills/react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
- package/skills/react-best-practices/rules/rendering-conditional-render.md +40 -0
- package/skills/react-best-practices/rules/rendering-content-visibility.md +38 -0
- package/skills/react-best-practices/rules/rendering-hoist-jsx.md +46 -0
- package/skills/react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
- package/skills/react-best-practices/rules/rendering-hydration-suppress-warning.md +30 -0
- package/skills/react-best-practices/rules/rendering-resource-hints.md +85 -0
- package/skills/react-best-practices/rules/rendering-script-defer-async.md +68 -0
- package/skills/react-best-practices/rules/rendering-svg-precision.md +28 -0
- package/skills/react-best-practices/rules/rendering-usetransition-loading.md +75 -0
- package/skills/react-best-practices/rules/rerender-defer-reads.md +39 -0
- package/skills/react-best-practices/rules/rerender-dependencies.md +45 -0
- package/skills/react-best-practices/rules/rerender-derived-state-no-effect.md +40 -0
- package/skills/react-best-practices/rules/rerender-derived-state.md +29 -0
- package/skills/react-best-practices/rules/rerender-functional-setstate.md +74 -0
- package/skills/react-best-practices/rules/rerender-lazy-state-init.md +58 -0
- package/skills/react-best-practices/rules/rerender-memo-with-default-value.md +38 -0
- package/skills/react-best-practices/rules/rerender-memo.md +44 -0
- package/skills/react-best-practices/rules/rerender-move-effect-to-event.md +45 -0
- package/skills/react-best-practices/rules/rerender-no-inline-components.md +82 -0
- package/skills/react-best-practices/rules/rerender-simple-expression-in-memo.md +35 -0
- package/skills/react-best-practices/rules/rerender-split-combined-hooks.md +64 -0
- package/skills/react-best-practices/rules/rerender-transitions.md +40 -0
- package/skills/react-best-practices/rules/rerender-use-deferred-value.md +59 -0
- package/skills/react-best-practices/rules/rerender-use-ref-transient-values.md +73 -0
- package/skills/react-best-practices/rules/server-after-nonblocking.md +73 -0
- package/skills/react-best-practices/rules/server-auth-actions.md +96 -0
- package/skills/react-best-practices/rules/server-cache-lru.md +41 -0
- package/skills/react-best-practices/rules/server-cache-react.md +76 -0
- package/skills/react-best-practices/rules/server-dedup-props.md +65 -0
- package/skills/react-best-practices/rules/server-hoist-static-io.md +142 -0
- package/skills/react-best-practices/rules/server-parallel-fetching.md +83 -0
- package/skills/react-best-practices/rules/server-serialization.md +38 -0
- package/skills/react-native-skills/AGENTS.md +2897 -0
- package/skills/react-native-skills/README.md +165 -0
- package/skills/react-native-skills/SKILL.md +121 -0
- package/skills/react-native-skills/SYNC.md +5 -0
- package/skills/react-native-skills/metadata.json +16 -0
- package/skills/react-native-skills/rules/_sections.md +86 -0
- package/skills/react-native-skills/rules/_template.md +28 -0
- package/skills/react-native-skills/rules/animation-derived-value.md +53 -0
- package/skills/react-native-skills/rules/animation-gesture-detector-press.md +95 -0
- package/skills/react-native-skills/rules/animation-gpu-properties.md +65 -0
- package/skills/react-native-skills/rules/design-system-compound-components.md +66 -0
- package/skills/react-native-skills/rules/fonts-config-plugin.md +71 -0
- package/skills/react-native-skills/rules/imports-design-system-folder.md +68 -0
- package/skills/react-native-skills/rules/js-hoist-intl.md +61 -0
- package/skills/react-native-skills/rules/list-performance-callbacks.md +44 -0
- package/skills/react-native-skills/rules/list-performance-function-references.md +132 -0
- package/skills/react-native-skills/rules/list-performance-images.md +53 -0
- package/skills/react-native-skills/rules/list-performance-inline-objects.md +97 -0
- package/skills/react-native-skills/rules/list-performance-item-expensive.md +94 -0
- package/skills/react-native-skills/rules/list-performance-item-memo.md +82 -0
- package/skills/react-native-skills/rules/list-performance-item-types.md +104 -0
- package/skills/react-native-skills/rules/list-performance-virtualize.md +67 -0
- package/skills/react-native-skills/rules/monorepo-native-deps-in-app.md +46 -0
- package/skills/react-native-skills/rules/monorepo-single-dependency-versions.md +63 -0
- package/skills/react-native-skills/rules/navigation-native-navigators.md +188 -0
- package/skills/react-native-skills/rules/react-compiler-destructure-functions.md +50 -0
- package/skills/react-native-skills/rules/react-compiler-reanimated-shared-values.md +48 -0
- package/skills/react-native-skills/rules/react-state-dispatcher.md +91 -0
- package/skills/react-native-skills/rules/react-state-fallback.md +56 -0
- package/skills/react-native-skills/rules/react-state-minimize.md +65 -0
- package/skills/react-native-skills/rules/rendering-no-falsy-and.md +74 -0
- package/skills/react-native-skills/rules/rendering-text-in-text-component.md +36 -0
- package/skills/react-native-skills/rules/scroll-position-no-state.md +82 -0
- package/skills/react-native-skills/rules/state-ground-truth.md +80 -0
- package/skills/react-native-skills/rules/ui-expo-image.md +66 -0
- package/skills/react-native-skills/rules/ui-image-gallery.md +104 -0
- package/skills/react-native-skills/rules/ui-measure-views.md +78 -0
- package/skills/react-native-skills/rules/ui-menus.md +174 -0
- package/skills/react-native-skills/rules/ui-native-modals.md +77 -0
- package/skills/react-native-skills/rules/ui-pressable.md +61 -0
- package/skills/react-native-skills/rules/ui-safe-area-scroll.md +65 -0
- package/skills/react-native-skills/rules/ui-scrollview-content-inset.md +45 -0
- package/skills/react-native-skills/rules/ui-styling.md +87 -0
- package/skills/slidev/LICENSE.md +21 -0
- package/skills/slidev/README.md +61 -0
- package/skills/slidev/SKILL.md +189 -0
- package/skills/slidev/SYNC.md +5 -0
- package/skills/slidev/references/animation-click-marker.md +37 -0
- package/skills/slidev/references/animation-drawing.md +68 -0
- package/skills/slidev/references/animation-rough-marker.md +53 -0
- package/skills/slidev/references/api-slide-hooks.md +37 -0
- package/skills/slidev/references/build-og-image.md +36 -0
- package/skills/slidev/references/build-pdf.md +40 -0
- package/skills/slidev/references/build-remote-assets.md +34 -0
- package/skills/slidev/references/build-seo-meta.md +43 -0
- package/skills/slidev/references/code-groups.md +64 -0
- package/skills/slidev/references/code-import-snippet.md +55 -0
- package/skills/slidev/references/code-line-highlighting.md +50 -0
- package/skills/slidev/references/code-line-numbers.md +46 -0
- package/skills/slidev/references/code-magic-move.md +57 -0
- package/skills/slidev/references/code-max-height.md +37 -0
- package/skills/slidev/references/code-twoslash.md +42 -0
- package/skills/slidev/references/core-animations.md +196 -0
- package/skills/slidev/references/core-cli.md +140 -0
- package/skills/slidev/references/core-components.md +197 -0
- package/skills/slidev/references/core-exporting.md +148 -0
- package/skills/slidev/references/core-frontmatter.md +195 -0
- package/skills/slidev/references/core-global-context.md +155 -0
- package/skills/slidev/references/core-headmatter.md +188 -0
- package/skills/slidev/references/core-hosting.md +152 -0
- package/skills/slidev/references/core-layouts.md +286 -0
- package/skills/slidev/references/core-syntax.md +155 -0
- package/skills/slidev/references/diagram-latex.md +55 -0
- package/skills/slidev/references/diagram-mermaid.md +44 -0
- package/skills/slidev/references/diagram-plantuml.md +45 -0
- package/skills/slidev/references/editor-monaco-run.md +44 -0
- package/skills/slidev/references/editor-monaco-write.md +24 -0
- package/skills/slidev/references/editor-monaco.md +50 -0
- package/skills/slidev/references/editor-prettier.md +40 -0
- package/skills/slidev/references/editor-side.md +23 -0
- package/skills/slidev/references/editor-vscode.md +55 -0
- package/skills/slidev/references/layout-canvas-size.md +25 -0
- package/skills/slidev/references/layout-draggable.md +57 -0
- package/skills/slidev/references/layout-global-layers.md +50 -0
- package/skills/slidev/references/layout-slots.md +75 -0
- package/skills/slidev/references/layout-transform.md +33 -0
- package/skills/slidev/references/layout-zoom.md +39 -0
- package/skills/slidev/references/presenter-notes-ruby.md +35 -0
- package/skills/slidev/references/presenter-recording.md +30 -0
- package/skills/slidev/references/presenter-remote.md +40 -0
- package/skills/slidev/references/presenter-timer.md +34 -0
- package/skills/slidev/references/style-direction.md +34 -0
- package/skills/slidev/references/style-icons.md +46 -0
- package/skills/slidev/references/style-scoped.md +50 -0
- package/skills/slidev/references/syntax-block-frontmatter.md +39 -0
- package/skills/slidev/references/syntax-frontmatter-merging.md +49 -0
- package/skills/slidev/references/syntax-importing-slides.md +60 -0
- package/skills/slidev/references/syntax-mdc.md +51 -0
- package/skills/slidev/references/tool-eject-theme.md +27 -0
- package/skills/tsdown/LICENSE.md +22 -0
- package/skills/tsdown/README.md +77 -0
- package/skills/tsdown/SKILL.md +407 -0
- package/skills/tsdown/SYNC.md +5 -0
- package/skills/tsdown/references/README.md +139 -0
- package/skills/tsdown/references/advanced-benchmark.md +8 -0
- package/skills/tsdown/references/advanced-ci.md +89 -0
- package/skills/tsdown/references/advanced-hooks.md +363 -0
- package/skills/tsdown/references/advanced-plugins.md +381 -0
- package/skills/tsdown/references/advanced-programmatic.md +378 -0
- package/skills/tsdown/references/advanced-rolldown-options.md +117 -0
- package/skills/tsdown/references/guide-getting-started.md +178 -0
- package/skills/tsdown/references/guide-introduction.md +42 -0
- package/skills/tsdown/references/guide-migrate-from-tsup.md +189 -0
- package/skills/tsdown/references/option-cjs-default.md +98 -0
- package/skills/tsdown/references/option-cleaning.md +275 -0
- package/skills/tsdown/references/option-config-file.md +281 -0
- package/skills/tsdown/references/option-css.md +301 -0
- package/skills/tsdown/references/option-dependencies.md +385 -0
- package/skills/tsdown/references/option-dts.md +251 -0
- package/skills/tsdown/references/option-entry.md +211 -0
- package/skills/tsdown/references/option-exe.md +120 -0
- package/skills/tsdown/references/option-lint.md +127 -0
- package/skills/tsdown/references/option-log-level.md +91 -0
- package/skills/tsdown/references/option-minification.md +177 -0
- package/skills/tsdown/references/option-output-directory.md +270 -0
- package/skills/tsdown/references/option-output-format.md +181 -0
- package/skills/tsdown/references/option-package-exports.md +320 -0
- package/skills/tsdown/references/option-platform.md +256 -0
- package/skills/tsdown/references/option-root.md +88 -0
- package/skills/tsdown/references/option-shims.md +299 -0
- package/skills/tsdown/references/option-sourcemap.md +301 -0
- package/skills/tsdown/references/option-target.md +222 -0
- package/skills/tsdown/references/option-tree-shaking.md +335 -0
- package/skills/tsdown/references/option-unbundle.md +310 -0
- package/skills/tsdown/references/option-watch-mode.md +261 -0
- package/skills/tsdown/references/recipe-react.md +338 -0
- package/skills/tsdown/references/recipe-solid.md +46 -0
- package/skills/tsdown/references/recipe-svelte.md +54 -0
- package/skills/tsdown/references/recipe-vue.md +387 -0
- package/skills/tsdown/references/recipe-wasm.md +125 -0
- package/skills/tsdown/references/reference-cli.md +472 -0
- package/skills/turborepo/LICENSE.md +7 -0
- package/skills/turborepo/SKILL.md +951 -0
- package/skills/turborepo/SYNC.md +5 -0
- package/skills/turborepo/command/turborepo.md +70 -0
- package/skills/turborepo/references/best-practices/RULE.md +241 -0
- package/skills/turborepo/references/best-practices/dependencies.md +246 -0
- package/skills/turborepo/references/best-practices/packages.md +335 -0
- package/skills/turborepo/references/best-practices/structure.md +297 -0
- package/skills/turborepo/references/boundaries/RULE.md +126 -0
- package/skills/turborepo/references/caching/RULE.md +153 -0
- package/skills/turborepo/references/caching/gotchas.md +190 -0
- package/skills/turborepo/references/caching/remote-cache.md +127 -0
- package/skills/turborepo/references/ci/RULE.md +79 -0
- package/skills/turborepo/references/ci/github-actions.md +162 -0
- package/skills/turborepo/references/ci/patterns.md +145 -0
- package/skills/turborepo/references/ci/vercel.md +103 -0
- package/skills/turborepo/references/cli/RULE.md +100 -0
- package/skills/turborepo/references/cli/commands.md +297 -0
- package/skills/turborepo/references/configuration/RULE.md +235 -0
- package/skills/turborepo/references/configuration/global-options.md +239 -0
- package/skills/turborepo/references/configuration/gotchas.md +368 -0
- package/skills/turborepo/references/configuration/tasks.md +325 -0
- package/skills/turborepo/references/environment/RULE.md +123 -0
- package/skills/turborepo/references/environment/gotchas.md +175 -0
- package/skills/turborepo/references/environment/modes.md +101 -0
- package/skills/turborepo/references/filtering/RULE.md +148 -0
- package/skills/turborepo/references/filtering/patterns.md +152 -0
- package/skills/turborepo/references/watch/RULE.md +99 -0
- package/skills/vercel-cli-with-tokens/SKILL.md +328 -0
- package/skills/vercel-cli-with-tokens/SYNC.md +5 -0
- package/skills/vue/SKILL.md +90 -0
- package/skills/vue/references/composables.md +54 -0
- package/skills/vue/references/lifecycle.md +31 -0
- package/skills/vue/references/props-emits.md +62 -0
- package/skills/vue/references/provide-inject.md +47 -0
- package/skills/vue/references/state.md +65 -0
- package/skills/vue-antdv-tailwind/SKILL.md +33 -0
- package/skills/vue-antdv-tailwind/references/styling-rules.md +61 -0
- package/skills/vue-best-practices/LICENSE.md +21 -0
- package/skills/vue-best-practices/SKILL.md +154 -0
- package/skills/vue-best-practices/SYNC.md +5 -0
- package/skills/vue-best-practices/references/animation-class-based-technique.md +254 -0
- package/skills/vue-best-practices/references/animation-state-driven-technique.md +291 -0
- package/skills/vue-best-practices/references/component-async.md +97 -0
- package/skills/vue-best-practices/references/component-data-flow.md +307 -0
- package/skills/vue-best-practices/references/component-fallthrough-attrs.md +174 -0
- package/skills/vue-best-practices/references/component-keep-alive.md +137 -0
- package/skills/vue-best-practices/references/component-slots.md +216 -0
- package/skills/vue-best-practices/references/component-suspense.md +228 -0
- package/skills/vue-best-practices/references/component-teleport.md +108 -0
- package/skills/vue-best-practices/references/component-transition-group.md +128 -0
- package/skills/vue-best-practices/references/component-transition.md +125 -0
- package/skills/vue-best-practices/references/composables.md +290 -0
- package/skills/vue-best-practices/references/directives.md +162 -0
- package/skills/vue-best-practices/references/perf-avoid-component-abstraction-in-lists.md +159 -0
- package/skills/vue-best-practices/references/perf-v-once-v-memo-directives.md +182 -0
- package/skills/vue-best-practices/references/perf-virtualize-large-lists.md +187 -0
- package/skills/vue-best-practices/references/plugins.md +166 -0
- package/skills/vue-best-practices/references/reactivity.md +344 -0
- package/skills/vue-best-practices/references/render-functions.md +201 -0
- package/skills/vue-best-practices/references/sfc.md +310 -0
- package/skills/vue-best-practices/references/state-management.md +135 -0
- package/skills/vue-best-practices/references/updated-hook-performance.md +187 -0
- package/skills/vue-jsx-best-practices/LICENSE.md +21 -0
- package/skills/vue-jsx-best-practices/SKILL.md +12 -0
- package/skills/vue-jsx-best-practices/SYNC.md +5 -0
- package/skills/vue-jsx-best-practices/reference/render-function-jsx-vue-vs-react.md +141 -0
- package/skills/vue-options/SKILL.md +98 -0
- package/skills/vue-options/references/lifecycle.md +107 -0
- package/skills/vue-options/references/mixins.md +96 -0
- package/skills/vue-options/references/props-emits.md +106 -0
- package/skills/vue-options/references/provide-inject.md +92 -0
- package/skills/vue-options/references/state.md +115 -0
- package/skills/vue-options-api-best-practices/LICENSE.md +21 -0
- package/skills/vue-options-api-best-practices/SKILL.md +23 -0
- package/skills/vue-options-api-best-practices/SYNC.md +5 -0
- package/skills/vue-options-api-best-practices/reference/no-arrow-functions-in-lifecycle-hooks.md +95 -0
- package/skills/vue-options-api-best-practices/reference/no-arrow-functions-in-methods.md +68 -0
- package/skills/vue-options-api-best-practices/reference/stateful-methods-lifecycle.md +61 -0
- package/skills/vue-options-api-best-practices/reference/ts-options-api-arrow-functions-validators.md +141 -0
- package/skills/vue-options-api-best-practices/reference/ts-options-api-computed-return-types.md +192 -0
- package/skills/vue-options-api-best-practices/reference/ts-options-api-proptype-complex-types.md +212 -0
- package/skills/vue-options-api-best-practices/reference/ts-options-api-provide-inject-limitations.md +135 -0
- package/skills/vue-options-api-best-practices/reference/ts-options-api-type-event-handlers.md +202 -0
- package/skills/vue-options-api-best-practices/reference/ts-options-api-use-definecomponent.md +172 -0
- package/skills/vue-options-api-best-practices/reference/ts-strict-mode-options-api.md +197 -0
- package/skills/vue-pinia-best-practices/LICENSE.md +21 -0
- package/skills/vue-pinia-best-practices/SKILL.md +21 -0
- package/skills/vue-pinia-best-practices/SYNC.md +5 -0
- package/skills/vue-pinia-best-practices/reference/pinia-no-active-pinia-error.md +248 -0
- package/skills/vue-pinia-best-practices/reference/pinia-setup-store-return-all-state.md +227 -0
- package/skills/vue-pinia-best-practices/reference/pinia-store-destructuring-breaks-reactivity.md +193 -0
- package/skills/vue-pinia-best-practices/reference/state-url-for-ephemeral-filters.md +238 -0
- package/skills/vue-pinia-best-practices/reference/state-use-pinia-for-large-apps.md +262 -0
- package/skills/vue-pinia-best-practices/reference/store-method-binding-parentheses.md +191 -0
- package/skills/vue-router-best-practices/LICENSE.md +21 -0
- package/skills/vue-router-best-practices/SKILL.md +23 -0
- package/skills/vue-router-best-practices/SYNC.md +5 -0
- package/skills/vue-router-best-practices/reference/router-beforeenter-no-param-trigger.md +167 -0
- package/skills/vue-router-best-practices/reference/router-beforerouteenter-no-this.md +176 -0
- package/skills/vue-router-best-practices/reference/router-guard-async-await-pattern.md +227 -0
- package/skills/vue-router-best-practices/reference/router-navigation-guard-infinite-loop.md +187 -0
- package/skills/vue-router-best-practices/reference/router-navigation-guard-next-deprecated.md +150 -0
- package/skills/vue-router-best-practices/reference/router-param-change-no-lifecycle.md +181 -0
- package/skills/vue-router-best-practices/reference/router-simple-routing-cleanup.md +209 -0
- package/skills/vue-router-best-practices/reference/router-use-vue-router-for-production.md +183 -0
- package/skills/vue-testing-best-practices/LICENSE.md +21 -0
- package/skills/vue-testing-best-practices/SKILL.md +29 -0
- package/skills/vue-testing-best-practices/SYNC.md +5 -0
- package/skills/vue-testing-best-practices/reference/async-component-testing.md +163 -0
- package/skills/vue-testing-best-practices/reference/teleport-testing-complexity.md +158 -0
- package/skills/vue-testing-best-practices/reference/testing-async-await-flushpromises.md +175 -0
- package/skills/vue-testing-best-practices/reference/testing-browser-vs-node-runners.md +208 -0
- package/skills/vue-testing-best-practices/reference/testing-component-blackbox-approach.md +144 -0
- package/skills/vue-testing-best-practices/reference/testing-composables-helper-wrapper.md +238 -0
- package/skills/vue-testing-best-practices/reference/testing-e2e-playwright-recommended.md +242 -0
- package/skills/vue-testing-best-practices/reference/testing-no-snapshot-only.md +197 -0
- package/skills/vue-testing-best-practices/reference/testing-pinia-store-setup.md +228 -0
- package/skills/vue-testing-best-practices/reference/testing-suspense-async-components.md +229 -0
- package/skills/vue-testing-best-practices/reference/testing-vitest-recommended-for-vue.md +204 -0
- package/skills/vueuse-functions/LICENSE.md +21 -0
- package/skills/vueuse-functions/SKILL.md +419 -0
- package/skills/vueuse-functions/SYNC.md +5 -0
- package/skills/vueuse-functions/references/computedAsync.md +195 -0
- package/skills/vueuse-functions/references/computedEager.md +62 -0
- package/skills/vueuse-functions/references/computedInject.md +137 -0
- package/skills/vueuse-functions/references/computedWithControl.md +98 -0
- package/skills/vueuse-functions/references/createEventHook.md +86 -0
- package/skills/vueuse-functions/references/createGenericProjection.md +25 -0
- package/skills/vueuse-functions/references/createGlobalState.md +95 -0
- package/skills/vueuse-functions/references/createInjectionState.md +215 -0
- package/skills/vueuse-functions/references/createProjection.md +31 -0
- package/skills/vueuse-functions/references/createRef.md +54 -0
- package/skills/vueuse-functions/references/createReusableTemplate.md +357 -0
- package/skills/vueuse-functions/references/createSharedComposable.md +42 -0
- package/skills/vueuse-functions/references/createTemplatePromise.md +306 -0
- package/skills/vueuse-functions/references/createUnrefFn.md +51 -0
- package/skills/vueuse-functions/references/extendRef.md +76 -0
- package/skills/vueuse-functions/references/from.md +80 -0
- package/skills/vueuse-functions/references/get.md +30 -0
- package/skills/vueuse-functions/references/injectLocal.md +35 -0
- package/skills/vueuse-functions/references/isDefined.md +31 -0
- package/skills/vueuse-functions/references/logicAnd.md +40 -0
- package/skills/vueuse-functions/references/logicNot.md +36 -0
- package/skills/vueuse-functions/references/logicOr.md +40 -0
- package/skills/vueuse-functions/references/makeDestructurable.md +41 -0
- package/skills/vueuse-functions/references/onClickOutside.md +221 -0
- package/skills/vueuse-functions/references/onElementRemoval.md +88 -0
- package/skills/vueuse-functions/references/onKeyStroke.md +211 -0
- package/skills/vueuse-functions/references/onLongPress.md +227 -0
- package/skills/vueuse-functions/references/onStartTyping.md +53 -0
- package/skills/vueuse-functions/references/provideLocal.md +37 -0
- package/skills/vueuse-functions/references/reactify.md +144 -0
- package/skills/vueuse-functions/references/reactifyObject.md +62 -0
- package/skills/vueuse-functions/references/reactiveComputed.md +34 -0
- package/skills/vueuse-functions/references/reactiveOmit.md +86 -0
- package/skills/vueuse-functions/references/reactivePick.md +106 -0
- package/skills/vueuse-functions/references/refAutoReset.md +46 -0
- package/skills/vueuse-functions/references/refDebounced.md +81 -0
- package/skills/vueuse-functions/references/refDefault.md +36 -0
- package/skills/vueuse-functions/references/refManualReset.md +44 -0
- package/skills/vueuse-functions/references/refThrottled.md +99 -0
- package/skills/vueuse-functions/references/refWithControl.md +146 -0
- package/skills/vueuse-functions/references/set.md +30 -0
- package/skills/vueuse-functions/references/syncRef.md +195 -0
- package/skills/vueuse-functions/references/syncRefs.md +128 -0
- package/skills/vueuse-functions/references/templateRef.md +86 -0
- package/skills/vueuse-functions/references/toObserver.md +38 -0
- package/skills/vueuse-functions/references/toReactive.md +41 -0
- package/skills/vueuse-functions/references/toRef.md +75 -0
- package/skills/vueuse-functions/references/toRefs.md +81 -0
- package/skills/vueuse-functions/references/tryOnBeforeMount.md +34 -0
- package/skills/vueuse-functions/references/tryOnBeforeUnmount.md +32 -0
- package/skills/vueuse-functions/references/tryOnMounted.md +34 -0
- package/skills/vueuse-functions/references/tryOnScopeDispose.md +31 -0
- package/skills/vueuse-functions/references/tryOnUnmounted.md +32 -0
- package/skills/vueuse-functions/references/unrefElement.md +54 -0
- package/skills/vueuse-functions/references/until.md +161 -0
- package/skills/vueuse-functions/references/useAbs.md +31 -0
- package/skills/vueuse-functions/references/useActiveElement.md +85 -0
- package/skills/vueuse-functions/references/useAnimate.md +181 -0
- package/skills/vueuse-functions/references/useArrayDifference.md +84 -0
- package/skills/vueuse-functions/references/useArrayEvery.md +59 -0
- package/skills/vueuse-functions/references/useArrayFilter.md +63 -0
- package/skills/vueuse-functions/references/useArrayFind.md +50 -0
- package/skills/vueuse-functions/references/useArrayFindIndex.md +59 -0
- package/skills/vueuse-functions/references/useArrayFindLast.md +52 -0
- package/skills/vueuse-functions/references/useArrayIncludes.md +63 -0
- package/skills/vueuse-functions/references/useArrayJoin.md +74 -0
- package/skills/vueuse-functions/references/useArrayMap.md +59 -0
- package/skills/vueuse-functions/references/useArrayReduce.md +81 -0
- package/skills/vueuse-functions/references/useArraySome.md +59 -0
- package/skills/vueuse-functions/references/useArrayUnique.md +76 -0
- package/skills/vueuse-functions/references/useAsyncQueue.md +136 -0
- package/skills/vueuse-functions/references/useAsyncState.md +185 -0
- package/skills/vueuse-functions/references/useAsyncValidator.md +70 -0
- package/skills/vueuse-functions/references/useAuth.md +123 -0
- package/skills/vueuse-functions/references/useAverage.md +36 -0
- package/skills/vueuse-functions/references/useAxios.md +325 -0
- package/skills/vueuse-functions/references/useBase64.md +136 -0
- package/skills/vueuse-functions/references/useBattery.md +78 -0
- package/skills/vueuse-functions/references/useBluetooth.md +175 -0
- package/skills/vueuse-functions/references/useBreakpoints.md +172 -0
- package/skills/vueuse-functions/references/useBroadcastChannel.md +74 -0
- package/skills/vueuse-functions/references/useBrowserLocation.md +83 -0
- package/skills/vueuse-functions/references/useCached.md +52 -0
- package/skills/vueuse-functions/references/useCeil.md +31 -0
- package/skills/vueuse-functions/references/useChangeCase.md +79 -0
- package/skills/vueuse-functions/references/useClamp.md +85 -0
- package/skills/vueuse-functions/references/useClipboard.md +123 -0
- package/skills/vueuse-functions/references/useClipboardItems.md +94 -0
- package/skills/vueuse-functions/references/useCloned.md +91 -0
- package/skills/vueuse-functions/references/useColorMode.md +172 -0
- package/skills/vueuse-functions/references/useConfirmDialog.md +159 -0
- package/skills/vueuse-functions/references/useCookies.md +162 -0
- package/skills/vueuse-functions/references/useCountdown.md +105 -0
- package/skills/vueuse-functions/references/useCounter.md +86 -0
- package/skills/vueuse-functions/references/useCssSupports.md +35 -0
- package/skills/vueuse-functions/references/useCssVar.md +50 -0
- package/skills/vueuse-functions/references/useCurrentElement.md +61 -0
- package/skills/vueuse-functions/references/useCycleList.md +75 -0
- package/skills/vueuse-functions/references/useDark.md +144 -0
- package/skills/vueuse-functions/references/useDateFormat.md +145 -0
- package/skills/vueuse-functions/references/useDebounceFn.md +100 -0
- package/skills/vueuse-functions/references/useDebouncedRefHistory.md +40 -0
- package/skills/vueuse-functions/references/useDeviceMotion.md +86 -0
- package/skills/vueuse-functions/references/useDeviceOrientation.md +62 -0
- package/skills/vueuse-functions/references/useDevicePixelRatio.md +44 -0
- package/skills/vueuse-functions/references/useDevicesList.md +90 -0
- package/skills/vueuse-functions/references/useDisplayMedia.md +71 -0
- package/skills/vueuse-functions/references/useDocumentVisibility.md +45 -0
- package/skills/vueuse-functions/references/useDraggable.md +317 -0
- package/skills/vueuse-functions/references/useDrauu.md +65 -0
- package/skills/vueuse-functions/references/useDropZone.md +83 -0
- package/skills/vueuse-functions/references/useElementBounding.md +131 -0
- package/skills/vueuse-functions/references/useElementByPoint.md +48 -0
- package/skills/vueuse-functions/references/useElementHover.md +79 -0
- package/skills/vueuse-functions/references/useElementSize.md +78 -0
- package/skills/vueuse-functions/references/useElementVisibility.md +123 -0
- package/skills/vueuse-functions/references/useEventBus.md +101 -0
- package/skills/vueuse-functions/references/useEventListener.md +226 -0
- package/skills/vueuse-functions/references/useEventSource.md +204 -0
- package/skills/vueuse-functions/references/useExtractedObservable.md +198 -0
- package/skills/vueuse-functions/references/useEyeDropper.md +71 -0
- package/skills/vueuse-functions/references/useFavicon.md +67 -0
- package/skills/vueuse-functions/references/useFetch.md +546 -0
- package/skills/vueuse-functions/references/useFileDialog.md +91 -0
- package/skills/vueuse-functions/references/useFileSystemAccess.md +162 -0
- package/skills/vueuse-functions/references/useFirestore.md +129 -0
- package/skills/vueuse-functions/references/useFloor.md +31 -0
- package/skills/vueuse-functions/references/useFocus.md +99 -0
- package/skills/vueuse-functions/references/useFocusTrap.md +245 -0
- package/skills/vueuse-functions/references/useFocusWithin.md +57 -0
- package/skills/vueuse-functions/references/useFps.md +28 -0
- package/skills/vueuse-functions/references/useFullscreen.md +75 -0
- package/skills/vueuse-functions/references/useFuse.md +107 -0
- package/skills/vueuse-functions/references/useGamepad.md +222 -0
- package/skills/vueuse-functions/references/useGeolocation.md +85 -0
- package/skills/vueuse-functions/references/useIDBKeyval.md +93 -0
- package/skills/vueuse-functions/references/useIdle.md +88 -0
- package/skills/vueuse-functions/references/useImage.md +86 -0
- package/skills/vueuse-functions/references/useInfiniteScroll.md +157 -0
- package/skills/vueuse-functions/references/useIntersectionObserver.md +118 -0
- package/skills/vueuse-functions/references/useInterval.md +112 -0
- package/skills/vueuse-functions/references/useIntervalFn.md +50 -0
- package/skills/vueuse-functions/references/useIpcRenderer.md +144 -0
- package/skills/vueuse-functions/references/useIpcRendererInvoke.md +58 -0
- package/skills/vueuse-functions/references/useIpcRendererOn.md +52 -0
- package/skills/vueuse-functions/references/useJwt.md +57 -0
- package/skills/vueuse-functions/references/useKeyModifier.md +87 -0
- package/skills/vueuse-functions/references/useLastChanged.md +63 -0
- package/skills/vueuse-functions/references/useLocalStorage.md +41 -0
- package/skills/vueuse-functions/references/useMagicKeys.md +245 -0
- package/skills/vueuse-functions/references/useManualRefHistory.md +204 -0
- package/skills/vueuse-functions/references/useMath.md +47 -0
- package/skills/vueuse-functions/references/useMax.md +36 -0
- package/skills/vueuse-functions/references/useMediaControls.md +571 -0
- package/skills/vueuse-functions/references/useMediaQuery.md +53 -0
- package/skills/vueuse-functions/references/useMemoize.md +175 -0
- package/skills/vueuse-functions/references/useMemory.md +71 -0
- package/skills/vueuse-functions/references/useMin.md +36 -0
- package/skills/vueuse-functions/references/useMounted.md +38 -0
- package/skills/vueuse-functions/references/useMouse.md +113 -0
- package/skills/vueuse-functions/references/useMouseInElement.md +123 -0
- package/skills/vueuse-functions/references/useMousePressed.md +112 -0
- package/skills/vueuse-functions/references/useMutationObserver.md +61 -0
- package/skills/vueuse-functions/references/useNProgress.md +78 -0
- package/skills/vueuse-functions/references/useNavigatorLanguage.md +57 -0
- package/skills/vueuse-functions/references/useNetwork.md +106 -0
- package/skills/vueuse-functions/references/useNow.md +79 -0
- package/skills/vueuse-functions/references/useObjectUrl.md +55 -0
- package/skills/vueuse-functions/references/useObservable.md +91 -0
- package/skills/vueuse-functions/references/useOffsetPagination.md +199 -0
- package/skills/vueuse-functions/references/useOnline.md +41 -0
- package/skills/vueuse-functions/references/usePageLeave.md +42 -0
- package/skills/vueuse-functions/references/useParallax.md +58 -0
- package/skills/vueuse-functions/references/useParentElement.md +54 -0
- package/skills/vueuse-functions/references/usePerformanceObserver.md +48 -0
- package/skills/vueuse-functions/references/usePermission.md +79 -0
- package/skills/vueuse-functions/references/usePointer.md +89 -0
- package/skills/vueuse-functions/references/usePointerLock.md +60 -0
- package/skills/vueuse-functions/references/usePointerSwipe.md +80 -0
- package/skills/vueuse-functions/references/usePrecision.md +49 -0
- package/skills/vueuse-functions/references/usePreferredColorScheme.md +42 -0
- package/skills/vueuse-functions/references/usePreferredContrast.md +42 -0
- package/skills/vueuse-functions/references/usePreferredDark.md +41 -0
- package/skills/vueuse-functions/references/usePreferredLanguages.md +41 -0
- package/skills/vueuse-functions/references/usePreferredReducedMotion.md +42 -0
- package/skills/vueuse-functions/references/usePreferredReducedTransparency.md +42 -0
- package/skills/vueuse-functions/references/usePrevious.md +40 -0
- package/skills/vueuse-functions/references/useProjection.md +38 -0
- package/skills/vueuse-functions/references/useQRCode.md +53 -0
- package/skills/vueuse-functions/references/useRTDB.md +83 -0
- package/skills/vueuse-functions/references/useRafFn.md +68 -0
- package/skills/vueuse-functions/references/useRefHistory.md +285 -0
- package/skills/vueuse-functions/references/useResizeObserver.md +109 -0
- package/skills/vueuse-functions/references/useRound.md +31 -0
- package/skills/vueuse-functions/references/useRouteHash.md +27 -0
- package/skills/vueuse-functions/references/useRouteParams.md +38 -0
- package/skills/vueuse-functions/references/useRouteQuery.md +79 -0
- package/skills/vueuse-functions/references/useSSRWidth.md +47 -0
- package/skills/vueuse-functions/references/useScreenOrientation.md +96 -0
- package/skills/vueuse-functions/references/useScreenSafeArea.md +60 -0
- package/skills/vueuse-functions/references/useScriptTag.md +116 -0
- package/skills/vueuse-functions/references/useScroll.md +238 -0
- package/skills/vueuse-functions/references/useScrollLock.md +66 -0
- package/skills/vueuse-functions/references/useSessionStorage.md +41 -0
- package/skills/vueuse-functions/references/useShare.md +68 -0
- package/skills/vueuse-functions/references/useSortable.md +235 -0
- package/skills/vueuse-functions/references/useSorted.md +90 -0
- package/skills/vueuse-functions/references/useSpeechRecognition.md +94 -0
- package/skills/vueuse-functions/references/useSpeechSynthesis.md +105 -0
- package/skills/vueuse-functions/references/useStepper.md +137 -0
- package/skills/vueuse-functions/references/useStorage.md +278 -0
- package/skills/vueuse-functions/references/useStorageAsync.md +136 -0
- package/skills/vueuse-functions/references/useStyleTag.md +131 -0
- package/skills/vueuse-functions/references/useSubject.md +77 -0
- package/skills/vueuse-functions/references/useSubscription.md +33 -0
- package/skills/vueuse-functions/references/useSum.md +36 -0
- package/skills/vueuse-functions/references/useSupported.md +29 -0
- package/skills/vueuse-functions/references/useSwipe.md +75 -0
- package/skills/vueuse-functions/references/useTemplateRefsList.md +37 -0
- package/skills/vueuse-functions/references/useTextDirection.md +75 -0
- package/skills/vueuse-functions/references/useTextSelection.md +40 -0
- package/skills/vueuse-functions/references/useTextareaAutosize.md +97 -0
- package/skills/vueuse-functions/references/useThrottleFn.md +57 -0
- package/skills/vueuse-functions/references/useThrottledRefHistory.md +47 -0
- package/skills/vueuse-functions/references/useTimeAgo.md +154 -0
- package/skills/vueuse-functions/references/useTimeAgoIntl.md +117 -0
- package/skills/vueuse-functions/references/useTimeout.md +113 -0
- package/skills/vueuse-functions/references/useTimeoutFn.md +51 -0
- package/skills/vueuse-functions/references/useTimeoutPoll.md +47 -0
- package/skills/vueuse-functions/references/useTimestamp.md +89 -0
- package/skills/vueuse-functions/references/useTitle.md +113 -0
- package/skills/vueuse-functions/references/useToNumber.md +54 -0
- package/skills/vueuse-functions/references/useToString.md +34 -0
- package/skills/vueuse-functions/references/useToggle.md +103 -0
- package/skills/vueuse-functions/references/useTransition.md +265 -0
- package/skills/vueuse-functions/references/useTrunc.md +33 -0
- package/skills/vueuse-functions/references/useUrlSearchParams.md +121 -0
- package/skills/vueuse-functions/references/useUserMedia.md +1138 -0
- package/skills/vueuse-functions/references/useVModel.md +182 -0
- package/skills/vueuse-functions/references/useVModels.md +67 -0
- package/skills/vueuse-functions/references/useVibrate.md +87 -0
- package/skills/vueuse-functions/references/useVirtualList.md +182 -0
- package/skills/vueuse-functions/references/useWakeLock.md +50 -0
- package/skills/vueuse-functions/references/useWebNotification.md +176 -0
- package/skills/vueuse-functions/references/useWebSocket.md +299 -0
- package/skills/vueuse-functions/references/useWebWorker.md +60 -0
- package/skills/vueuse-functions/references/useWebWorkerFn.md +102 -0
- package/skills/vueuse-functions/references/useWindowFocus.md +46 -0
- package/skills/vueuse-functions/references/useWindowScroll.md +61 -0
- package/skills/vueuse-functions/references/useWindowSize.md +76 -0
- package/skills/vueuse-functions/references/useZoomFactor.md +53 -0
- package/skills/vueuse-functions/references/useZoomLevel.md +53 -0
- package/skills/vueuse-functions/references/watchArray.md +53 -0
- package/skills/vueuse-functions/references/watchAtMost.md +55 -0
- package/skills/vueuse-functions/references/watchDebounced.md +101 -0
- package/skills/vueuse-functions/references/watchDeep.md +54 -0
- package/skills/vueuse-functions/references/watchExtractedObservable.md +192 -0
- package/skills/vueuse-functions/references/watchIgnorable.md +120 -0
- package/skills/vueuse-functions/references/watchImmediate.md +44 -0
- package/skills/vueuse-functions/references/watchOnce.md +41 -0
- package/skills/vueuse-functions/references/watchPausable.md +86 -0
- package/skills/vueuse-functions/references/watchThrottled.md +108 -0
- package/skills/vueuse-functions/references/watchTriggerable.md +98 -0
- package/skills/vueuse-functions/references/watchWithFilter.md +54 -0
- package/skills/vueuse-functions/references/whenever.md +100 -0
- package/skills/web-design-guidelines/SKILL.md +39 -0
- package/skills/web-design-guidelines/SYNC.md +5 -0
- package/tsconfig.json +17 -0
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Navigation Guard Infinite Redirect Loops
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: Misconfigured navigation guards can trap users in infinite redirect loops, crashing the browser or making the app unusable
|
|
5
|
+
type: gotcha
|
|
6
|
+
tags: [vue3, vue-router, navigation-guards, redirect, debugging]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Navigation Guard Infinite Redirect Loops
|
|
10
|
+
|
|
11
|
+
**Impact: HIGH** - A common mistake in navigation guards is creating conditions that cause infinite redirects. Vue Router will detect this and show a warning, but in production, it can crash the browser or create a broken user experience.
|
|
12
|
+
|
|
13
|
+
## Task Checklist
|
|
14
|
+
|
|
15
|
+
- [ ] Always check if already on target route before redirecting
|
|
16
|
+
- [ ] Test guard logic with all possible navigation scenarios
|
|
17
|
+
- [ ] Add route meta to control which routes need protection
|
|
18
|
+
- [ ] Use Vue Router devtools to debug redirect chains
|
|
19
|
+
|
|
20
|
+
## The Problem
|
|
21
|
+
|
|
22
|
+
```javascript
|
|
23
|
+
// WRONG: Infinite loop - always redirects to login, even when on login!
|
|
24
|
+
router.beforeEach((to, from) => {
|
|
25
|
+
if (!isAuthenticated()) {
|
|
26
|
+
return '/login' // Redirects to /login, which triggers guard again...
|
|
27
|
+
}
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
// WRONG: Circular redirect between two routes
|
|
31
|
+
router.beforeEach((to, from) => {
|
|
32
|
+
if (to.path === '/dashboard' && !hasProfile()) {
|
|
33
|
+
return '/profile'
|
|
34
|
+
}
|
|
35
|
+
if (to.path === '/profile' && !isVerified()) {
|
|
36
|
+
return '/dashboard' // Back to dashboard, which goes to profile...
|
|
37
|
+
}
|
|
38
|
+
})
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**Error you'll see:**
|
|
42
|
+
```
|
|
43
|
+
[Vue Router warn]: Detected an infinite redirection in a navigation guard when going from "/" to "/login". Aborting to avoid a Stack Overflow.
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Solution 1: Exclude Target Route
|
|
47
|
+
|
|
48
|
+
```javascript
|
|
49
|
+
// CORRECT: Don't redirect if already going to login
|
|
50
|
+
router.beforeEach((to, from) => {
|
|
51
|
+
if (!isAuthenticated() && to.path !== '/login') {
|
|
52
|
+
return '/login'
|
|
53
|
+
}
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
// CORRECT: Use route name for cleaner check
|
|
57
|
+
router.beforeEach((to, from) => {
|
|
58
|
+
const publicPages = ['Login', 'Register', 'ForgotPassword']
|
|
59
|
+
|
|
60
|
+
if (!isAuthenticated() && !publicPages.includes(to.name)) {
|
|
61
|
+
return { name: 'Login' }
|
|
62
|
+
}
|
|
63
|
+
})
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Solution 2: Use Route Meta Fields
|
|
67
|
+
|
|
68
|
+
```javascript
|
|
69
|
+
// router.js
|
|
70
|
+
const routes = [
|
|
71
|
+
{
|
|
72
|
+
path: '/login',
|
|
73
|
+
name: 'Login',
|
|
74
|
+
component: Login,
|
|
75
|
+
meta: { requiresAuth: false }
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
path: '/dashboard',
|
|
79
|
+
name: 'Dashboard',
|
|
80
|
+
component: Dashboard,
|
|
81
|
+
meta: { requiresAuth: true }
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
path: '/public',
|
|
85
|
+
name: 'PublicPage',
|
|
86
|
+
component: PublicPage,
|
|
87
|
+
meta: { requiresAuth: false }
|
|
88
|
+
}
|
|
89
|
+
]
|
|
90
|
+
|
|
91
|
+
// Guard checks meta field
|
|
92
|
+
router.beforeEach((to, from) => {
|
|
93
|
+
// Only redirect if route requires auth
|
|
94
|
+
if (to.meta.requiresAuth && !isAuthenticated()) {
|
|
95
|
+
return { name: 'Login', query: { redirect: to.fullPath } }
|
|
96
|
+
}
|
|
97
|
+
})
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Solution 3: Handle Redirect Chains Carefully
|
|
101
|
+
|
|
102
|
+
```javascript
|
|
103
|
+
// CORRECT: Break potential circular redirects
|
|
104
|
+
router.beforeEach((to, from) => {
|
|
105
|
+
// Prevent redirect loops by tracking redirect depth
|
|
106
|
+
const redirectCount = to.query._redirectCount || 0
|
|
107
|
+
|
|
108
|
+
if (redirectCount > 3) {
|
|
109
|
+
console.error('Too many redirects, stopping at:', to.path)
|
|
110
|
+
return '/error' // Escape hatch
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (needsRedirect(to)) {
|
|
114
|
+
return {
|
|
115
|
+
path: getRedirectTarget(to),
|
|
116
|
+
query: { ...to.query, _redirectCount: redirectCount + 1 }
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
})
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Solution 4: Centralized Redirect Logic
|
|
123
|
+
|
|
124
|
+
```javascript
|
|
125
|
+
// guards/auth.js
|
|
126
|
+
export function createAuthGuard(router) {
|
|
127
|
+
const publicRoutes = new Set(['Login', 'Register', 'ForgotPassword', 'ResetPassword'])
|
|
128
|
+
const guestOnlyRoutes = new Set(['Login', 'Register'])
|
|
129
|
+
|
|
130
|
+
router.beforeEach((to, from) => {
|
|
131
|
+
const isPublic = publicRoutes.has(to.name)
|
|
132
|
+
const isGuestOnly = guestOnlyRoutes.has(to.name)
|
|
133
|
+
const isLoggedIn = isAuthenticated()
|
|
134
|
+
|
|
135
|
+
// Not logged in, trying to access protected route
|
|
136
|
+
if (!isLoggedIn && !isPublic) {
|
|
137
|
+
return { name: 'Login', query: { redirect: to.fullPath } }
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Logged in, trying to access guest-only route (like login page)
|
|
141
|
+
if (isLoggedIn && isGuestOnly) {
|
|
142
|
+
return { name: 'Dashboard' }
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// All other cases: proceed
|
|
146
|
+
})
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Debugging Redirect Loops
|
|
151
|
+
|
|
152
|
+
```javascript
|
|
153
|
+
// Add logging to understand the redirect chain
|
|
154
|
+
router.beforeEach((to, from) => {
|
|
155
|
+
console.log(`Navigation: ${from.path} -> ${to.path}`)
|
|
156
|
+
console.log('Auth state:', isAuthenticated())
|
|
157
|
+
console.log('Route meta:', to.meta)
|
|
158
|
+
|
|
159
|
+
// Your guard logic here
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
// Or use afterEach for confirmed navigations
|
|
163
|
+
router.afterEach((to, from) => {
|
|
164
|
+
console.log(`Navigated: ${from.path} -> ${to.path}`)
|
|
165
|
+
})
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## Common Redirect Loop Patterns
|
|
169
|
+
|
|
170
|
+
| Pattern | Problem | Fix |
|
|
171
|
+
|---------|---------|-----|
|
|
172
|
+
| Auth check without exclusion | Login redirects to login | Exclude `/login` from check |
|
|
173
|
+
| Role-based with circular deps | Admin -> User -> Admin | Use single source of truth for role requirements |
|
|
174
|
+
| Onboarding flow | Step 1 -> Step 2 -> Step 1 | Track completion state properly |
|
|
175
|
+
| Redirect query handling | Reading redirect creates new redirect | Process redirect only once |
|
|
176
|
+
|
|
177
|
+
## Key Points
|
|
178
|
+
|
|
179
|
+
1. **Always exclude the target route** - Never redirect to a route that would trigger the same redirect
|
|
180
|
+
2. **Use route meta fields** - Cleaner than path string comparisons
|
|
181
|
+
3. **Test edge cases** - Direct URL access, refresh, back button
|
|
182
|
+
4. **Add logging during development** - Helps trace redirect chains
|
|
183
|
+
5. **Have an escape hatch** - Error page or max redirect count
|
|
184
|
+
|
|
185
|
+
## Reference
|
|
186
|
+
- [Vue Router Navigation Guards](https://router.vuejs.org/guide/advanced/navigation-guards.html)
|
|
187
|
+
- [Vue Router Route Meta Fields](https://router.vuejs.org/guide/advanced/meta.html)
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Vue Router Navigation Guard next() Function Deprecated
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: Using the deprecated next() function incorrectly causes navigation to hang, infinite loops, or silent failures
|
|
5
|
+
type: gotcha
|
|
6
|
+
tags: [vue3, vue-router, navigation-guards, migration, async]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Vue Router Navigation Guard next() Function Deprecated
|
|
10
|
+
|
|
11
|
+
**Impact: HIGH** - The third `next()` argument in navigation guards is deprecated in Vue Router 4. While still supported for backward compatibility, using it incorrectly is one of the most common sources of bugs: calling it multiple times, forgetting to call it, or calling it conditionally without proper logic.
|
|
12
|
+
|
|
13
|
+
## Task Checklist
|
|
14
|
+
|
|
15
|
+
- [ ] Refactor guards to use return-based syntax instead of next()
|
|
16
|
+
- [ ] Remove all next() calls from navigation guards
|
|
17
|
+
- [ ] Use async/await pattern for asynchronous checks
|
|
18
|
+
- [ ] Return false to cancel, return route to redirect, return nothing to proceed
|
|
19
|
+
|
|
20
|
+
## The Problem
|
|
21
|
+
|
|
22
|
+
```javascript
|
|
23
|
+
// WRONG: Using deprecated next() function
|
|
24
|
+
router.beforeEach((to, from, next) => {
|
|
25
|
+
if (!isAuthenticated) {
|
|
26
|
+
next('/login') // Easy to forget this call
|
|
27
|
+
}
|
|
28
|
+
// BUG: next() not called when authenticated - navigation hangs!
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
// WRONG: Multiple next() calls
|
|
32
|
+
router.beforeEach((to, from, next) => {
|
|
33
|
+
if (!isAuthenticated) {
|
|
34
|
+
next('/login')
|
|
35
|
+
}
|
|
36
|
+
next() // BUG: Called twice when not authenticated!
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
// WRONG: next() in async code without proper handling
|
|
40
|
+
router.beforeEach(async (to, from, next) => {
|
|
41
|
+
const user = await fetchUser()
|
|
42
|
+
if (!user) {
|
|
43
|
+
next('/login')
|
|
44
|
+
}
|
|
45
|
+
next() // Still gets called even after redirect!
|
|
46
|
+
})
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Solution: Use Return-Based Guards
|
|
50
|
+
|
|
51
|
+
```javascript
|
|
52
|
+
// CORRECT: Return-based syntax (modern Vue Router 4+)
|
|
53
|
+
router.beforeEach((to, from) => {
|
|
54
|
+
if (!isAuthenticated) {
|
|
55
|
+
return '/login' // Redirect
|
|
56
|
+
}
|
|
57
|
+
// Return nothing (undefined) to proceed
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
// CORRECT: Return false to cancel navigation
|
|
61
|
+
router.beforeEach((to, from) => {
|
|
62
|
+
if (hasUnsavedChanges) {
|
|
63
|
+
return false // Cancel navigation
|
|
64
|
+
}
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
// CORRECT: Async with return-based syntax
|
|
68
|
+
router.beforeEach(async (to, from) => {
|
|
69
|
+
const user = await fetchUser()
|
|
70
|
+
if (!user) {
|
|
71
|
+
return { name: 'Login', query: { redirect: to.fullPath } }
|
|
72
|
+
}
|
|
73
|
+
// Proceed with navigation
|
|
74
|
+
})
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Return Values Explained
|
|
78
|
+
|
|
79
|
+
```javascript
|
|
80
|
+
router.beforeEach((to, from) => {
|
|
81
|
+
// Return nothing/undefined - allow navigation
|
|
82
|
+
return
|
|
83
|
+
|
|
84
|
+
// Return false - cancel navigation, stay on current route
|
|
85
|
+
return false
|
|
86
|
+
|
|
87
|
+
// Return string path - redirect to path
|
|
88
|
+
return '/login'
|
|
89
|
+
|
|
90
|
+
// Return route object - redirect with full control
|
|
91
|
+
return { name: 'Login', query: { redirect: to.fullPath } }
|
|
92
|
+
|
|
93
|
+
// Return Error - cancel and trigger router.onError()
|
|
94
|
+
return new Error('Navigation cancelled')
|
|
95
|
+
})
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## If You Must Use next() (Legacy Code)
|
|
99
|
+
|
|
100
|
+
If maintaining legacy code that uses `next()`, follow these rules strictly:
|
|
101
|
+
|
|
102
|
+
```javascript
|
|
103
|
+
// CORRECT: Exactly one next() call per code path
|
|
104
|
+
router.beforeEach((to, from, next) => {
|
|
105
|
+
if (!isAuthenticated) {
|
|
106
|
+
next('/login')
|
|
107
|
+
return // CRITICAL: Exit after calling next()
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (!hasPermission(to)) {
|
|
111
|
+
next('/forbidden')
|
|
112
|
+
return // CRITICAL: Exit after calling next()
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
next() // Only reached if all checks pass
|
|
116
|
+
})
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Error Handling Pattern
|
|
120
|
+
|
|
121
|
+
```javascript
|
|
122
|
+
router.beforeEach(async (to, from) => {
|
|
123
|
+
try {
|
|
124
|
+
await validateAccess(to)
|
|
125
|
+
// Proceed
|
|
126
|
+
} catch (error) {
|
|
127
|
+
if (error.status === 401) {
|
|
128
|
+
return '/login'
|
|
129
|
+
}
|
|
130
|
+
if (error.status === 403) {
|
|
131
|
+
return '/forbidden'
|
|
132
|
+
}
|
|
133
|
+
// Log error and proceed anyway (or return false)
|
|
134
|
+
console.error('Access validation failed:', error)
|
|
135
|
+
return false
|
|
136
|
+
}
|
|
137
|
+
})
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Key Points
|
|
141
|
+
|
|
142
|
+
1. **Prefer return-based syntax** - Cleaner, less error-prone, modern standard
|
|
143
|
+
2. **next() must be called exactly once** - If using legacy syntax, ensure single call per path
|
|
144
|
+
3. **Always return/exit after redirect** - Prevent multiple navigation actions
|
|
145
|
+
4. **Async guards work naturally** - Just return the redirect route or nothing
|
|
146
|
+
5. **Test all code paths** - Each branch must result in either return or next()
|
|
147
|
+
|
|
148
|
+
## Reference
|
|
149
|
+
- [Vue Router Navigation Guards](https://router.vuejs.org/guide/advanced/navigation-guards.html)
|
|
150
|
+
- [RFC: Remove next() from Navigation Guards](https://github.com/vuejs/rfcs/discussions/302)
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Route Param Changes Do Not Trigger Lifecycle Hooks
|
|
3
|
+
impact: HIGH
|
|
4
|
+
impactDescription: Navigating between routes with different params reuses the component instance, skipping created/mounted hooks and leaving stale data
|
|
5
|
+
type: gotcha
|
|
6
|
+
tags: [vue3, vue-router, lifecycle, params, reactivity]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Route Param Changes Do Not Trigger Lifecycle Hooks
|
|
10
|
+
|
|
11
|
+
**Impact: HIGH** - When navigating between routes that use the same component (e.g., `/users/1` to `/users/2`), Vue Router reuses the existing component instance for performance. This means `onMounted`, `created`, and other lifecycle hooks do NOT fire, leaving you with stale data from the previous route.
|
|
12
|
+
|
|
13
|
+
## Task Checklist
|
|
14
|
+
|
|
15
|
+
- [ ] Use `watch` on route params for data fetching
|
|
16
|
+
- [ ] Or use `onBeforeRouteUpdate` in-component guard
|
|
17
|
+
- [ ] Or use `:key="route.params.id"` to force re-creation (less efficient)
|
|
18
|
+
- [ ] Never rely solely on `onMounted` for route-param-dependent data
|
|
19
|
+
|
|
20
|
+
## The Problem
|
|
21
|
+
|
|
22
|
+
```vue
|
|
23
|
+
<!-- UserProfile.vue - Used for /users/:id -->
|
|
24
|
+
<script setup>
|
|
25
|
+
import { ref, onMounted } from 'vue'
|
|
26
|
+
import { useRoute } from 'vue-router'
|
|
27
|
+
|
|
28
|
+
const route = useRoute()
|
|
29
|
+
const user = ref(null)
|
|
30
|
+
|
|
31
|
+
// BUG: Only runs once when component first mounts!
|
|
32
|
+
// Navigating from /users/1 to /users/2 does NOT trigger this
|
|
33
|
+
onMounted(async () => {
|
|
34
|
+
user.value = await fetchUser(route.params.id)
|
|
35
|
+
})
|
|
36
|
+
</script>
|
|
37
|
+
|
|
38
|
+
<template>
|
|
39
|
+
<div>
|
|
40
|
+
<!-- Still shows User 1 data when navigating to /users/2! -->
|
|
41
|
+
<h1>{{ user?.name }}</h1>
|
|
42
|
+
</div>
|
|
43
|
+
</template>
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**Scenario:**
|
|
47
|
+
1. Visit `/users/1` - Component mounts, fetches User 1 data
|
|
48
|
+
2. Navigate to `/users/2` - Component is REUSED, onMounted doesn't run
|
|
49
|
+
3. UI still shows User 1's data!
|
|
50
|
+
|
|
51
|
+
## Solution 1: Watch Route Params (Recommended)
|
|
52
|
+
|
|
53
|
+
```vue
|
|
54
|
+
<script setup>
|
|
55
|
+
import { ref, watch } from 'vue'
|
|
56
|
+
import { useRoute } from 'vue-router'
|
|
57
|
+
|
|
58
|
+
const route = useRoute()
|
|
59
|
+
const user = ref(null)
|
|
60
|
+
const loading = ref(false)
|
|
61
|
+
|
|
62
|
+
// Watch for param changes - handles both initial load and navigation
|
|
63
|
+
watch(
|
|
64
|
+
() => route.params.id,
|
|
65
|
+
async (newId) => {
|
|
66
|
+
loading.value = true
|
|
67
|
+
user.value = await fetchUser(newId)
|
|
68
|
+
loading.value = false
|
|
69
|
+
},
|
|
70
|
+
{ immediate: true } // Run immediately for initial load
|
|
71
|
+
)
|
|
72
|
+
</script>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Solution 2: Use onBeforeRouteUpdate Guard
|
|
76
|
+
|
|
77
|
+
```vue
|
|
78
|
+
<script setup>
|
|
79
|
+
import { ref, onMounted } from 'vue'
|
|
80
|
+
import { useRoute, onBeforeRouteUpdate } from 'vue-router'
|
|
81
|
+
|
|
82
|
+
const route = useRoute()
|
|
83
|
+
const user = ref(null)
|
|
84
|
+
|
|
85
|
+
async function loadUser(id) {
|
|
86
|
+
user.value = await fetchUser(id)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Initial load
|
|
90
|
+
onMounted(() => loadUser(route.params.id))
|
|
91
|
+
|
|
92
|
+
// Handle param changes within same route
|
|
93
|
+
onBeforeRouteUpdate(async (to, from) => {
|
|
94
|
+
if (to.params.id !== from.params.id) {
|
|
95
|
+
await loadUser(to.params.id)
|
|
96
|
+
}
|
|
97
|
+
})
|
|
98
|
+
</script>
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Solution 3: Force Component Re-creation with Key
|
|
102
|
+
|
|
103
|
+
```vue
|
|
104
|
+
<!-- App.vue or parent component -->
|
|
105
|
+
<template>
|
|
106
|
+
<router-view :key="$route.fullPath" />
|
|
107
|
+
</template>
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**Tradeoffs:**
|
|
111
|
+
- Simple but less performant
|
|
112
|
+
- Destroys and recreates component on every param change
|
|
113
|
+
- Loses component state
|
|
114
|
+
- Use only when component state should reset completely
|
|
115
|
+
|
|
116
|
+
## Solution 4: Composable for Route-Reactive Data
|
|
117
|
+
|
|
118
|
+
```javascript
|
|
119
|
+
// composables/useRouteData.js
|
|
120
|
+
import { ref, watch } from 'vue'
|
|
121
|
+
import { useRoute } from 'vue-router'
|
|
122
|
+
|
|
123
|
+
export function useRouteData(paramName, fetcher) {
|
|
124
|
+
const route = useRoute()
|
|
125
|
+
const data = ref(null)
|
|
126
|
+
const loading = ref(false)
|
|
127
|
+
const error = ref(null)
|
|
128
|
+
|
|
129
|
+
watch(
|
|
130
|
+
() => route.params[paramName],
|
|
131
|
+
async (id) => {
|
|
132
|
+
if (!id) return
|
|
133
|
+
|
|
134
|
+
loading.value = true
|
|
135
|
+
error.value = null
|
|
136
|
+
|
|
137
|
+
try {
|
|
138
|
+
data.value = await fetcher(id)
|
|
139
|
+
} catch (e) {
|
|
140
|
+
error.value = e
|
|
141
|
+
} finally {
|
|
142
|
+
loading.value = false
|
|
143
|
+
}
|
|
144
|
+
},
|
|
145
|
+
{ immediate: true }
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
return { data, loading, error }
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
```vue
|
|
153
|
+
<!-- Usage in component -->
|
|
154
|
+
<script setup>
|
|
155
|
+
import { useRouteData } from '@/composables/useRouteData'
|
|
156
|
+
import { fetchUser } from '@/api/users'
|
|
157
|
+
|
|
158
|
+
const { data: user, loading, error } = useRouteData('id', fetchUser)
|
|
159
|
+
</script>
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## What Triggers vs. What Doesn't
|
|
163
|
+
|
|
164
|
+
| Navigation Type | Lifecycle Hooks | beforeRouteUpdate | Watch on params |
|
|
165
|
+
|----------------|-----------------|-------------------|-----------------|
|
|
166
|
+
| `/users/1` to `/posts/1` | YES | NO | YES |
|
|
167
|
+
| `/users/1` to `/users/2` | NO | YES | YES |
|
|
168
|
+
| `/users/1?tab=a` to `/users/1?tab=b` | NO | YES | NO (different watch) |
|
|
169
|
+
| `/users/1` to `/users/1` (same) | NO | NO | NO |
|
|
170
|
+
|
|
171
|
+
## Key Points
|
|
172
|
+
|
|
173
|
+
1. **Same route, different params = same component instance** - This is a performance optimization
|
|
174
|
+
2. **Lifecycle hooks only fire once** - When component first mounts
|
|
175
|
+
3. **Use `watch` with `immediate: true`** - Covers both initial load and updates
|
|
176
|
+
4. **`onBeforeRouteUpdate` is navigation-aware** - Good for data that must load before view updates
|
|
177
|
+
5. **`:key="route.fullPath"` is a sledgehammer** - Use only when necessary
|
|
178
|
+
|
|
179
|
+
## Reference
|
|
180
|
+
- [Vue Router Dynamic Route Matching](https://router.vuejs.org/guide/essentials/dynamic-matching.html#reacting-to-params-changes)
|
|
181
|
+
- [Vue School: Reacting to Param Changes](https://vueschool.io/lessons/reacting-to-param-changes)
|