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

mvframe

v1.1.3

Published

**English** | [简体中文](README.cn.md)

Readme

MVFrame

English | 简体中文

A Vue 3 + Vite oriented admin-shell toolkit: Frame layout, common business components, global utilities & directives, Pinia wiring with tabs/router, composable modules, and SCSS utilities & tokens. Priorities favor SaaS-style admin apps over a fully pluggable, zero-opinion utility library.


Stack & dependencies

| Kind | Notes | |------|------| | Runtime | vue ^3.3, vue-router ^4.6, pinia ^3 | | Demo / dev | element-plus (demo forms, etc.), vite ^6, sass-embedded | | Build | Library output is ESM; vue / pinia / vue-router are externals and must be supplied by the host app |

package.json exports include:

  • "."dist/index.js (main plugin; default export is the install function)
  • "./composition"dist/composition.js (e.g. import { useMap } from 'mvframe/composition')
  • "./store", "./directive", "./util" → matching chunks under dist
  • "./notify"dist/notify.js (browser helper for the local mvframe-notify service)
  • "./style/mixin"src/style/chip/mixin.scss (shared breakpoint and helper mixins for host SCSS)
  • "./style"dist/css/style.css (full toolkit CSS from src/style/index.scss entry)
  • "./style/cpt"dist/css/cpt.css (component-extracted CSS; usually import 'mvframe/style' is enough)

Repository layout

src/ — library source

| Path | Role | |------|------| | src/index.js | Install entry: registers config → global components (cpt) → utildirectivestorerouter | | src/config/ | Merges defaults with app options → globalThis.$config (chip/base.js: name, copyright, version, etc.) | | src/cpt/index.js | Auto-registers every component/*/index.vue via import.meta.glob; component name equals the folder name (PascalCase, e.g. BtnGroup) | | src/component/ | Implementations; root class Mvc + name (see .cursor/rules/component-hierarchy.mdc) | | src/util/index.js | Global helpers on app.config.globalProperties & globalThis ($getLang, $fa, $copy, $deepClone, …) | | src/directive/index.js | Directives: v-copy (optional .dblclick), v-focus | | src/store/ | createPinia + built-in init / tab / rmenu; optional storeChips; provide("store", store) | | src/router/ | createWebHistory router; optional guard; built-in guardThis (meta.admin, afterEach + tabs, document.title) | | src/composition/ | Import on demand; exports lang, dom, data, media, … (Vite alias @cps → this folder) | | src/style/ | index.scss aggregates chip/*.scss (tokens, spacing, typography, layout, overrides) |

Globally registered components (folder name = registration name):

BtnGroup, Form, Frame, Icon, Input, Page, Select, SelectV2, Table, Tabs, Textarea, VTable

VTable is registered with defineAsyncComponent by default so the VisActor chunk is loaded only when <VTable> is rendered.

chip/ subfolders hold internal pieces (e.g. Frame/chip/Menu.vue); they are not registered as root components.

demo/ — local preview app

With NODE_ENV=development, Vite root is ./demo (see vite.config.js) to exercise Frame, routing, and components.

| File | Role | |------|------| | demo/index.html | HTML shell | | demo/main.js | Boot: ElementPlus + ../src/index.js + ../src/style/index.scss + routes | | demo/App.vue | Frame layout, menu: { iconClass: 'imicon', routes }, slots logo / logomini | | demo/routes.js | Sample routes: /Overview/Home, /aA/Home; nested children for the sidebar | | demo/views/Overview/Home.vue | Page + Tabs switching FormPanel / IconPanel | | demo/views/Overview/Home/FormPanel.vue | Form demo | | demo/views/Overview/Home/IconPanel.vue, iconfontAntNames.js | Icon demo & Ant icon name list | | demo/auto-imports.d.ts | Types from unplugin-auto-import (Vue / vue-router) |

Local dev:

yarn install
yarn dev

Dev server port 8088 (see vite.config.js).

Path aliases

| Alias | Points to | |------|-----------| | @ | src/ | | @cps | src/composition/ | | @scss | assets/scss (if present) |

Demo routes use paths like import("/views/Overview/Home.vue") resolved from the demo root.


Using in a host application

1. Install peer-style deps

Align versions of vue, vue-router, pinia. For Form / Table tied to Element Plus, add element-plus and app.use(ElementPlus).

2. Register MVFrame

import { createApp } from "vue";
import mvframe from "mvframe";
// Styles: use package path when depending on source / monorepo; published `dist`-only—see “Styles”
import "mvframe/src/style/index.scss";

const app = createApp(App);

app.use(mvframe, {
  components: {
    async: ["VTable"],
  },
  vueRouter: {
    routes: yourRoutes,
    // optional: custom beforeEach, etc.
    // guard: (router) => { /* ... */ },
    // useAdmin: true,
    // adminPermission: () => true,
    // noaccess: (next) => next(false),
  },
  pinia: {
    useTab: true, // multi-tab + localStorage restore for `tabs` / `ctab`
    // storeChips: import.meta.glob("./pinia/chip/*.js", { eager: true }),
  },
  config: {
    // merged with src/config/chip/base.js → globalThis.$config
    iconfont: {
      url: "//at.alicdn.com/t/c/your_font.js",
      prefix: "ant",
    },
  },
});

