npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, πŸ‘‹, I’m Ryan HefnerΒ  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you πŸ™

Β© 2024 – Pkg Stats / Ryan Hefner

vue-modular

v0.2.0

Published

> Helps you implement a folder-by-feature module structure in large Vue projects πŸ‘·β€πŸ‘·β€

Downloads

114

Readme

Vue Modular

Helps you implement a folder-by-feature module structure in large Vue projects πŸ‘·β€πŸ‘·β€

Building large Vue projects

When Vue projects grow, the classic folder-by-type folder structure can become unmanageable because dependencies across files are hard to refactor and mentally compute.

Instead, you should consider structuring your code into "features" that are encapsulated with their own components, vuex module, routes and more. Think of it as a structural design pattern that encourages encapsulation of related code.

The main purpose of this repo is simply to prescribe a scalable project structure. To ease the setup, this simple Vue plugin helps you do that easily by extracting vuex stores and router definitions from each module and registering them globally.

Plugin installation

Install the NPM module

yarn add vue-modular

In your main.js (or equivalent), add

import VueModular from 'vue-modular'
import foo from './modules/foo'
import bar from './modules/bar'

// simplified for example purpose
const router = new Router()
const store = new Vuex.Store()

// install the plugin with modules and router + store references
Vue.use(VueModular, {
  modules: {
    foo,
    bar
  },
  router,
  store
})

The plugin currently achieves three things:

  1. Vuex stores defined in each module are registered on the global vuex instance
  2. Vue router definitions in each module are merged and registered on the global router instance
  3. A vue instance helper vm.$modules is injected into all components which makes it easy to access custom values that each module can export

Recommended setup

Please see the example folder for a reference setup

Choose a folder structure that will with your local modules. Each module can be simple (foo below) or complex (bar below), depending on your need.

modules/
β”‚
β”œβ”€β”€ foo/
β”‚   β”œβ”€β”€ index.js
β”‚   β”œβ”€β”€ router.js
β”‚   β”œβ”€β”€ store.js
β”‚   └── ComponentA.vue
β”‚
└── bar/
    β”œβ”€β”€ index.js
    β”œβ”€β”€ router.js
    β”œβ”€β”€ store/
    β”‚   β”œβ”€β”€ mutations.js
    β”‚   β”œβ”€β”€ actions.js
    β”‚   └── getters.js
    β”‚
    β”œβ”€β”€ views/
    β”‚   β”œβ”€β”€ PageA.vue
    β”‚   └── PageB.vue
    β”‚
    β”œβ”€β”€ services/
    β”‚   β”œβ”€β”€ datasource.js
    β”‚   └── tracking.js
    β”‚
    └── tests/
        β”œβ”€β”€ services.spec.js
        └── views.spec.js

There's technically no restriction on how you structure your directory tree or what you name your files, as long as each module exports an object like this

// modules/foo/index.js

import router from './router.js'
import store from './store.js'

export default {
  router, // module vue router (if any)
  store, // module vuex store (if any)
  custom: {
    // optional extra info you to share
    foo: 'bar'
  }
}

The router and store objects are exactly what you'd expect and know from Vuex modules and Vue Router definitions

// modules/foo/router.js

import ComponentA from './ComponentA.vue'

export default {
  routes: [
    {
      path: '/foo',
      name: 'foo',
      component: ComponentA
    }
  ],
  beforeEach: (to, from, next) => {
    next()
  }
}
// modules/foo/store.js

export default {
  namespaced: true,
  state: {
    foo: []
  },
  mutations: {
    setFoo(state, foo) {
      state.foo = foo
    }
  },
  getters: {
    getFoo(state) {
      return state.foo
    }
  }
}

When to use it

Don't over-engineer prematurely

For small and medium-sized projects, the folder-by-type approach is usually simpler to navigate because it's helpful to have all your routes and stores in one place.

If you're a one or two people building a small Vue app, that's usually fine.

LIFT your code base

When projects grow to hundreds of components with large developer teams working on the same code base, things start to change.

What you're looking to achieve can be abbreviated LIFT: Structure the app such that you can Locate code quickly, Identify the code at a glance, keep the Flattest structure you can, and Try to be DRY

Do remember though that not all your code can or should be self-contained: base UI components, API client, general purpose utilities etc. should probably not be modules.

But an authentication module with it's own routes (ex. /login), store (ex. currentUser), tests (ex. login.spec.js) and view components (ex. Login.vue) is ideal for encapsulation.

Tips & tricks

Exposing stuff from modules

As a thumb rule, the more isolated you can keep your modules from each other and the rest of your codebase, the easier it will be to maintain.

However, sometimes you do want to export a component, service or utility function for other code to use. In these cases, I recommend that you do it explicitly and only from your module's index.js

// modules/foo/index.js

import ComponentA from './ComponentA.vue'
import { utilityFunction } from './utilities.js'

export { ComponentA, utilityFunction }
// somewhere-else.js

import { ComponentA, utilityFunction } from './modules/foo'

This achieves two things:

  1. The import statement reads well and is self explanatory i.e. import x from module foo
  2. It's a lot easier to refactor and modify your module afterwards, because it's explicit what is exposed outside of your module. You can even change file names and still keep the named exports outwards in order to not break other stuff while refactoring.

Lazy load modules async

When your code base grows, bundling everything together in one giant chunk results in a big up-front download for code that the client might never use.

Instead, consider using code splitting by loading your modules only when needed. You can do this inside each module with lazy loading routes, or you can load in entire module definitions with the registerModules function and webpack's dynamic imports

import { registerModules } from 'vue-modular'

const { default: foo } = await import('./modules/foo')
registerModules({ foo })

Contribute

For the repo and install dependencies

# Serve example app
yarn serve

# Production build
yarn build

# Run unit tests
yarn test:unit

# Lint files
yarn lint

PRs and issues are welcome!

License

MIT

Use it, fork it, change it, do what you want.