Reference:

  • NPM publishes vUE components
  • A step-by-step guide to encapsulating Vue components and publishing them using NPM
  • NPM distribution package

Initialize the project

vue init webpack-simple yyl-npm-practice

// Then follow the prompts
cd yyl-npm-practice
npm install
npm run dev
Copy the code

Why not use vue init webpack npm-practice to initialize the project, because developing components does not require much configuration, too much configuration can cause configuration trouble, use Webpack-simple is enough.

File directory Configuration

It’s up to you how to create folders for your own components. Finally, just configure the corresponding ones in the webPack entry and exit.

├ ─ ─ the SRC / / / source directory │ ├ ─ ─ packages / / / component │ │ ├ ─ ─ myButton / / / component 1 │ │ ├ ─ ─ myButton, vue / / component code │ │ ├ ─ ─ index. The js / / mount plug-in ├ ─ ─ myText / / / component 2 │ │ ├ ─ ─ myText. Vue / / component code │ │ ├ ─ ─ index. The js / / mount plug-in │ ├ ─ ─ App. Vue / / page entry │ ├ ─ ─ the main, js / / program entrance │ ├ ─ ─ Index.js // (all) Plugin Entry ├─ index.html // Entry HTML fileCopy the code

On demand import, that is, single component import

packages/myButton/myButton.vue:

<template> <div> MyButton component </div> </template> <script> export default {name: } </script> </script>Copy the code

packages/myButton/index.js:

import MyButton from './myButton.vue'

export default {
    //Vue is the constructor of Vue. Options is an optional configuration item
    install(Vue,options){ Vue.component(MyButton.name, MyButton); }}Copy the code

So far, a component plug-in has been packaged successfully. Finally, we can test and publish it to NPM.

Test using: main.js to introduce:

import Vue from 'vue'
import App from './App.vue'

Use automatically executes the install method, which mounts the component to the Vue constructor
import MyButton from './packages/myButton/index.js'
Vue.use(MyButton)

new Vue({
  el: '#app'.render: h= > h(App)
})
Copy the code

App.vue:

<template>
  <div id="app">
    <my-button />
  </div>
</template>

<script>
export default {
  name: 'app'
}
</script>
Copy the code

Display:

In the multi-component case, all components are imported globally

We create index.js. SRC /index.js in the SRC directory of app. vue :(entry for all components)– elementui uses the same form:

import MyButton from './packages/myButton/myButton.vue'
import MyText from './packages/myText/myText.vue'


const components = [
    MyButton,
    MyText
    / /... Keep adding if there are more
]

  // This step checks whether window.vue exists, because referencing Vue.min.js directly binds Vue to the window.
if (typeof window! = ='undefined' && window.Vue) {
    components.map(component= >{ Vue.component(component.name, component); })}export default {
    //Vue is the constructor of Vue. Options is an optional configuration item
    install(Vue,options={}){
        components.map(component= >{ Vue.component(component.name, component); }}})// the effect is equivalent to
// const install = function(Vue,options={}) {
// components.map(component => {
// Vue.component(component.name, component);
/ /})
// }
// export default {
// install
// }
Copy the code

Dynamic import can be used instead of multiple imports. After optimization:

// Use dynamic import instead of import
Vue $/ to find all files ending in. Vue name, return a webpackContext object
const urlList = require.context('./packages'.true./\.vue$/);
console.log('= = = = = = =',urlList.keys())
//["./myButton/myButton.vue", "./myTable/myTable.vue", "./myText/myText.vue"]
/ / use urlList ('. / myButton myButton. Vue '). The default; You can achieve the same effect as import and get the component instance.

// This step checks whether window.vue exists, because referencing Vue.min.js directly binds Vue to the window.
if (typeof window! = ='undefined' && window.Vue) {
    urlList.keys().forEach(item= >{
        let compObj = urlList(item).default;// Can also be directly according to the./myButton/ mybutton.vue to cut the corresponding myButton, etc., and each of the above components have name attribute, so you can directly use the name attribute
        Vue.component(compObj.name,compObj)
    })
}

export default {
    //Vue is the constructor of Vue. Options is an optional configuration item
    install(Vue,options={}){
         urlList.keys().forEach(item= >{
            let compObj = urlList(item).default;
            Vue.component(compObj.name,compObj)
        })
    }
}
Copy the code