components.async controls async global component registration. VTable is async by default to keep @visactor/vtable out of the initial synchronous component chain; keeping it explicit in app config documents that choice.

Frame injects a <script> for icon fonts from globalThis.$config.iconfont.url on mount (implementation removes url afterward to avoid duplicate injection).

3. Globals at a glance

  • globalThis.$config — merged app config
  • globalThis.$router — router instance assigned by this library after install
  • inject("store") — store factory (store.tab(), store.rmenu(), custom chips)
  • Global components — use Frame, Page, Table, … without local registration
  • Directivesv-copy, v-focus
  • Compositionimport { ... } from "mvframe/composition" or your @cps alias

Full helper list: .cursor/rules/util.mdc and src/util/index.js.

4. Styles

  • Utility classes & tokens: .cursor/rules/style-system.mdc (--color-*, spacing, typography, layout).
  • vite.config.js additionalData injects src/style/chip/mixin.scss; mirror this in apps that compile the same SCSS tree.
  • Breakpoints are centralized in mixin.scss: xs / sm / md / lg / xl / xxl. Host SCSS can @use "mvframe/style/mixin" as *; and use @include media-up(md), media-down(md), media-only(md), or media-between(sm, lg).
  • mvframe/style now ships responsive utility classes in the shape {breakpoint}-{up|down|only}-{utility}, for example md-down-hide, lg-up-flexMode, and xs-only-block.
  • Grid containers also support breakpoint column-count classes such as class="grid col2 md2 lg3 sm1": default 2 columns, sm 1 column, md 2 columns, lg 3 columns.
  • Published packages can use import 'mvframe/style' (dist/css/style.css). For SCSS overrides, still link src/style/index.scss from Git/monorepo when needed.

Host SCSS example:

@use "mvframe/style/mixin" as *;

.BillingPanel {
  padding: 1.5rem;

  @include media-down(sm) {
    padding: 1rem;
  }
}

Building the library

yarn build

Production uses library mode with entry src/index.js and obfuscation-related plugins (see vite.config.js). NODE_ENV=development points Vite at the demo app; to verify a real build locally, run production vite build (or your script that sets production env).


DingTalk Notify Service

MVFrame ships a local Node service for DingTalk robot messages only:

yarn notify
yarn exec mvframe-notify

yarn d
yarn exec mvframe-d

The service reads .env.mvframe-notify from the host root:

MVFRAME_NOTIFY_PORT=3300
MVFRAME_NOTIFY_HOST=127.0.0.1
MVFRAME_NOTIFY_TOKEN=
DINGTALK_WEBHOOK="https://oapi.dingtalk.com/robot/send?access_token=xxxxxxxx"
DINGTALK_SECRET="SECxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

Browser code should only configure the local endpoint/token:

app.use(mvframe, {
  config: {
    notify: {
      enabled: true,
      endpoint: import.meta.env.VITE_MVFRAME_NOTIFY_ENDPOINT || "http://127.0.0.1:3300",
      token: import.meta.env.VITE_MVFRAME_NOTIFY_TOKEN || "",
    },
  },
});

Send messages with globalThis.$notify.send("message") or import { notify } from "mvframe/notify". Keep DingTalk webhook/secret out of browser-bundled files.


Design notes

  • Layout, guards, tabs, and menu behavior are opinionated; heavy customization may mean forking src/router, src/store/tab.js, or wrapping from the app.
  • CSS naming & units: root Mvc*, children camelCase; prefer rem for sizes other than 1px/2px (16px root)—see style-system.mdc.
  • Use globalThis or store / pinia exports outside setup (e.g. guards), as in src/router/chip/guard.js.

Form Labels

Input, Textarea, Select, and SelectV2 support a shared label API:

<Input v-model="form.name" label="Name" />
<Input v-model="form.name" label="Material Name" material-label />

<Textarea v-model="form.remark" label="Remark" />
<Textarea v-model="form.remark" label="Material Remark" material-label />

<Select v-model="form.type" :options="options" label="Type" />
<Select v-model="form.type" :options="options" label="Material Type" material-label />

Rules:

  • label only: renders a normal top label
  • label + material-label: renders a Material-style floating label
  • no label: keeps the default control appearance

