purpose

The purpose of on-demand import is to introduce only the components used to reduce the size of the project.

Realize the principle of

For example: babel-plugin-component

practice

The toast component is special. Other components are usually used with labels after registration. Whereas toast needs to be used in the project through this.xxx.toast.show() or similar methods.

Developing the TOAST component

File structure:

// main.vue <template> <! --> <transition name=" toasts-from-top "> <div class="my-toast" v-show="show"> <div Class =" my-toasts-content "> This is a toast ~ </div> </div> </transition> </template> <script> export default {name: 'MyToast', data () {return {time: 2000, // toast display timer: null, // show: false // toast display}}, watch: { show (val) { if (val) { this.timer = setTimeout(() => { this.show = false this.timer = null }, this.time) } } } } </script> <style scoped> .my-toast { position: fixed; top: 25%; width: 100%; text-align: center; } .my-toast-content { display: inline-block; max-width: 80%; box-sizing: border-box; padding: 10px; background-color: hsla(0, 0%, 7%, .7); color: #fff; border-radius: 3px; } .toast-from-top-enter-active, .toast-from-top-leave-active { transition: all .5s; } .toast-from-top-enter, .toast-from-top-leave-to { transform: translateY(-100%); opacity: 0; } </style>Copy the code
// index.js
import main from './src/main'

let instance

const plugin = {
  // vue. use will call this method
  install (Vue) {
    const Toast = Vue.extend(main)
    if(! instance) {// Create toast component instance
      instance = new Toast({
        el: document.createElement('div')})// Add toast dom to the body
      document.body.appendChild(instance.$el)
    }

    const toast = {
      show (options = {}) {
        if (instance.timer) {
          return
        }
        let defaults = {}
        for (let key in instance.$options.props) {
          defaults[key] = instance.$options.props[key].default
        }

        Object.assign(instance, defaults, options)
        / / show the toast
        instance.show = true}}if(! Vue.$myui) { Vue.$myui = { toast } }else {
      Vue.$myui.toast = toast
    }
      
    $myUI = this.$myui.toast.show(...); $myui.toast.show(...); Shows the
    Vue.mixin({
      created () {
        this.$myui = Vue.$myui
      }
    })
  }
}

export default plugin

Copy the code

SRC index.js will also need to be modified, because this file is imported globally.

// src/index.js
'use strict'
import MyButton from './components/my-button'
import MyToast from './components/my-toast'

const components = [
  MyButton
]

const plugins = [
  MyToast
]

const install = function (Vue) {
  components.forEach(component= > {
    Vue.component(component.name, component)
  })

  plugins.forEach(plugin= > {
    Use calls the install method in plugin
    Vue.use(plugin)
  })
}

export default {
  install
}
Copy the code

At this point, you can write examples in Example and add the necessary routes.

</my-button @click="clickFunc"> </my-button> </div>  </template> <script> export default { name: 'example-button', methods: { clickFunc () { this.$myui.toast.show({ text: 'This is a Toast'})}}} </script> <style scoped> </style>Copy the code

Effect:

Configuration Webpack

The idea is to configure multiple entries using the index.js entry in each component folder, and then package each component into the Lib folder.

Create a new build-components.js file

'use strict'
require('./check-versions')()

process.env.NODE_ENV = 'publish'

const ora = require('ora')
const rm = require('rimraf')
const fs = require('fs')
const path = require('path')
const chalk = require('chalk')
const webpack = require('webpack')
let webpackConfig = require('./webpack.publish.conf')
let config = require('.. /config')

function getFolders (dir) {
  return fs.readdirSync(dir).filter(function (file) {
    return fs.statSync(path.join(dir, file)).isDirectory()
  })
}

const spinner = ora('building for production... ')
spinner.start()

rm(path.join(config.publish.distRoot, 'lib'), err => {
  if (err) throw err
})

// Get the list of component folder names
const folders = getFolders(path.join(__dirname, '.. /src/components'))
const originEntry = Object.assign(webpackConfig.entry)
const originOutput = Object.assign(webpackConfig.output)

// Iterate over the number group and add it to the entry
webpackConfig.entry = {}
for (let i = 0; i < folders.length; i++) {
  let componentName = folders[i]

  if(! webpackConfig.entry[componentName]) { webpackConfig.entry[componentName] =`./src/components/${componentName}/index.js`
  }
}

webpackConfig.output.path = path.join(config.publish.distRoot, 'lib')
webpackConfig.output.filename = '[name].js'

webpack(webpackConfig, (err, stats) => {
  spinner.stop()
  if (err) throw err
  process.stdout.write(stats.toString({
    colors: true.modules: false.children: false.chunks: false.chunkModules: false
  }) + '\n\n')

  if (stats.hasErrors()) {
    console.log(chalk.red('Build failed with errors.\n'))
    process.exit(1)}console.log(chalk.greenBright(`$Build components successfully! \n`))
  webpackConfig.entry = originEntry
  webpackConfig.output = originOutput
})

Copy the code

test

To test the effects of the component, create a new project: TestMyComponent. Initialize the project as before.

Then I installed the developed and packaged component library. I put the component library on my Github and used the Github link to install it.

npm install https://github.com/NicholasCui/MyComponent.git -S
Copy the code

Introducing component libraries in main.js:

// ...
import MyComponent from 'my-component'

Vue.use(MyComponent)
// ...
Copy the code

Using component libraries in app.vue:

<template> <div id="app"> <my-button @click="clickFunc"> button </my-button> <my-button @click="toastFunc"> toast </my-button> </div> </template> <script> export default { name: 'App', methods: { clickFunc () { alert('click') }, toastFunc () { this.$myui.toast.show({ text: </script> <style> </style>Copy the code

The effect is as follows:

TestMyComponent
babel-plugin-component

npm i babel-plugin-component -D
Copy the code

Add configuration to. Babelrc, see babel-plugin-Component for more configuration

{/ /... "plugins": [ // ... [ "component", { "libraryName": "my-component", "libDir": "lib", "style": false }, "my-component" ] ] }Copy the code

Modify the main js

// All comments are introduced
// import MyComponents from 'my-component'
// Vue.use(MyComponents)

/ / only introducing the toast, without introducing button, my - button labels complains
import {
  // MyButton,
  MyToast
} from 'my-component'

// Vue.use(MyButton)
Vue.use(MyToast)
Copy the code

Effect:

we-button
toast
toast
we-button

conclusion

What impressed me most was that there was still a lot to learn.

The source code:MyComponent source code TestMyComponent source code