Test the SRC/main. Js:

import Vue from 'vue'
import App from './App.vue'


import AllComponents from './index'
Vue.use(AllComponents)

new Vue({
  el: '#app'.render: h= > h(App)
})
Copy the code

src/App.vue:

<template>
  <div id="app">
    <my-button />
    <my-text />
  </div>
</template>

<script>
export default {
  name: 'app'
}
</script>
Copy the code

Display:

Write components using VUE’s JSX notation

npm i npm i babel-plugin-syntax-jsx babel-plugin-transform-vue-jsx babel-helper-vue-jsx-merge-props -D
Copy the code
/ /. Babelrc {" presets ": [[" env" {} "modules" : false]], "plugins" : [" transform - vue - JSX "] / / add the plug-in}Copy the code

Use:

//test.js
export default {
    name: 'Test'.props: {
        show: {type: String}},render(){
        return (
            <div>{this.show? 'JSX' : 'XXX'}</div>)}}Copy the code

Pre-release operation, account registration and configuration

  • Configuration modification:

Webpack.config. js configures the development environment and production environment entry:

/ /... Omit code here
// Execution environment
const NODE_ENV = process.env.NODE_ENV

module.exports = {
  // Configure different entries for different execution environments
  entry: NODE_ENV == 'development' ? './src/main.js' : './src/index.js'.output: {
    // Modify the package exit to package an index.js file in the outermost directory, which we import will point to by default
    path: path.resolve(__dirname, './dist'),
    publicPath: '/dist/'.filename: 'outy-test.js'.library: 'outy-test'.// Specify the module name when you use require
    libraryTarget: 'umd'.// libraryTarget generates code for different UMDs, which can be commonJS, AMD, or just imported through script tags
    umdNamedDefine: true // AMD modules in the UMD build process are named. Otherwise use anonymous define
  },
  / /... Omit code here
}
Copy the code

Package. json: private field (private is true and cannot be published to NPM, set to false); And add the main field, which is the require method that finds the entry file through this configuration, which inputs the module load specification. In addition, check whether the name is a duplicate name. If the name is a duplicate name, change it to another name. How to find whether the name is used? Log in to NPM and search. If the name is found, it indicates that it exists.

"name": "outy-test".// Publish open source so you need to change this field to false
"private": false.// This refers to the path it retrieves when importing outy-test
"main": "dist/outy-test.js".Copy the code

Index.html: because we changed the input file filename default name build.js to outy-test.js when we changed webpack.config.js, we need to match it to outy-test.js.

<! DOCTYPEhtml>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>outy-test</title>
  </head>
  <body>
    <div id="app"></div>
    <! -- Original -->
    <! -- <script src="/dist/build.js"></script> -->
    <script src="/dist/outy-test.js"></script>
  </body>
</html>
Copy the code
  • Run the pack command to generate the dist folder,npm run build

If you don’t need to generate the map file, you can comment out the diagram contents in the webpack.config.js file.

Published to the NPM

  • First register an NPM account
  • npm loginLog in,
    • Pit (reference) : If NPM source is Taobao source, 500 error will be reported, you must change to NPM source to log in:

npm config set registry https://registry.npmjs.org/

  • npm publishReleased,
    • The following 403 error will not occur if the mailbox is not authenticated when registering.

A successful release is illustrated as follows:

use

  • The installation

npm i outy-test -S

  • Mian. Js introduction
import OutyTest from 'outy-test'
Vue.use(OutyTest)
Copy the code
  • use
<template>
  <div class="home">
    <my-button></my-button>
    <my-text></my-text>
  </div>
</template>
Copy the code
  • According to

Update existing packages

  • Change the version number in package.json
  • Run againnpm publish
  • To view

Deletes the package of the specified version

Delete the entire package

  • NPM unpublish package name --force

Re-encapsulate elder-UI’s EL-table

Use Webpack-simple as the template.

  • The installation

npm i element-ui -S

  • Introduce element-UI on demand

NPM install babel-plugin-component -d then change.babelrc to:

{
  "presets": [["es2015", { "modules": false }]],
  "plugins": [["component",
      {
        "libraryName": "element-ui"."styleLibraryName": "theme-chalk"}}]]Copy the code
  • Install and configure the Loader