The floating label shell is implemented centrally in src/style/chip/element.scss. When you want a Material-style form field, prefer the built-in label + material-label API instead of recreating the same pattern locally.


CLI: project skeleton

From an empty folder or existing Vite root, generates src/views, src/component, src/api, src/assets/img, src/assets/style, src/router, src/pinia/chip, src/config, plus starter main.js / App.vue with app.use(mvframe, …) (routes, Pinia storeChips, config, and components.async: ["VTable"]). It also writes/updates host-project AGENTS.md with MVFrame Codex rules, including a requirement that AI send a completion message with yarn exec mvframe-notify --once --message "..." after each finished development task, and copies /.cursor/rules/*.mdc from the package (same as this repo’s Cursor rules). Adds index.html and vite.config.js only if missing (use --force to overwrite). Merges scripts / dependencies / devDependencies into package.json (existing values win for shared keys), initializes .env.mvframe-notify.example / .env.local.example and config.notify, then runs yarn install; use --no-package-json to skip package changes and install. Then run yarn dev or explicitly run yarn exec mvframe-d to start Vite with the notify service.

cd /path/to/your-app
node /path/to/mvframe/scripts/scaffold-app.js
node /path/to/mvframe/scripts/scaffold-app.js --force
node /path/to/mvframe/scripts/scaffold-app.js -f

# Skip package.json (only scaffold sources + Vite config):
node /path/to/mvframe/scripts/scaffold-app.js --no-package-json
node /path/to/mvframe/scripts/scaffold-app.js -n

yarn exec mvframe-init-app
# or: npx mvframe-init-app

See MVFRAME-SCAFFOLD.md in the target project. Set MVFRAME_SCAFFOLD_TARGET to point at the project root.


Codex Rules (AGENTS.md)

Codex does not automatically read Cursor .cursor/rules/*.mdc. For host projects, install the MVFrame AGENTS.md section so Codex prefers MVFrame global components, global helpers, and style utilities before writing local replacements:

cd /path/to/your-app
yarn exec mvframe-init-rules
# or: npx mvframe-init-rules

# Codex rules only
yarn exec mvframe-install-codex-rules
# or: npx mvframe-install-codex-rules

# Full checkout / monorepo path to mvframe
node /path/to/mvframe/scripts/init-rules.js
node /path/to/mvframe/scripts/init-rules.js /path/to/your-app

# Codex rules only
node /path/to/mvframe/scripts/install-codex-agents.js
node /path/to/mvframe/scripts/install-codex-agents.js /path/to/your-app

The scaffold command already runs this step. The generated block is bounded by MVFRAME-CODEX-RULES markers, so rerunning the command updates only that block and preserves other AGENTS.md content.

Cursor Rules (.cursor/rules)

The unified mvframe-init-rules command also adds the package’s *.mdc files into the target project’s /.cursor/rules/ (component-hierarchy, script-setup, style-system, views, router, global-components, data, util). If the host project already has a same-named rule file, the host file is kept and only missing rules are added.

Install Cursor rules only:

cd /path/to/your-app
yarn exec mvframe-install-cursor-rules
# or: npx mvframe-install-cursor-rules

# Full checkout / monorepo path to mvframe
node /path/to/mvframe/scripts/install-cursor-rules.js
node /path/to/mvframe/scripts/install-cursor-rules.js /path/to/your-app

Cursor Skill (app scaffold)

This repo ships .cursor/skills/mvframe-app-init. Copy it into your app’s .cursor/skills so Cursor can pick up MVFrame integration conventions.

From your app root, run either:

# Full checkout / monorepo path to mvframe
node /path/to/mvframe/scripts/install-cursor-skill.js
node /path/to/mvframe/scripts/install-cursor-skill.js /path/to/your-app

# After installing the npm package (the tarball must include `scripts/` and `.cursor/skills`—see `package.json` `files`)
cd /path/to/your-app
yarn exec mvframe-install-cursor-skill
# or: npx mvframe-install-cursor-skill

Default target is ./.cursor/skills/mvframe-app-init under the current working directory. Override with MVFRAME_CURSOR_SKILL_OUT=/path/to/your-app.


Changelog

  • Added mvframe-notify, a DingTalk-only local Node notification service.
  • Added mvframe/notify and global $notify for browser calls through config.notify.
  • Added framework command yarn d / mvframe-d to run yarn dev with the notify service.
  • mvframe-init-app now initializes config.notify, .env.mvframe-notify / .env.mvframe-notify.example with the MVFrame test DingTalk robot, and .env.local.example without forcing host d scripts.
  • VTable now uses async global registration by default; mvframe-init-app writes components.async: ["VTable"] in main.js.

License

ISC (see package.json).