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-component-holder

v0.0.17

Published

Inject asynchronized hooks on vue components

Downloads

7

Readme

vue-component-holder

Version

Navigation

Introduction

This plugin introduces a component placeholder machanism. A placeholder component replaces the original child component in the template, and the plugin creates/mounts/destroys the child component by itself. This child component then becomes an "mvm" (managed vm). If vue updates the placeholder, the plugin applies the same changes to the mvm. Since the mvm is totally managed by the plugin, it is possible to inject some (asynchronized) custom hooks before and after the creation. For example, the plugin injects an "asyncData" hook in each mvm to prefetch asynchronous data (Nuxt is only able to do it in page components).

Component Tree and Mvm Tree

Component Tree and Mvm Tree

It also supports user-defined hooks. The graph below shows the calling sequence with two user-defined hooks: "beforeInit" and "inited"

The Calling Sequence with user-defined "beforeInit" and "inited" hooks

To declare an mvm, just wrap a child component with "vue-holder" as follows:

<!-- MyParentComponent.vue -->
<template>
<div>
  <vue-holder name="MyFavoriteHolderName">
    <MyChildComponent />
  </vue-holder>
</template>

To prevent vue from managing mvms, we need to edit the template AST generated by vue-component-compiler. This is done by the "holdify" function we inject into "vue-loader" (details in Installation). In the previous example, the child's template is moved from the default slot to the template attribute as follows:

<vue-holder name="MyFavoriteHolderName" template="<MyChildComponent />">
</vue-holder>

Then, the plugin could make a render function for this mvm based on the results of "holdify". The mvm is created after running this render function.

Below is an example of declaring "fetch" and "asyncData" hooks:

/** MyChildComponent.vue */
<template>
<div>
  <div>Name: {{ name }}</div>
  <div>Recommendations: {{ $store.state.recommendations }} </div>
</div>
</template>
<script>
export default {
  async fetch({ $store, $route }) {
    const { data } = await axios.get(`/api/my-recommendations/${$route.params.id}`)
    $store.commit('updateRecommandations', data)
  },

  async asyncData({ $route }) {
    const { data } = await axios.get(`/api/my-data/${$route.params.id}`)
    return { name: data.name }
  }
}
</script>

Please refer vue-component-holder-demo for more examples.

Installation

npm

npm install vue-component-holder --save

yarn

yarn add vue-component-holder

Add the following in vue.config.js:

/** vue.config.js */
module.exports = {
  // ...

  chainWebpack: config => {
    config.module
      .rule('vue')
      .use('vue-loader')
        .loader('vue-loader')
        .tap(options => {
          options.compilerModules = options.compilerModules || [];
          options.compilerModules.push({
            postTransformNode: require('vue-component-holder/holdify')()
          });
          return options;
        });

    // Cache may cause the injected 'holdify' option skipped
    config.module
      .rule('vue')
      .uses.delete('cache-loader');
  }
}

If you are using webpack.config.js, add the following at module.exports -> modules -> rules -> (vue) -> use -> options:

/** webpack.config.js */
    compilerModules: [{
      postTransformNode: require('vue-component-holder/holdify')()
    }]

Install the plugin in the early stage of your project:

import Vue from 'vue'
import VueComponentHolder from 'vue-component-holder'

Vue.use(VueComponentHolder)

Holdify

HTML Template

If the child component is in "v-for" loop(s), it could have multiple mvm instances. In this case, the "holdify" function will add more attributes on the placeholder component. For example, the "uid" attribute is added to identify different mvms, and the "vars" attribute is added to pass local variables to the mvm's render function. Please view our "holdify" examples or try it yourself on Holdify Demo.

JSX

Automatic "holdify" in JSX has not been implemented yet. To use "vue-holder" with JSX, you have to do "holdify" manually by providing the neccessary attributes.

Configuration

A "holder.config.js" file is used to configure the plugin. Place it at the same level with the "node_modules" folder where the plugin was installed. Normally, it should be placed in the project root folder.

/** holder.config.js */
module.exports = {
  // plugin configs as below
}

globalHolderMixin

This option is default to "true". If it is "false", you need to setup "HolderMixin" manually as follows:

/** holder.config.js */
module.exports = {
  globalHolderMixin: false
}
/** MyParentComponent.vue */
import { HolderMixin } from 'vue-component-holder'
export default {
  mixins: [ HolderMixin /* more mixins*/ ]
}
/** MyChildComponent.vue */
import { HolderMixin } from 'vue-component-holder'
export default {
  mixins: [ HolderMixin /* more mixins*/ ]
}

customHooks

You could inject asynchronized custom hooks in the parent component. They are partitioned into two groups: "preInitMvms" and "postInitMvms", indicating if they are excuted before or after the mvms are initialized.

/** holder.config.js */
module.exports = {
  customHooks: {
    preInitMvms: [ 'beforeInit' ],
    postInitMvms: [ 'inited' ]
  }
}
/** MyParentComponent.vue */
export default {
  async beforeInit() {
  },

  async inited() {
  }
}

APIs and Hooks

Please refer vue-component-holder-demo for examples.

mvmsUpdated

A hook, defined in the parent component, is called everytime there are some mvms created/deleted/updated.

asyncData

A hook, defined in the child component, is called before an mvm is created, which helps to fetch async data.

fetch

A hook, defined in the child component, is called before an mvm is created, which helps to update stores.

$intf

This function retrieves the interface object of a specific mvm with the holder name and uid.

$publish (or @Public)

With the "$publish" function, an mvm reveals some functions via its interface object. If working with vue-class-component, it could also use the "@Public" decorator.

registerHolders

A hook, defined in the parent component, is used for registering holders manually. Normally, a holder is automatically registered in the "created" hook of the 'vue-holder' component. However, if a "vue-holder" component is defined in "v-if" or "v-for", the parent component may not be able to perceive it at run time. This may prevent an mvm root from calling its user-defined hooks. In this case, we need to register it manually as follows.

<!-- MyMvmRootComponent.vue -->
<template>
<div>
  <div v-if="isDataLoaded">
    <vue-holder name="MyFavoriteHolderName">
      <MyChildComponent />
    </vue-holder>
  </div>
</template>

<script>
export default {
  // ...
  registerHolders() {
    return { name: 'MyFavoriteHolderName' };
  },
  // ...
}
</script>