Implementing Composable Architecture in Vue.js
Techniques for building modular and reusable components in Vue.js to enhance code maintainability and scalability.
0 likes
9 views
Rule Content
{ "title": "Implementing Composable Architecture in Vue.js", "description": "Techniques for building modular and reusable components in Vue.js to enhance code maintainability and scalability.", "category": "Vue Cursor Rules", "rules": [ { "name": "Organize Composables by Feature or Domain", "description": "Group composables based on their purpose or the feature they support to keep the project organized and facilitate code management.", "pattern": "src/composables/{feature}/use{Feature}.js", "examples": [ { "before": "src/composables/useAuth.js", "after": "src/composables/auth/useAuth.js" }, { "before": "src/composables/useFetch.js", "after": "src/composables/data/useFetch.js" } ] }, { "name": "Follow Consistent Naming Conventions", "description": "Prefix composables with 'use' and use descriptive names to clearly indicate their functionality.", "pattern": "use[A-Z][a-zA-Z]+", "examples": [ { "before": "fetchData.js", "after": "useFetchData.js" }, { "before": "auth.js", "after": "useAuth.js" } ] }, { "name": "Encapsulate State and Logic Together", "description": "Composables should encapsulate related state and logic, returning both in an object to promote modularity and reusability.", "pattern": "export function use[A-Z][a-zA-Z]+\\(\\) {.*return {.*};.*}", "examples": [ { "before": "export function useCounter() { const count = ref(0); const increment = () => count.value++; return increment; }", "after": "export function useCounter() { const count = ref(0); const increment = () => count.value++; return { count, increment }; }" } ] }, { "name": "Keep Composables Focused and Single-Responsibility", "description": "Ensure each composable addresses a single concern to simplify understanding, testing, and maintenance.", "pattern": "export function use[A-Z][a-zA-Z]+\\(\\) {.*}", "examples": [ { "before": "export function useAuthAndFetch() { /* authentication and data fetching logic */ }", "after": "export function useAuth() { /* authentication logic */ } export function useFetch() { /* data fetching logic */ }" } ] }, { "name": "Use TypeScript or JSDoc for Better Intellisense", "description": "Define types or use JSDoc annotations in composables to enhance code clarity and reduce bugs.", "pattern": "/\\*\\*.*@returns {.*}.*\\*/\\nexport function use[A-Z][a-zA-Z]+\\(\\) {.*}", "examples": [ { "before": "export function useAuth() { /* authentication logic */ }", "after": "/** * Manages user authentication state. * @returns {Object} - Authentication state and methods */ export function useAuth() { /* authentication logic */ }" } ] }, { "name": "Document Composables Thoroughly", "description": "Add comments explaining the purpose, parameters, and return values of composables to facilitate understanding and usage.", "pattern": "/\\*\\*.*\\*/\\nexport function use[A-Z][a-zA-Z]+\\(\\) {.*}", "examples": [ { "before": "export function useFetchData() { /* data fetching logic */ }", "after": "/** * Fetches data from the API. * @returns {Object} - Data and error state */ export function useFetchData() { /* data fetching logic */ }" } ] }, { "name": "Use Watchers and WatchEffects Carefully", "description": "Manage side effects and cleanup properly when using 'watch' or 'watchEffect' in composables to avoid memory leaks.", "pattern": "watch\\(.*\\) {.*onBeforeUnmount\\(.*\\);.*}", "examples": [ { "before": "watch(data, save);", "after": "const stopWatch = watch(data, save); onBeforeUnmount(() => { stopWatch(); });" } ] }, { "name": "Isolate API Calls in Composables", "description": "Keep API calls within their own composables to separate data-fetching logic from presentation components.", "pattern": "export function use[A-Z][a-zA-Z]+\\(\\) {.*axios\\.get\\(.*\\).*}", "examples": [ { "before": "export function useComponentLogic() { /* component logic */ axios.get('/api/data'); }", "after": "export function useFetchData() { /* data fetching logic */ axios.get('/api/data'); }" } ] }, { "name": "Avoid Overuse of Reactive Variables", "description": "Use reactive state only when necessary to minimize performance overhead and complexity.", "pattern": "const [a-zA-Z]+ = ref\\(.*\\);", "examples": [ { "before": "const isActive = ref(false);", "after": "let isActive = false;" } ] }, { "name": "Test Composables Independently", "description": "Write unit tests for composables to ensure their functionality before integrating them into components.", "pattern": "describe\\('use[A-Z][a-zA-Z]+', () => {.*it\\('.*', () => {.*expect\\(.*\\).toBe\\(.*\\);.*}.*});", "examples": [ { "before": "// No tests", "after": "describe('useFetchData', () => { it('fetches data successfully', () => { const { data } = useFetchData(); expect(data.value).toBeDefined(); }); });" } ] } ] }