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 🙏

© 2026 – Pkg Stats / Ryan Hefner

vue-feature-registry

v0.0.1

Published

A Vue plugin to help implement folder-by-feature module structure in large Vue projects

Readme

Vue Feature Registry

帮助你在大型 Vue 项目中实现按功能组织的模块结构 👷‍👷‍

English | 中文文档

构建大型 Vue 项目

当 Vue 项目不断增长时,传统的按类型组织文件夹结构可能会变得难以管理,因为跨文件的依赖关系难以重构和理清。

相反,你应该考虑将代码组织成"功能"模块,每个模块封装自己的组件、Pinia store、路由等。这可以看作是一种结构设计模式,鼓励相关代码的封装。

这个仓库的主要目的就是规定一个可扩展的项目结构。为了简化设置,这个简单的 Vue 插件通过从每个模块中提取 Pinia stores 和路由定义并全局注册它们,帮助你轻松实现这一点。

插件安装

安装 NPM 包

yarn add vue-feature-registry

在你的 main.js(或等效文件)中,添加

import { createApp } from 'vue'
import { createPinia } from 'pinia'
import { createRouter, createWebHistory } from 'vue-router'
import VueFeatureRegistry from 'vue-feature-registry'
import foo from './modules/foo'
import bar from './modules/bar'

const app = createApp(App)
const pinia = createPinia()
const router = createRouter({
  history: createWebHistory(),
  routes: []
})

// 使用插件并传入模块、pinia 和 router 引用
app.use(VueFeatureRegistry, {
  modules: {
    foo,
    bar
  },
  pinia,
  router
})

app.use(router)
app.use(pinia)
app.mount('#app')

该插件目前实现三个功能:

  1. Pinia stores - 在每个模块中定义的 Pinia store 会被注册到全局 Pinia 实例
  2. Vue router - 每个模块中的路由定义会被合并并注册到全局路由实例
  3. Vue 实例辅助属性 - $modules 被注入到所有组件中,方便访问每个模块可以导出的自定义值

推荐设置

请查看 example 文件夹作为参考设置

选择一个适合你本地模块的文件夹结构。每个模块可以是简单的(如下面的 foo)或复杂的(如下面的 bar),取决于你的需求。

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

技术上对你的目录树结构或文件命名没有限制,只要每个模块导出一个如下所示的对象即可

// modules/foo/index.js

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

export default {
  router, // 模块的 vue router(如果有)
  store, // 模块的 pinia store(如果有)
  custom: {
    // 可选的自定义信息,用于共享
    foo: 'bar'
  }
}

路由和 store 对象正是你从 Pinia stores 和 Vue Router 定义中所期望和了解的

// 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

import { defineStore } from 'pinia'

export default defineStore('foo', {
  state: () => ({
    foo: []
  }),
  getters: {
    getFoo: (state) => state.foo
  },
  actions: {
    setFoo(foo) {
      this.foo = foo
    }
  }
})

何时使用

不要过早过度设计

对于中小型项目,按类型组织文件夹的方法通常更易于导航,因为将所有路由和 stores 放在一个地方很有帮助。

如果你是一两个人构建一个小型 Vue 应用,这通常没问题。

LIFT 你的代码库

当项目增长到数百个组件,有大型开发团队在同一个代码库上工作时,情况开始发生变化。

你要实现的目标可以缩写为 LIFT:构建应用结构,以便能够快速定位代码,识别代码一目了然,保持最扁平的结构,并尝试保持 DRY(不要重复自己)

但请记住,并非所有代码都可以或应该是自包含的:基础 UI 组件、API 客户端、通用工具等可能不应该是模块。

但是一个带有自己的路由(例如 /login)、store(例如 currentUser)、测试(例如 login.spec.js)和视图组件(例如 Login.vue)的身份验证模块非常适合封装。

技巧和窍门

从模块中暴露内容

作为经验法则,你能让模块之间以及模块与代码库其余部分之间保持越隔离,维护就越容易。

但是,有时你确实想要导出一个组件、服务或工具函数供其他代码使用。在这些情况下,我建议你明确地只从模块的 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'

这实现了两个目标:

  1. 导入语句读起来很好,并且是自解释的,即 从模块 foo 导入 x
  2. 之后重构和修改模块要容易得多,因为明确知道模块外部暴露了什么。你甚至可以更改文件名,同时保持命名导出向外,以便在重构时不会破坏其他内容。

在组件中使用 Pinia stores

在组件中使用 Pinia stores 时,你可以使用 Composition API:

// Component.vue
<script setup>
import useFooStore from '../modules/foo/store'

const fooStore = useFooStore()

// 访问 state
console.log(fooStore.foo)

// 调用 actions
fooStore.setFoo(['bar', 'baz'])

// 访问 getters
console.log(fooStore.getFoo)
</script>

或使用 Options API:

// Component.vue
<script>
import useFooStore from '../modules/foo/store'

export default {
  setup() {
    const fooStore = useFooStore()
    return { fooStore }
  }
}
</script>

<template>
  <div>
    <p>{{ fooStore.foo }}</p>
    <button @click="fooStore.setFoo(['bar'])">Set Foo</button>
  </div>
</template>

异步懒加载模块

当你的代码库增长时,将所有内容打包在一起会导致一个巨大的初始下载,而客户端可能永远不会使用这些代码。

相反,考虑使用代码分割,只在需要时加载模块。你可以在每个模块内部使用懒加载路由来实现这一点,或者你可以使用 registerModules 函数和 Vite 的动态导入加载整个模块定义

import { registerModules } from 'vue-feature-registry'

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

贡献

克隆仓库并安装依赖

# 运行示例应用
yarn serve

# 生产构建
yarn build

# 运行单元测试
yarn test

# 代码检查
yarn lint

欢迎提交 PR 和 issue!

许可证

MIT

使用它,fork 它,修改它,随你便 🖖