npm i style-loader url-loader -D

// Other required loaders
less-loader
sass-loader
Copy the code
  • Introduced the main. Js
import { Table,TableColumn } from 'element-ui';
Vue.use(Table)
Vue.use(TableColumn)
Copy the code

webpack.config.js:

{
    test: /\.(woff2? |eot|ttf|otf)(\? . *)? $/,
    loader: 'url-loader'.options: {
        limit: 10000.name: '[name].[ext]'}}Copy the code
  • Encapsulating table components

packages/myTable/myTable.vue:

<template> <el-table :data="tableData" style="width: 100%" :row-class-name="tableRowClassName"> <el-table-column prop="date" label=" date" width="180"> </el-table-column> <el-table-column prop="address" label=" address" > </el-table-column> <el-table-column prop="address" label=" address" > </el-table-column> </el-table> </template> <style> .el-table .warning-row { background: oldlace; } .el-table .success-row { background: #f0f9eb; } </style> <script> export default { name:'MyTable', methods: { tableRowClassName({row, rowIndex}) { if (rowIndex === 1) { return 'warning-row'; } else if (rowIndex === 3) { return 'success-row'; } return ''; }}, data() {return {tableData: [{date: '2016-05-02', name: '王 xiaohu ', address: '1518 一 路 ',}, {date: '2016-05-04', name: 'Wang Xiaohu ', address:' 1518 Jinshajiang Road, Putuo District, Shanghai ', {date: '2016-05-01', name: 'Wang Xiaohu ', address: }, {date: '2016-05-03', name: 'Wang Xiaohu ', address:' Shanghai Putuo Jinshajiang Road 1518 Lane '}]}}}Copy the code
  • The introduction and use of Vue.com Poment registration section is referenced above.
  • Test use:
<div id="app">
    <my-table />
</div>
Copy the code

Elemetui encapsulates component learning

tag.vue:

<script>
  export default {
    name: 'ElTag',
    props: {
      text: String,
      closable: Boolean,
      type: String,
      hit: Boolean,
      disableTransitions: Boolean,
      color: String,
      size: String,
      effect: {
        type: String,
        default: 'light',
        validator(val) {
          return ['dark', 'light', 'plain'].indexOf(val) !== -1;
        }
      }
    },
    methods: {
      handleClose(event) {
        event.stopPropagation();
        this.$emit('close', event);
      },
      handleClick(event) {
        this.$emit('click', event);
      }
    },
    computed: {
      tagSize() {
        return this.size || (this.$ELEMENT || {}).size;
      }
    },
    render(h) {
      const { type, tagSize, hit, effect } = this;
      const classes = [
        'el-tag',
        type ? `el-tag--${type}` : '',
        tagSize ? `el-tag--${tagSize}` : '',
        effect ? `el-tag--${effect}` : '',
        hit && 'is-hit'
      ];
      const tagEl = (
        <span
          class={ classes }
          style={{ backgroundColor: this.color }}
          on-click={ this.handleClick }>
          { this.$slots.default }
          {
            this.closable && <i class="el-tag__close el-icon-close" on-click={ this.handleClose }></i>
          }
        </span>
      );

      return this.disableTransitions ? tagEl : <transition name="el-zoom-in-center">{ tagEl }</transition>;
    }
  };
</script>
Copy the code

card.vue:

<template>
  <div class="el-card" :class="shadow ? 'is-' + shadow + '-shadow' : 'is-always-shadow'">
    <div class="el-card__header" v-if="$slots.header || header">
      <slot name="header">{{ header }}</slot>
    </div>
    <div class="el-card__body" :style="bodyStyle">
      <slot></slot>
    </div>
  </div>
</template>

<script>
  export default {
    name: 'ElCard',
    props: {
      header: {},
      bodyStyle: {},
      shadow: {
        type: String
      }
    }
  };
</script>
Copy the code

Summary:

<my-button @click=" XXX "@change=" BBB" size="small"> <span> Default slot </span> </my-button $emit('clcik', parameter), this.$emit('change', parameter), etc. + has default slots, <span v-if="$sloth. default><slot></slot></span>Copy the code