preface

When the mainstream component libraries in the market cannot meet our business needs, it is necessary for us to develop a set of component libraries belonging to our team. Here is a simple component to describe the development and release of Vue3.0 + TS based components from NPM repository (see Element-Plus)

The environment

The versions of the environment used in this article are listed here

  • Vue 3.0
  • Vue/cli 4.5.9
  • NodeJs 14.15.1
  • NPM 6.14.8
> vue --version@ vue/cli 4.5.9
> npm -v
6.14.8

> node -v
v14.15.1
Copy the code

steps

1. Create projects

Create a VuE3 project using vue-CLI, assuming the project name is nandit-vue-vant

> vue create nandit-vue-vant
Copy the code

Select Manually Select Features and press Enter to go to the next step

Check Choose Vue Version, Babel, TypeScript, and CSS pre-processors and press Enter to go to the next step

  • Choose a version of vue.js that you want to start the project with select 3.x (Preview)

  • Use class-style component syntax? Type n

  • Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? Enter y

  • Pick a CSS pre-processor (PostCSS, Autoprefixer and CSS Modules are supported by default) Select Sass/SCSS (with Dart-sass)

  • Where do you prefer placing config for Babel, ESLint, etc.? Select In Dedicated Config Files

  • Save this as a preset for future projects? Enter y and press Enter to save the template

Finally, press Enter and wait for the project to complete

The directory structure is shown in the figure

2. Plan directories

├ ─ the build// Edit the package script directory to store the script files│ ├─ ├.config.js ├─ docs// Document directory, used to generate vuePress document pages│ ├─.Vuepress │ ├─ Guide │ ├─.MD ├─ examples// Change the SRC directory to examples for examples│ ├─ App.vue │ ├─ Main// Add packages directory for writing and storing components such as buttons│ ├─ Button │ ├─ Index// Add typings directory for.d.ts files, move shims-vue.d.ts to this directory│ ├─ Shims-├.d.Bass Exercises ─.nPMIgnore// Add the.npmignore configuration file├ ─ vue. Config. Js// Add vue. Config. js configuration file
Copy the code

Change the SRC directory to examples, delete assets and Components, and remove component references from app. vue.

The adjusted directory structure is shown in the figure

3. Project configuration

3.1 the vue. Config. Js

The vue.config.js configuration file is added to adapt to the replanned project directory

const path = require('path')

