In the development of VUE project, we will abstract the frequently used logic or modules into components. For those components that are useful to multiple projects, we can consider encapsulating them into component libraries and publishing them to NPM. Each time to only need NPM install xx once, there is no need to copy back and forth. Let’s package a Vue component library starting at 0.
Common ways to use a VUE component library
- 1, through the
script
Tags introduced
<body> <div id="app"> <hello></hello> </div> </body> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <! <script SRC =".. /dist/my-lib.js"></script> <script> new Vue({ el: '#app' }) </script>Copy the code
- 2, through the
import
The introduction of
import Vue from "vue"
import App from "./App.vue"
import MyLib from "my-lib"
Vue.use(MyLib)
new Vue({
name: "root",
el: '#root',
render: h => h(App)
})
Copy the code
After this is introduced, use it directly in the project component that needs to use the component library, such as:
<template>
<div id="app">
<hello></hello>
</div>
</template>
Copy the code
Components need to be registered before they are used. Registered components can be registered locally and globally. From the usage of component libraries above, we can see that the components of component libraries are registered globally.
In the first method of importing through the script tag, we complete the global registration inside the component library so that the imported component library can be used directly.
In the second import approach, we complete the global registration of components through vue.use (MyLib).
The project structure for the component library is as follows, with the install method defined in SRC /index.js.
// SRC /index.js import Hello from "./components/ hello.vue "function install(vue){// external vue.use (MyLib) will execute this method to complete the global registration of the component. Vue.component(hello.name, Hello)} if(window && window.vue) {// Complete the component registration within the component by introducing the 'script' tag. Vue.use(install) } export default installCopy the code
Webpack packaging
Webpack: WebPack: WebPack: WebPack: WebPack: WebPack: WebPack
Now we only have one component libraryHello component
Through WebPack, we will package it into a component library that can be used in both ways.Webpack packages vUE component libraries in much the same way as a normal VUE project. justoutput
Different, as shown below, increasedlibraryTarget
And so on.
//webpack.config.js const path = require('path') const { VueLoaderPlugin } = require('vue-loader') module.exports = { mode: 'none', entry: './src/index.js', output: { path: path.join(__dirname,"/dist"), filename: LibraryExport: 'default'}, module: {rules: [ { test: /\.vue$/, use: ['vue-loader'] }, { test: /\.css$/, use: ['style-loader','css-loader','postcss-loader'] }, { test: /\.s[ac]ss$/i, use: ['style-loader','css-loader','postcss-loader','sass-loader'] }, { test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/, } ] }, plugins: [ new VueLoaderPlugin() ] }Copy the code
libraryTarget
Var Assign this window Global JSONp CommonJS CommonJS2 AMD UMD var Assign this window Global JSONp CommonJS CommonJS2 AMD UMD For details, see official documents
We are using UMD here, which will run in CommonJS, AMD environment, or export modules to variables under Global. The basic structure of the exported library files under the UMD module specification is as follows, which we often see in some plug-ins or library files, such as jquery.
// The official example. 'MyLibrary' is the name of the library defined in the library, and corresponds to myLib in our own demo. (function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(); else if(typeof define === 'function' && define.amd) define([], factory); else if(typeof exports === 'object') exports['MyLibrary'] = factory(); else root['MyLibrary'] = factory(); })(typeof self ! == 'undefined' ? self : this, function() { return _entry_return_; // This module returns the value returned by the entry chunk});Copy the code
With webpack.config.js written, we can configure the scripts in package.json:
"Scripts ": {"build": "webpack" // the default will execute webpack.config.js in the root directory},Copy the code
npm run build
A beggar version of the Vue component library is packaged.
externals
In our VUE component library, vue is passed in as a parameter. We didn’t import any other libraries either. When the functionality of this library is more complex, it is often inevitable to import other libraries, such as if you want to use Vue’s static method vue.xxx, or a tool library such as lodash.
It is not possible to package these external libraries into our own component library, because when the user introduces these external libraries and then introduces our component library, the external library will be imported and packaged twice, which is completely redundant. Therefore, when we develop a library, the external modules that the library depends on can be provided by the users who import the library.
This requires the use of externals, which prevents certain imported packages from being packaged into the bundle and instead retrieves these external dependency modules from the outside at run time. Add externals to webpack.config.js above:
const path = require('path') const { VueLoaderPlugin } = require('vue-loader') module.exports = { ... Externals: {vue: {root: "vue ", // the global variable can access vue commonjs: "Vue ", // can access CommonJs2 as a CommonJS module: "vue", // similar to above, but exports module.exports.default AMD: "Vue" is similar to commonJS, but uses AMD module system}}}Copy the code
The externals configuration can be string, array, object, function, and regex. Externals configuration
Only libraryTarget: ‘umd’ can be configured with {root, AMD, commonjs,… }, other libraryTarget values cannot be configured this way.
To test the externals configuration, add the following two lines to SRC /index.js:
import Vue from "vue"
console.log(Vue)
Copy the code
How do I debug component libraries locally
- 1, first to debug through
script
In the case of tag import, create a new HTML document and import the packaged component library.
<! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, Word-wrap: break-word! Important; "> <title>Document</title> </head> <body> <div id="app"> <hello></hello> </div> </body> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script src=".. /dist/my-lib.js"></script> <script> new Vue({ el: '#app' }) </script> </html>Copy the code
- 2,
import
In the case of the introduction. Create a vue project called LibTest for testing, or, more conveniently, add a test component to the existing Vue project and add it to routes.
Modify the main field in the package.json of the myLib project, which defines the entry file for the NPM package.
"main": "./dist/my-lib.js",
Copy the code
Execute in the myLib component library project root directorynpm link
cd myLib
npm link
Copy the code
Execute in the test project root directorynpm link my-lib
CD LibTest NPM link my-lib // "name": "my-lib" : "name": "my-lib"Copy the code
You can then use the same component libraries as a normal NPM installation
In the js entry of the LibTest test project, introduce my-lib and execute vue.use () to register the component
import MyLib from 'my-lib'
Vue.use(MyLib)
Copy the code
Using components in LibTest’s app.vue:
<template>
<div>
<hello></hello>
</div>
</template>
Copy the code
According to the need to load
Now that we’ve got the basic component library out of the way, let’s transform it into an on-demand component library.
Component libraries can be loaded on demand only when: Component libraries are exported in ES6 modular mode. In other words, the exported file should look like this:
import { xxx } from 'xxx'
import yyy from yyy
export default zzz;
export { a, b, c };
Copy the code
Use tree-shaking to remove unused code.
The principles of Tree-shaking, Wall cracking suggest careful reading of these two articles:
Tree-Shaking Performance Optimization Practice – Principles, your Tree-Shaking is not good
1. The modules introduced in ES6 are statically analyzed, so it is possible to determine exactly what code has been loaded at compile time. 2. Analyze the program flow, determine which variables are not used or referenced, and then delete the code.Copy the code
In the base packaging, we know that WebPack has multiple export modes (libraryTarget), but WebPack does not support an export mode for ES modules. The popular ‘UMd’ export mode, where the export file is also an instant-execute function, does not fit the ES6 modular approach at all. There is no way to load on demand with the above configuration.
There are many libraries that package each component or function into a separate file or directory for reference on demand. It is then referenced by the file path:
import 'echarts/lib/chart/pie'
import 'echarts/lib/component/title'
Copy the code
Writing this way doesn’t introduce more than one component at a time, nor is it elegant. The Elemental-UI has developed the Babel plugin, babel-plugin-Component, so we can introduce it on demand as follows:
import { Button, Select } from 'element-ui'
Vue.use(Button)
Vue.use(Select)
Copy the code
See how element-UI is built
Babel-plugin-component will:
import { Button } from 'element-ui'
Copy the code
Converted to:
var button = require('element-ui/lib/button')
require('element-ui/lib/theme-chalk/button.css')
Copy the code
In the path above, element-UI and Theme-Chalk are configurable, button is the component name, and lib is the folder where the babel-plugin-Component will find the component by default.
If we also want to implement more elegant on-demand references with the help of the Babel-plugin-Component plug-in, we pack each component separately and place it in the lib file of the component library.
Implement on-demand references
To create awebpack.component.js
, as a configuration file packaged separately as a component. Write two more components, Hello and Test, which will be used for testing.Since components are packaged separately, each component exports a function that is executed at vue.use (xx) to complete the global registration of the component.
Hello/Hello.vue
andHello/index.js
/ SRC /index.js import Hello from "./components/Hello" import Test from "./components/Test" function install(Vue){ Vue.use(Hello) Vue.use(Test) } if(window && window.Vue) { Vue.use(install) } export default installCopy the code
The implementation is simple. The core is multi-entry packaging. There is a multi-entry package
Let’s copy and paste the previous content from webpack.config.js into webpack.component.js.
- Step 1: Modify
entry
andoutput
Fields:
entry: {
'hello': './src/components/Hello/index.js',
'test': './src/components/Test/index.js',
'my-lib': './src/index.js'
},
output: {
path: path.join(__dirname,"/lib"),
filename: '[name].js',
libraryTarget: 'umd',
library: '[name]',
libraryExport: 'default'
},
Copy the code
Add package.json scripts: “component”: “webpack –config webpack.component.js”
npm run component
There is a lib folder in the myLib component directory.
- Step two, from the top
element-ui
thebabel-plugin-component
Using the plugin, we can see that the js and CSS files of the component library are separated. So we also separate the component CSS into a separate file, which we use heremini-css-extract-plugin
The plug-in.
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
Copy the code
Configure the NPM run Component again
Next, modify package.json"main": "./lib/my-lib.js",
Back to the test item. Create.babelrc in the project root directory (install the plug-in as prompted) and restart the project. Babel-plugin-component configuration reference
{
"presets": [["es2015", { "modules": false }]],
"plugins": [
[
"component",
{
"libraryName": "my-lib",
"styleLibrary": {
"name": "lib-style", // same with styleLibraryName
"base": false // if theme package has a base.css
}
}
]
]
}
Copy the code
Let’s put it to the rough test. Reference only the Hello component, using both Hello and test.
// LibTest/src/index.js import { Hello } from "my-lib" Vue.use(Hello) // LibTest/src/App.vue <template> <div class="cp"> <hello></hello> <test></test> </div> </template>Copy the code
Add a reference to the test component:
import { Hello,Test } from "my-lib"
Vue.use(Hello)
Vue.use(Test)
Copy the code
Let’s remove the reference to the Test component. Package the test project. Search the contents of the two components in the packaged file.
We have packaged the vUE component library to load on demand. In fact, developing component libraries can also be packaged using rollup.js, which supports ES Modules very well. Tree-shaking was also proposed by Rollup.js first, so it is much easier to load component libraries on demand. That’s it for today. The next article will show you how to package a library using Rollup. See you next time.