The term component library is familiar to everyone in the front-end domain. Like element-UI vant… All of them are excellent component libraries in the community, so can we make a component library ourselves? Can!!!! Must be able to! Let’s play a game today.
The premise
Clone element-UI before you start and create your own project using Vuecli.
Example:
git clone https://github.com/ElemeFE/element.git
vue create vue-cmop-base
Copy the code
Renovation Project Catalog
1, remove scaffolding called assets Components under SRC, add SRC flat packages directory
2, Copy the button and card components of elder-UI (Elder-UI packages/). Add a theme folder in Packages to store styles.
3, try to keep the style hierarchy unchanged and copy only useful styles (element-UI pockages/theme-chalk/ SRC /); The styles currently in use include
-
Common/var. SCSS;
-
Fonts directory for all files;
-
All files in the mixins directory;
-
Theme-chalk /button. SCSS, theme-chalk/card. SCSS, theme-chalk/icon. SCSS, theme-chalk/index.scss
When you’re done, it looks something like this.
4. Add index.js to packages as a unified export for all components.
import Button from './button';
import Card from './card';
const components = [Button, Card];
const install = function (Vue) {
// Batch registration
components.forEach(component= > {
Vue.component(component.name, component);
});
};
/ / into the Vue
if (typeof window.Vue ! = ='undefined' && window.Vue) {
install(window.Vue);
}
export default {
// Export install vue.use (). The install method must be implemented.
install,
// Component export
Button,
Card
};
Copy the code
Test whether the component is available
src/main.js
In the new registered component related code;
/ /... .
import testComp from '.. /packages';
import '.. /packages/theme/index.scss';
Vue.use(testComp);
/ /... .
Copy the code
src/App.vue
Use component testing; Start the service at this time, there will be an error; Solutions in the next section;Depend on the installation
<template>
<! -- Importing components -->
<el-button size="mini" type="primary">test-btn</el-button>
</template>
<! -... . -->
Copy the code
Depend on the installation
Vuecli created a project, the default is not parse SCSS files, so need to download the corresponding dependencies;
TypeError: this. GetOptions is not a function; Syntax Error: TypeError: this. This problem is caused by the excessively high version of sas-Loader.
Install the latest version with a larger version of 7
npm intall sass-loader@7 -D
Copy the code
Syntax Error: Error: Cannot find module ‘node-sass’; NPM install node-sass -d NPM install node-sass -d Syntax Error: Error: Node Sass version 7.0.1 is incompatible with ^4.0.0. We need to install Version 4 of Node-sass as prompted.
Install the latest version with a larger version of 4
npm install node-sass@4 -D
Copy the code
$–group-option-flex: 00 math.div(1, 5) * 100%! default; ; The way this problem occurs is that node-sass does not support the math syntax, whereas element-UI uses Sass to avoid this problem. Of course, this was not the focus of the study; Solution:
-
Delete this line of code directly because the styles are not used in this example; Theme /common/var. SCSS search for $–group-option-flex;
-
Install sASS to fix this problem; NPM install sass -d; Of course I chose the latter
Come and show! showtime
At this point, we are halfway through implementing our component library; Go back to the whole project; Find that there will be some unreasonable places;
- why
src
To be used as a demo directory for the project; Actually useexamples
A more reasonable; Arrange ~ ~ ~
// vue.config.js
const path = require('path');
module.exports = {
// Change entry and rename SRC directory to examples
configureWebpack: {
entry: path.join(__dirname, 'examples/main.js')}};Copy the code
Project package
The component library is complete and must be packaged for others to use; Vuecli provides a library mode of packaging, of course we can also define the packaging method.
Library pattern packaging
The build goal is to add a command to scripts in package.json.
npm run build:lib: "vue-cli-service build --target lib --dest lib --name test-comp-base packages/index.js"
Vue-cli-service build
Usage: vue cli - service build [options] [entry | pattern] options: - mode specified environment mode (default: production), dest specifies the output directory (default: Dist) - modern geared to the needs of modern browsers with automatic back to build applications -- target app | lib | wc | wc - async (default: app) - library name or the name of the Web Components mode (default: "Name" field or entry filename in package.json) --no-clean Does not clean the target directory before building the project --report generates report-html to help analyze package contents --report-json generates report-.json To help analyze package contents -- Watch listens for file changesCopy the code
After executing the above command, the lib folder will appear in the project. This is the source code of our component library;
This is where the problem arises; We find that the packaged code does not contain the CSS we want so the style is missing? Library package. It actually generates CSS files; This CSS was not introduced in our project
I’m not sure if this is an official VueCli best practice. Or do I have to understand that there is a problem; As far as I know, this way of packaging is not able to achieve the function of importing components on demand; But now that the side quests are out, we have to do them.
-
Import the theme/index.scss file in Packages /index.js.
-
Once again, you can see that the packaged package already contains the CSS file. Then you can go to the NPM process
- Install components in the new Vue project and in
src/main.js
To register components andsrc/App.vue
Use components in;
// src/main.js
import testComp from 'test-comp-base';
import 'test-comp-base/lib/test-comp-base.css';
Vue.use(testComp);
/ /... .
// src/App.vue
<template>
<el-button size="mini" type="primary">
test-btn
</el-button>
</template>;
Copy the code
Vue.config.js build package
This packaging method basically requires multiple entries to be packaged one by one, and finally generates different files for us to use Babel to load on demand;
1, create a components.json file in the root directory: as the entry configuration for packaging.
// Each new configuration needs to be configured again.
{
"button": "./packages/button/index.js"."card": "./packages/card/index.js"."index": "./packages/index.js" / / the main file
}
Copy the code
2. Delete all the previous code in vue.config.js and add the following code; (It is not necessary to delete it. You can decide what configuration to use according to the environment later. I am for convenience.)
const path = require('path');
const components = require('./components.json');
// Get the absolute path for each component
const getComponentEntries = () = > {
const entryKeys = Object.keys(components);
entryKeys.forEach(key= > {
components[key] = path.join(__dirname, components[key]);
});
return components;
};
// { button: '/Users/xxx/packages/button/index.js' }
const componentEntries = getComponentEntries();
module.exports = {
outputDir: path.join(__dirname, 'lib'),
configureWebpack: {
entry: componentEntries,
output: {
// File name
filename: '[name].js'.// Build the dependency type
libraryTarget: 'umd'.// The exported item in the library
libraryExport: 'default'.// The dependency name for the reference
library: 'testComp'}},css: {
// Build the CSS independently
extract: {
filename: 'theme/[name].css' // Create a theme folder in the lib folder to generate the corresponding CSS file.}},/** * 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 to the lib folder. * Remove HTML, only package components, do not generate HTML pages. * Remove preload and prefetch, which are useless because no HTML pages are generated. * Delete HMR, delete hot updates. * Delete automatically added entry App. * /
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
3, and then directly execute our original NPM run build. Not surprisingly, there might be only one index.css file.
The reason for this is simple: we introduced the index.scss file earlier; Now that we have changed to multiple entries, we need to do one more import in each file.
Solution:
- Each component imports a file once;
<! -- packages/button/src/button.vue -->
<style lang="scss" src=".. /.. /theme/button.scss"></style>
Copy the code
- Package CSS files separately. reference
element-ui
usegulp
And then pack them separately
4, if you complete the above operations, packaging again appears a file structure similar to the following; Congratulations you can enter the next hosting to NPM, then we can study another project load on demand now;
babel-plugin-component
According to the need to introduce
In general, the mainstream component library is introduced on demand mainly according to babel-plugin-import babel-plugin-component. The following example will be based on the popular element UI Vant in the community. The former uses only babel-plugin-component and the latter babel-plugin-import.
Because our component library basically mimics the packaged structure of Element-UI; That’s why we use it. Babel – plugin – component.
1. Install the plug-in in the new project and download the babel-plugin-Component.
npm install test-comp-base
npm install babel-plugin-component
Copy the code
2. Refer to the use of element- UI. Note: THE style directory I packed was theme, not theme-chalk, which needs to be changed. LibraryName is the libraryName, for example, test-comp-base
3. Introduce components as needed in SRC /main.js for the new project.
/ /... .
import { Button as ElButton } from 'test-comp-base';
import { Card as ElCard } from 'test-comp-base';
Vue.use(ElButton);
Vue.use(ElCard);
Copy the code
4. Write the test code in SRC/app.vue of the new project
<el-card>
<div slot="header" class="clearfix">
<span>Name of the card</span>
<el-button type="primary" size="mini">test-btn</el-button>
</div>
<div v-for="o in 4" :key="o">{{' list contents' + o}}</div>
</el-card>
Copy the code
5, restart the project to see the result (try to restart the service after the modification of files not under SRC). You may experience an error after starting the service.
Why: It looks for a base.css file by default, why does element-UI work? (Because someone else has the file).
Solution: This default configuration item can be changed. Let’s just modify the configuration file.
plugins: [
[
'component',
{
libraryName: 'test-comp-base'.// don't let him find base
styleLibrary: {
name: 'theme'.base: false}}]]Copy the code
Why not?babel-plugin-import
If you go to their website, you’ll get the idea, but I’ll show you how to get in the water.
First, we changed the styleLibrary name in babel.config.js to theme-chalk to restart the service.
We can take a look at this by looking at the package structure in node_modules and error messages in the console. Look at the picture carefully
In fact, when we configure Babel, the syntax goes through the following transformation at runtime.
import { Button } from 'test-comp-base'
// babel-transform
var button = require('test-comp-base/lib/button')
// Of course the theme/ depends on how your Babel is configured.
require('test-comp-base/lib/theme/button.css')
Copy the code
Problem solved, let’s install a Vant in the new project to see how babel-plugin-import finds files.
npm install vant
npm install babel-plugin-import -D
Copy the code
At this point we let him make a deliberate mistake. For example, change the libraryDirectory in configuration to XXX. Run the project again. Look at the picture carefully
It can be seen that we should have searched for the style in the corresponding component in ES, but we could not find it after we modified ES. It is also important to note that he only finds the style directory, not a.css file.
This is more important. As we all know, if you only import into a directory structure, you will import the index.js so in that directory by default and its style reference will be placed in style/index.js.
As we inferred above, when you configure Babel, the syntax undergoes the following transformation at runtime.
import { Button } from 'vant'
// transform
// index.js is omitted
var _button = require('vant/lib/es/button');
require('vant/lib/es/button/style');
Copy the code
Conclusion: It’s not just that you can use whatever you want. It’s important to design the packaging structure in advance and fit it according to your needs.
Managed to NPM
We will consider writing another post about the release of NPM. I won’t go into the details here; Please follow the following steps:
1. Supplementary content of package.json: Some of the following contents will be missing in projects created by Cli; Make up your own.
-
Private: option changed to false; When private is true, publishing to NPM is not allowed.
-
Name: the option is the name of your current application; In other words, the library name.
-
Version: In principle, the version number should be increasing each time a version is released.
-
Main: project entry file. For example: / lib/test – comp – base. Umd. Min. Js
-
Author: indicates the author name.
-
License: Which open source protocol to use.
2, add.npmignore file; Filter files that do not need to be uploaded. File content rules refer to.gitignore.
3. Register an NPM account -> Log in to an NPM account -> Publish the NPM package reference.
4. Create a project using cli; Download and download our own component library to test.
vue create comp-demo
npm install test-comp-base
Copy the code
The source address
Source welcome star ~