module.exports = {
  // Modify the pages entry
  pages: {
    index: {
      entry: "examples/main.ts"./ / the entry
      template: "public/index.html"./ / template
      filename: "index.html" // Output file}},// Extend the WebPack configuration
  chainWebpack: (config) = > {
    // Add a ~ to the Packages directory for easy use in the sample code
    config.resolve.alias
      .set('~', path.resolve('packages'))}}Copy the code

3.2 .npmignore

The.npmignore configuration file is added. Components are published in NPM. Only compiled distribution directories (e.g. Lib), package.json, readme. md are required to be published, so we need to set the directory and files to be ignored

Idea.vscode build/ docs/ examples/ packages/ public/ node_modules/ typings/ tsconfig.json tslint.json vue.config.js .gitignore .browserslistrc *.mapCopy the code

3.3 tsconfig. Json

Modify the path in tsconfig.json

    "paths": {
      "@ / *": [
        "src/*"]}Copy the code

Instead of

    "paths": {
      "~ / *": [
        "packages/*"]}Copy the code

Modify the path of include

  "include": [
    "src/**/*.ts"."src/**/*.tsx"."src/**/*.vue"."tests/**/*.ts"."tests/**/*.tsx"
  ]
Copy the code

Instead of

  "include": [
    "examples/**/*.ts"."examples/**/*.tsx"."examples/**/*.vue"."packages/**/*.ts"."packages/**/*.tsx"."packages/**/*.vue"."typings/**/*.ts"."tests/**/*.ts"."tests/**/*.tsx"
  ]
Copy the code

3.4 package. Json

Modify the fields published to NPM in package.json

  • name: package name, which is unique. Search for the name on the NPM website, or change the name if it exists.
  • version: Version number. The version number must be changed each time you release to NPM. The version number cannot be the same as the historical version number.
  • description: describe.
  • main: entry file, this field should point to our final compiled package file.
  • typings: types file required by the TS component.
  • keyword: keyword, separated by Spaces from the final search term.
  • author: Author Information
  • private: Private or not, you need to change it to false to publish to NPM
  • license: Open source protocol

Reference Settings:

{
  "name": "nandit-vue-vant"."version": "0.1.0 from"."private": false."description": "Vue3 + Vant based front-end component library"."main": "lib/index.min.js"."module": "lib/index.esm.js"."typings": "lib/index.d.ts"."keyword": "vue3 vant"."license": "MIT"."author": {
    "name": "yourname"."email": "[email protected]"}}Copy the code

Added compile and publish commands to scripts of package.json

"scripts": {
    "build": "yarn build:clean && yarn build:lib && yarn build:esm-bundle && rimraf lib/demo.html"."build:clean": "rimraf lib"."build:lib": "vue-cli-service build --target lib --name index --dest lib packages/index.ts"."build:esm-bundle": "rollup --config ./build/rollup.config.js"
}
Copy the code

Build :lib is packaged in VUe-CLI umD mode, and build: ESM-bundle is packaged in ROLLup ES mode.

  • --target: Build target, default to application mode. Instead oflibEnable library mode.
  • --name: Output file name
  • --dest: Output directory, defaultdist. tolib
  • [entry]: Entry file path. The default value issrc/App.vue. Here we specify compilepackages/Component library directory.

Here is a complete package.json reference example

{
  "name": "nandit-vue-vant"."version": "0.1.0 from"."private": false."description": "Vue3 + Vant based front-end component library"."main": "lib/index.min.js"."module": "lib/index.esm.js"."typings": "lib/index.d.ts"."keyword": "vue3 vant"."license": "MIT"."author": {
    "name": "jiuage"."email": "[email protected]"
  },
  "scripts": {
    "serve": "vue-cli-service serve"."docs:dev": "vuepress dev docs"."docs:build": "vuepress build docs"."build": "yarn build:clean && yarn build:lib && yarn build:esm-bundle && rimraf lib/demo.html"."build:clean": "rimraf lib"."build:lib": "vue-cli-service build --target lib --name index --dest lib packages/index.ts"."build:esm-bundle": "rollup --config ./build/rollup.config.js"
  },
  "dependencies": {
    "core-js": "^ 3.6.5." "."vue": "^ 3.0.0"
  },
  "devDependencies": {
    "@rollup/plugin-node-resolve": "^ 13.0.5"."@vue/cli-plugin-babel": "~ 4.5.0." "."@vue/cli-plugin-typescript": "~ 4.5.0." "."@vue/cli-service": "~ 4.5.0." "."@vue/compiler-sfc": "^ 3.0.0"."rollup": "^ 2.58.0"."rollup-plugin-terser": "^ 7.0.2"."rollup-plugin-typescript2": "^ 0.30.0"."rollup-plugin-vue": "^ 6.0.0"."sass": "^ 1.26.5"."sass-loader": "^ 8.0.2." "."typescript": "~ 4.1.5." "}}Copy the code

3.5 a rollup. Config. Js

Added rollup.config.js, rollup package script

// import vue from 'rollup-plugin-vue'
import { nodeResolve } from '@rollup/plugin-node-resolve'
import path from 'path'
// import commonjs from '@rollup/plugin-commonjs'
import { terser } from 'rollup-plugin-terser'
import typescript from 'rollup-plugin-typescript2'
import pkg from '.. /package.json'
const deps = Object.keys(pkg.dependencies)
// eslint-disable-next-line @typescript-eslint/no-var-requires
const vue = require('rollup-plugin-vue')

export default[{input: path.resolve(__dirname, '.. /packages/index.ts'),
    output: [{format: 'es'.file: pkg.module,
      }
    ],
    plugins: [
      terser(),
      nodeResolve(),
      // commonjs(),
      vue({
        target: 'browser'.css: false.exposeFilename: false,
      }),
      typescript({
        tsconfigOverride: {
          compilerOptions: {
            declaration: true,},'include': [
            'packages/**/*'.'typings/shims-vue.d.ts',].'exclude': [
            'node_modules'.'packages/**/__tests__/*',]},abortOnError: false,})],external(id) {
      return /^vue/.test(id)
        || deps.some(k= > new RegExp(A '^' + k).test(id))
    },
  },
]
Copy the code

4. Develop components

The following uses the Button component as the development example. Create the index.ts file and the Button folder under the Packages directory, and create the index.ts and SRC /button.vue under the Button, as shown in the figure

button.vue

<template>
  <button class="nd-btn">
    <span v-if="$slots.default"><slot></slot></span>
  </button>
</template>

<script lang="ts">
import { defineComponent } from 'vue'
export default defineComponent({
  name: "nd-button"
})
</script>

<style scoped>

</style>

Copy the code

Button /index.ts, an entry file for a single component. In other projects you can use import {NdButton} from ‘nandit-vue-vant’ to reference a single component

import { App } from 'vue'
import Button from './src/button.vue'

// Define the install method with App as an argument
Button.install = (app: App): void= > {
    app.component(Button.name, Button)
}

export default Button

Copy the code

Index. ts acts as an entry file to the component library. You can import the entire component library in main.ts of other projects, as shown below

import { App } from 'vue'
import NdButton from './button'

// List of all components
const components = [ NdButton ]

// Define the install method with App as an argument
const install = (app: App): void= > {
    // Iterate over registered components
    components.map((component) = > app.component(component.name, component))
}

export {
    NdButton
}

export default {
    install
}

Copy the code

Now that we have a simple Button component, we need to extend the other components by following the structure of the button and adding them to the components list in the index.ts file.

5. Write examples

After the components are developed, we test them locally and release them to the NPM repository if there are no problems. Reference our component library in the sample entry main.ts

import { createApp } from 'vue'
import App from './App.vue'
import NanditVue from '~/index'  // Here ~ is the packages path configured in tsconfig.json and vue.config.js

const app = createApp(App)
app.use(NanditVue)
app.mount('#app')
Copy the code

App.vue deletes the HelloWorld component initialized by the project

<template> <div> Component example </div> <div>{{count}}</div> < nd-button@click ="handleClick"> button </nd-button> </template> <script lang="ts"> import { defineComponent } from 'vue'; export default defineComponent({ name: 'App', components: { }, data() { return { count: 0 } }, methods: { handleClick() { this.count ++ } } }); </script> <style lang="scss"> #app { font-family: Avenir, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style>Copy the code

Start the project and test it out

> yarn serve
Copy the code

6. Publish components

Once the component is developed and tested, it can be published to the NPM repository for use by other projects, starting with the compile library command to generate the lib directory

> yarn build
Copy the code

6.1 Release to NPM official website

6.1.1 Registering an NPM Account

Go to the official website to register an NPM account. If you have already registered, skip this step

6.1.2 Logging In to the NPM Account

Log in to the NPM account in the terminal command window of the project

> npm login
Username:
Password:
Email:(this IS public)
Copy the code

Enter your account, password, and email address registered with NPM

Also 6.1.3 release

Make sure registry is registry.npmjs.org

> npm config get registry
Copy the code

If not, modify Registry first

> npm config set registry=https://registry.npmjs.org
Copy the code

And then execute the command

> npm publish
Copy the code

To delete published components (it is not recommended to delete published components), run the following command (plus –force forcible deletion) :

> npm unpublish --force
Copy the code

Delete packages for the specified version, such as nandit-vue-vant version 0.1.0

>NPM unpublish [email protected]
Copy the code

If a component package with the same name has been deleted within 24 hours, the release will fail, prompting

npm ERR! code E403
npm ERR! 403 403 Forbidden - PUT https://registry.npmjs.org/nandit-vue-vant - nandit-vue-vant cannot be republished until 24 hours have passed.
npm ERR! 403 In most cases, you or one of your dependencies are requesting
npm ERR! 403 a package version that is forbidden by your security policy.

npm ERR! A complete log of this run can be found in:
npm ERR!     D:\tools\nodejs\node_cache\_logs\2021-10-18T09_58_58_933Z-debug.log
Copy the code

Only publish under a different name or after 24 hours, so do not delete published components (in case a project is already referenced)

6.2 Publishing to NPM Private server

6.2.1 Nexus builds NPM private server

Set up NPM private server using Nexus (here using Nexus2) and assign publishing accounts. Please refer to another article “Set up NPM private server using Nexus2” for details.

6.2.2 Modifying the NPM Registry

Registry corresponds to the path of the NPM group of nexus

> npm config set registry=http://nexus.xx.com/nexus/content/groups/npm-group
Copy the code
6.2.3 Configuring advertising Accounts

Modify.npmrc file (C:\Users\ username \. NPMRC), add email, always-auth, _auth at the end of the file

registry=http://nexus.xx.com/nexus/content/groups/npm-group
[email protected]
always-auth=true
_auth=dGVzdDp0ZXN0MTIz
Copy the code

Description:

_auth=dGVzdDp0ZXN0MTIz is the base64 encoding of the release account: password (such as test:test123), which can be done online in the rookie tool

Note:

NPM private server built by Nexus2 needs to be published in configuration. NPMRC mode. If you use NPM login mode, error 401 will occur, which is very troublesome.

6.2.4 release

After configuring NPM Registry and publishing account information, execute NPM publish –registry nexus.xx.com/nexus/conte… Registry is a Hosted type repository on the NPM private server

> npm publish --registry http://nexus.xx.com/nexus/content/repositories/npm-hosted/
Copy the code

You can also configure publishConfig in package.json

"publishConfig": {
	"registry": "http://nexus.xx.com/nexus/content/repositories/npm-hosted/"
}
Copy the code

Note:

  1. registryNeed tohostedType,Can’t bepublic
  2. registryThe address ends with a slash (/)Don’t omit
  3. The NPM private server library built by Nexus2 does not support the @scope publishing mode. For example, @vue/vue-form can only be used as the component publishing name. Otherwise, an error 400 will be reported
  4. The NPM private server library built by Nexus2 does not support unpublish

7. Test

Create another test project, VUe-Demo

7.1 check the registry

> npm config get registry
Copy the code

The value is generally set to registry.npmjs.org. If the NPM private server is installed by nexus, set it to the public address of the private server, for example, nexus.xx.com/nexus/conte…

7.2 test the install

To test whether the NPM private server can properly install dependencies on the agent library, select a vue project, delete the node_modules directory, and install again

>Yarn // Or use yarn install; Or NPM i.
Copy the code

If you can install vue, element-UI and core-js, you can use the NPM private server library

Then test the components we publish

>Yarn add nandit-vue-vant // Or use NPM i-s nandit-vue-vant
Copy the code

See if package.json and node_modules have nandit-vue-vant data and packages, then reference components in main.ts and app. vue (similar to the code in the example), start the project, and the test passes, This will make our component library available to other projects.

The last

Gitee project source code: Nandit-vue-vant

There are deficiencies in writing, please god not hesitate to give advice, thank you! Welcome to explore VUE!