In Vue CLI3 build component library and NPM release actual combat operation introduced a single component component library how to develop, this article will step by step to teach you how to develop multiple components integrated component library, how to realize the introduction of component library as needed. Give it a thumbs up if you think it’s useful.
This article will skip the installation of Vue CLI3, build component library project, clean component library project steps, do not understand the place can see Vue CLI3 build component library and NPM release combat operation
Create two Git repositories for this article’s sample code
- Component library
- Reference component library Demo
2. Some basic configuration of Webpack in component library project
In Vue CLI3, the webpack configuration of the project is to be configured by creating vue.config.js in the root directory.
1. Distinguish between the configuration of development and build environments
Because the configuration of the development and build environments in the multi-entry component library is different, it is important to distinguish between them. According to the process.env.NODE_ENV variable, process.env.NODE_ENV is development in the production environment.
Const devConfig = {//... } const buildConfig = { //... } module.exports = process.env.NODE_ENV === 'development' ? devConfig : buildConfig;Copy the code
2. Change the name of the SRC folder
In the Vue component library project, the original SRC folder is the content of the demo, so the file name is changed to examples, more vivid.
3. Reconfigure the project entry file
The configuration content in the vue.config.js file is as follows:
const devConfig={
pages: {
index: {
entry: 'examples/main.js',
template: 'public/index.html',
filename: 'index.html',
},
},
}
Copy the code
4. Configure file alias
The file alias will be used in writing the demo. The configuration content in the vue.config.js file is as follows:
const path = require('path');
function resolve(dir) {
return path.resolve(__dirname, dir)
}
const devConfig = {
configureWebpack: {
resolve: {
extensions: ['.js', '.vue', '.json'],
alias: {
'@': resolve('packages'),
'assets': resolve('examples/assets'),
'views': resolve('examples/views'),
}
},
},
}
Copy the code
5. Configure devServer
The configuration content in the vue.config.js file is as follows:
Const devConfig = {devServer:{port: 8091,// fixed port hot: true,// open: 'Google Chrome'// fixed browser}}Copy the code
6. Create the Packages folder under the root directory
The code for the component is developed in the Packages folder
7. Add the new Packages folder to Babel transcoding
The configuration content in the vue.config.js file is as follows:
const devConfig = {
chainWebpack: config => {
config.module
.rule('js')
.include
.add('/packages')
.end()
},
}
Copy the code
This is the configuration for the development environment. Let’s write the configuration for the production environment
8. Add the new Packages folder to Babel transcoding as well in production
const buildConfig = {
chainWebpack: config => {
config.module
.rule('js')
.include
.add('/packages')
.end()
},
}
Copy the code
9. Configure the directory for the production environment build files
We packed and compiled the component library and put it in the lib folder. The configuration content in the vue.config.js file is as follows:
const buildConfig = {
outputDir: 'lib',
}
Copy the code
10. Close source Map
Closing the Source Map has two benefits
- Reduce packaging compilation time;
- Avoid seeing source code in Sources with the F12 developer tools in production.
The configuration content in the vue.config.js file is as follows:
const buildConfig = {
productionSourceMap: false,
}
Copy the code
Three, multi-entry file page packaging configuration
In the project built by Vue CLI3 with the help of babel-plugin-import webpack plug-in and configure babel.config.js, to realize the component library on demand import premise is the component library is multi-entry file page package.
1. Configure Entry
In Vue CLI3, the project multiple entry is configured on the Entry property of the configureWebpack option. In this case, the configuration is as follows
const buildConfig = {
configureWebpack: {
entry: {
index: 'D:\\project\\02npm\\02Vue_Cli3_MAPLib\\packages\\index.js',
testA: 'D:\\project\\02npm\\02Vue_Cli3_MAPLib\\packages\\testA\\index.js',
testB: 'D:\\project\\02npm\\02Vue_Cli3_MAPLib\\packages\\testB\\index.js'
},
},
}
Copy the code
But each entry is written dead, so we use NodeJS to automate the configuration.
First we introduce the path module in NodeJS to handle file paths.
const path = require('path'); const join = path.join; // Splice pathsCopy the code
Write a method that converts the destination path to an absolute path based on the current file path
function resolve(dir) {
return path.resolve(__dirname, dir)
}
Copy the code
__dirname is the complete absolute path of the current file directory, for example
The fs module in NodeJS is also introduced to handle file information
const fs = require('fs');
Copy the code
We create a function getEntries(PATH), where PATH is the name of the folder where the component code is located, returns an object entry with key being the name of each component folder and the absolute path to the entry file index.js in each component folder.
First use fs.readdirsync (resolve(path)) to get the names of all the files in the component code’s folder, stored in the files variable.
Then use the array reduce() method to loop files, first convert each filename (item) into a path by join(path, item) and store it in the itemPath variable.
Determine if each file is a folder with fs.statsync (itemPath).isdirectory ().
If it is a folder, concatenate itemPath and the entry file index.js into an address, then convert it to an absolute path, and assign item as the key to the returned object
Entries [item] = resolve(join(itemPath, 'index.js')).Copy the code
If it is not a folder, convert itemPath directly to an absolute path, remove the item suffix as key, and assign the value to the returned object
const [name] = item.split('.')
entries[name] = resolve(`${itemPath}`)
Copy the code
Here is the complete code
function getEntries(path) {
let files = fs.readdirSync(resolve(path));
const entries = files.reduce((ret, item) => {
const itemPath = join(path, item)
const isDir = fs.statSync(itemPath).isDirectory();
if (isDir) {
ret[item] = resolve(join(itemPath, 'index.js'))
} else {
const [name] = item.split('.')
ret[name] = resolve(`${itemPath}`)
}
return ret
}, {})
return entries
}
Copy the code
For example, in this case, executing getEntries(‘ Packages ‘) will result in an object
{
index: 'D:\\project\\02npm\\02Vue_Cli3_MAPLib\\packages\\index.js',
testA: 'D:\\project\\02npm\\02Vue_Cli3_MAPLib\\packages\\testA\\index.js',
testB: 'D:\\project\\02npm\\02Vue_Cli3_MAPLib\\packages\\testB\\index.js'
},
Copy the code
Configure Entry using the object expansion operator
const buildConfig = { configureWebpack: { entry: { ... getEntries('packages'), }, }, }Copy the code
2. Configure output
- Filename: generates the corresponding filename after each component is packaged
[name].index.js
Why this name is configured will be explained later. - LibraryTarget: Set to
commonjs2
The key is that the return value of the entry file will be assigned to the Module.exports object to make its component library available in a WebPack built environment.
const buildConfig = {
configureWebpack: {
output: {
filename: '[name]/index.js',
libraryTarget: 'commonjs2',
}
},
}
Copy the code
3. Style packing configuration
Configure the style packing path and filename on css.extract. Filename
Const buildConfig = {CSS: {sourceMap: true, extract: {filename: 'style/[name].css'// Create style folder in lib, generate corresponding CSS file. }}},Copy the code
4. Delete some useless functions of Vue CLI3 originally packaged and compiled
- Remove splitChunks because each component is packaged separately and there is no need to pull out the common JS for each component.
- Delete copy. Do not copy the contents of the public folder into the lib folder.
- Remove HTML, package only components, do not generate HTML pages.
- Remove preload and prefetch, which are useless because no HTML pages are generated.
- Delete HMR, delete hot update.
- Delete automatically added entry App.
const buildConfig = {
chainWebpack: config => {
config.optimization.delete('splitChunks')
config.plugins.delete('copy')
config.plugins.delete('html')
config.plugins.delete('preload')
config.plugins.delete('prefetch')
config.plugins.delete('hmr')
config.entryPoints.delete('app')
},
}
Copy the code
5. Configure the loader for fonts
const buildConfig = {
chainWebpack: config => {
config.module
.rule('fonts')
.use('url-loader')
.tap(option => {
option.fallback.options.name = 'static/fonts/[name].[hash:8].[ext]'
return option
})
},
}
Copy the code
4. Component library development
In this case, testA and testB are simply written for testing
1, Packages directory structure
Mainly about the component entry file how to write, other development as usual.
2. Single component entry
In the case of component testA, expose an object called test and provide the install method. This component can be called via vue.use ().
import test from './src/index.vue';
test.install = function(Vue) {
Vue.component(test.name, test);
};
export default test;
Copy the code
3. General entry to the component library
import testA from './testA'
import testB from './testB'
export default {
install(Vue) {
Vue.use(testA);
Vue.use(testB)
},
}
Copy the code
Compile and package
Execute NPM run build, package and compile, and you’ll get a lib folder in your project with the contents shown in the figure below.
Vi. Preparation before NPM release
1. Configure the main import file
In package.json, write:
"main": "lib/index/index.js",
Copy the code
2. Other configurations
You can refer to Vue CLI3 to build a component library and release actual combat operation with NPM
7. Introduce configuration on demand
1. Introduce components
After the release (if not released please see Vue CLI3 build component library and NPM release actual operation), in reference to the component library demo, execute NPM install [email protected] –save install component library.
Install the babel-plugin-import plug-in after NPM install babel-plugin-import –save-dev and use it to import components on demand.
In the. Babelrc. js file in the root directory, do as follows
module.exports = { "presets": ["@vue/app"], "plugins": [ [ "import", { "libraryName": "The map - the lib - test", / / the name of the component library "camel2DashComponentName" : false, / / close the hump automatic chain "camel2UnderlineComponentName" : False // Disable serpentine autochain}],]}Copy the code
In the main. Js to write
import { testA, testB } from 'map-lib-test';
Vue.use(testA);
Vue.use(testB);
Copy the code
In the SRC/views/demo. Vue references
<template>
<div>
<testA></testA>
<testB></testB>
</div>
</template>
<script>
export default {
data() {
return {
}
},
}
</script>
Copy the code
Browser display
2. Introduce styles
In the. Babelrc. js file in the root directory, do as follows
module.exports = { "presets": ["@vue/app"], "plugins": [ [ "import", { "libraryName": "The map - the lib - test", / / the name of the component library "camel2DashComponentName" : false, / / close the hump automatic chain "camel2UnderlineComponentName" : False // Turn off serpentine autochain "style": (name) =>{ const cssName = name.split('/')[2]; return `map-lib-test/lib/style/${cssName}.css` } } ], ] }Copy the code
style
When the value of babel-plugin-import is a function, babel-plugin-import will automatically import files whose file path is equal to the value returned by the function. The following figure shows the path of the CSS file after the component library is packaged. This is as configured in the code above. Among themstyle
Is a function, an example of the value of its parameter name ismap-lib-test/lib/testA
, you can print it out when you use it.
Browser display
Eight, pay attention
1. Whyimport{testA,testB}
Rather thanimport{testC,testD}
If it is' import {testC, testD} ', the following error occursCopy the code
import { testA, testB } from 'map-lib-test';
Copy the code
Quite a
import testA from "map-lib-test/lib/testA";
import testB from "map-lib-test/lib/testB";
Copy the code
import { testC, testD } from 'map-lib-test';
Copy the code
Quite a
import testC from "map-lib-test/lib/testC";
import testB from "map-lib-test/lib/testD";
Copy the code
Map-lib-test /lib does not contain testC or testD.
Import {testA, testB} : import{testA, testB} : import{testA, testB} : import{testA, testB} : import{testA, testB} : import{testA, testB} Each component is packaged independently and the generated folder name is the original folder name of each component code.
Import {testA, testB} because testA and testB are packaged into folders named testA and testB, respectively.
Js’ instead of ‘[name]/main.js’ or ‘[name]/out.js’
Import testA from “map-lib-test/lib/testA”; Import testA from “map-lib-test/lib/testA/index.js”; import testA from “map-lib-test/lib/testA/index.js”;
Import {testA, testB} as needed.
2. Component labels
Why
import test from './src/index.vue';
test.install = function(Vue) {
Vue.component(test.name, test);
};
Copy the code
Register a component in Vue with the name test.name, which is the value of the name option in the testA component.